pax_global_header00006660000000000000000000000064141115772200014512gustar00rootroot0000000000000052 comment=1ead1bde80d30cbdde659786e134cba644d0def4 nestopia-1.51.1/000077500000000000000000000000001411157722000134215ustar00rootroot00000000000000nestopia-1.51.1/.gitignore000066400000000000000000000010511411157722000154060ustar00rootroot00000000000000*.so *.o *.dylib *.dll *.nes *.fds *.ips *.ups /nestopia *.js *.bc .npmignore source/core/database/ # Autotools cruft Makefile Makefile.in aclocal.m4 autom4te.cache/ config.guess config.log config.status config.sub configure depcomp install-sh missing source/core/.deps/ source/core/.dirstamp source/core/api/.deps/ source/core/api/.dirstamp source/core/board/.deps/ source/core/board/.dirstamp source/core/input/.deps/ source/core/input/.dirstamp source/core/vssystem/.deps/ source/core/vssystem/.dirstamp source/fltkui/.deps/ source/fltkui/.dirstamp nestopia-1.51.1/COPYING000066400000000000000000000354221411157722000144620ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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 nestopia-1.51.1/COPYRIGHT000066400000000000000000000014531411157722000147170ustar00rootroot00000000000000Included Software blargg's NTSC filter Copyright (C) 2006-2007 Shay Green For details, read source/nes_ntsc/* inih -- simple .INI file parser Copyright (c) 2009, Brush Technology All rights reserved. For details, read source/unix/ini.h LodePNG version 20141130 Copyright (c) 2005-2014 Lode Vandevenne For details, read source/unix/png.h zlib compression library Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler For details, read source/zlib/* nespad.svg based on work by Fant0men http://commons.wikimedia.org/wiki/File:Nes_controller.svg nestopia.svg based on work by Trollekop, with permission http://trollekop.deviantart.com/art/Zombie-NES-controller-Color-160691868 Palettes from FirebrandX, with permission extras/Unsaturated-V5.pal extras/YUV-V3.pal http://www.firebrandx.com/nespalette.html nestopia-1.51.1/ChangeLog000066400000000000000000001763031411157722000152050ustar00rootroot00000000000000---------------------------------------------------------------- 1.51.1 ---------------------------------------------------------------- Shell: Changes: - Unofficial support for macOS via homebrew Fixes: - FLTK: Better audio buffer management - FLTK: Fix bug related to system-wide NstDatabase.xml loading Core: Additions: - Mappers 162, 302, 554 (UNL-FS304, UNL-KS7057, UNL-KS7010) - Add database entries for Micro Mages, Nong Chang Xiao Jing Ling Fixes: - Accuracy fix for MMC3 and MMC6 IRQ timing - Accuracy fix for DMC DMA read conflicts - Accuracy fix for CPU Exec Space PPUIO ---------------------------------------------------------------- 1.51.0 ---------------------------------------------------------------- Shell: Changes: - Merged the win32 sources back into the main codebase - Change versioning scheme - Avoid possible trademark infringement in controller image - Switch from GTK to FLTK for Linux/BSD port - Use Legacy OpenGL (Compatibility Profile) Core: Additions: - Mappers 306, 307, 312 - Convert many UNIF boards to NES 2.0 mappers Changes: - Use Nestopia core from jgemu Fixes: - Timing and other accuracy fixes for CPU/APU - Revert changes that caused regressions - Fix Camerica mapper for Dooly Bravo Land - Improve MMC5 emulation for Sim City - Fix 8K PRG NROM games such as Galaxian - Full implementation of mapper 156 - Fix SOROM saving/loading - Fix FDS IRQ behaviour - Improve RAMBO-1 timing - Fix support for Korean Igo (Korea) (Unl) - Implement mirroring for UNL-KOF97 - Rewrite NAMCOT-175 and NAMCOT-340 - Assign UNL-CC-21 to mapper 27 and fix CHR bank swapping ---------------------------------------------------------------- 1.50 ---------------------------------------------------------------- Shell: Additions: - Added ability to output data from homebrew module (Phil Smith) libretro: Additions: - Button shift option - Input bitmask support (TwinAphex) - Enhanced core options (TwinAphex) - Build in NstDatabase.xml Core: Additions: - Homebrew module (Phil Smith) - Support for mapper 31 (rainwarrior) - Support for mappers 28 and 30 (retro-wertz) - Support for UNL-KS7031 (retro-wertz) - Support for MMC3 Big CHR-RAM Board Fixes: - Deterministic Save States (creambits) ---------------------------------------------------------------- 1.49 ---------------------------------------------------------------- Shell: Additions: - Added more palettes to extras - Game-specific custom palettes - Scale factors up to 8x - Added option to enable overclocking - Added rewind controls to gamepad - Famicom Mic support - Optional JACK Audio support (McKayJT) - Added .wav sample loading Changes: - Separated GTK+ and SDL input settings - Removed deprecated functions from UI - Use GTK+ OpenGL widget for GUI (Wayland support) - Reworked Alternate Speed/Fast-Forward - Allow mapping more than 9 joysticks (Lou-Cipher) - Restructured build system, separated SDL and GTK builds - Cursor options split int normal and special cursor options Fixes: - Fixed automatic ROM patching, improved patching function (hugoarpin) libretro: Additions: - Add support for multiline cheats and raw cheats (iLag) - Add adapter autoselect using NstDatabase.xml (hunterk) - Famicom Mic support - Cheevos ram access support (meepingsnesroms) - Add .wav sample loading Fixes: - Fixed heap corruption bug with crosshair (Arto Vainiolehto) - Fixed black screen when non-existent custom palette is selected - Fixed crosshair and overscan with blargg filter Core: Additions: - Added support for overclocking (meepingsnesroms) Fixes: - Fixed NSF and FDS in Dendy mode (Eugene.S) - Fixed coding mistake in PPU (zeromus) - Modified submappers for VRC2/VRC4 games (GeneralFailer) - Fixed compilation error in SetRamPowerState (Arto Vainiolehto) - Fix for McAcc games (joepogo) ---------------------------------------------------------------- 1.48 ---------------------------------------------------------------- Shell: Additions: - Remember previous ROM directory (fabiengb) - Added an option to disable the cursor - Added ability to load custom palettes - Added many palettes to extras (FirebrandX, BMF, others) - Added monochrome blargg NTSC filter - Added new build systems: CMake and Autotools (David Seifert) Changes: - TV Aspect Ratio changes depending on region Fixes: - Made the region selector more coherent - Fixed a bug that switches video modes rapidly - Revamped region selector code - Fixed fullscreen switching too fast - Fixed region selector when the XML database is not present libretro: Additions: - Added ability to load custom palettes - Added many palettes (Monroe88) - Added monochrome blargg NTSC filter (dalter) - Added Turbo A/B buttons Core: Additions: - RAM Power-on State setting - Support for mapper 23.10 Fixes: - VRC2 Mirroring bug (koitsu, lidnariq) - Dendy timing and audio fixes (FHorse, Eugene.S) - Removed unused code in APU - Properly initialize RAM - fixes F-1 Race (koitsu) - Silenced many build warnings (orbea) ---------------------------------------------------------------- 1.47 ---------------------------------------------------------------- Shell: Additions: - On-screen text when saving/loading states - Basic NSF player - PNG Screenshots - Quick State Save/Load menu items - Open Recent menu item - Ability to pause games when configuration dialog is open - Customizable NTSC filter options - Support for Mac OS X Changes: - Updated to modern OpenGL (version 3.2 minimum) Fixes: - Empty audio buffer when volume is set to 0 - Input config now accepts joystick buttons over 10 libretro: Additions: - Game Genie Sound Distortion option - Region selection core option Changes: - Default to "consumer" palette - Vertical and Horizontal overscan options separated Fixes: - Fixed FDS save path Core: Additions: - Added support for MC-ACC (perilsensitive) - Added NstDatabase.xml entries (clobber) - Added support for NES 2.0 submappers - Added support for mapper 4.1 - Added support for mapper 4.3 - Added support for mapper 23.15 - Added support for mapper 25.15 - Added support for mapper 32.1 - Added support for mapper 68.1 - Added support for mapper 71.1 - Added support for mapper 78.1 - Added support for mapper 78.3 Fixes: - Reverted fix for Mapper 79 - Fixed Burai Fighter status area (perilsensitive) - FME-7 IRQ Fix (lidnariq) - Disabled buggy audio sync ---------------------------------------------------------------- 1.46.1/1.46.2 ---------------------------------------------------------------- Unix Shell: Fixes: - Input config bugfixes - Only go fullscreen when the game is actually playing ---------------------------------------------------------------- 1.46 ---------------------------------------------------------------- Unix Shell: Additions: - Mask Overscan option - Disable GUI option - Command line interface - Scale Factor and Filters can be changed while playing - Zapper support - Palette and Picture options - Ability to turn Vsync on/off - Alternate emulation speed - libao audio output (handles ALSA, OSS, Pulse, etc) - More volume controls - Turbo Buttons A and B Changes: - Ported to SDL 2.0 - Completely rewrote config file handling - Completely rewrote input config and input handling - Completely rewrote cheats - Removed ALSA and OSS audio output Windows Shell: Fixes: - xBR dialog now updates video output when options change libretro: Additions: - Ability to load NstDatabase.xml (needed for some games) - Overscan masking (themaister) - Palette options - Zapper support Changes: - Region detection based on NstDatabase.xml Core: Additions: - Game Genie sound distortion option - Mapper 210 (NAMCOT-175, NAMCOT-340) Fixes: - Hard Drivin' now playable (dragon2snow) - Kaettekita Mario Bros. fix (dragon2snow) - Fix for rewinder sound issue (steelywing) - Typos and syntax error fixes (lioncash) - Fix for Mickey's Safari in Letterland (joepogo, james) ---------------------------------------------------------------- 1.45 ---------------------------------------------------------------- Unix Shell: Additions: - Added the ability to switch FDS disks for multi-disk games - xBR filter options - Support for more archive formats through libarchive - Differentiated Soft/Hard Reset Changes: - Removed internal zip and 7zip decoders in favour of libarchive - Replaced gtk_key_snooper with key_press_event and key_release_event Fixes: - 7zip CRC check segfault Windows Shell: Additions: - xBR filter options Changes: - Redundant TV Aspect checkbox removed from NTSC filter dialog - Modified default sound settings to avoid desync libretro: Additions: - blargg's NTSC filter core option - L/R now insert coins on Vs. System games Core: Additions: - xBR filter added - Hyllian, notBald Fixes: - Triangle volume bug in Dendy mode - emu-russia - NTSC filter background colour fix - blargg ---------------------------------------------------------------- 1.44 ---------------------------------------------------------------- Unix Shell: Additions: - Support for FreeBSD, OpenBSD, and NetBSD - TV Aspect Ratio option added - 2xSaI filter option exposed Changes: - Renamed Linux port to Unix port - Removed status bar - General UI improvements - Stop warning about unused results - SDL is the default sound API on Linux, the only one on the BSDs - Drag and Drop re-enabled Fixes: - Fixed SDL sound crashes - Fixed Movie Record crash - Loading a state when none exists no longer resets - Fixed bug that causes "Enter" to toggle fullscreen - GUI responsiveness glitches when failing to output sound fixed Windows Shell: Fixes: - TV Aspect is more accurate - W.M. Martinez libretro: Additions: - libretro port done by Themaister and twinaphex Core: Fixes: - Merged a fix for Mapper 79 that affects "Puzzle (Unl)" - shalma - Fixed a PPU bug that causes problems in "The Young Indiana Jones Chronicles" - Art Vandelae, plasturion, and James - Mapper 143 fix that affects "Dancing Blocks (Unl)" - shalma ---------------------------------------------------------------- 1.43 ---------------------------------------------------------------- Linux Shell: Additions: - Fullscreen defaults to native screen resolution Changes: - Completely rewrote the GUI (except for Cheat Manager and Archive Selector) - More traditional look and feel - Improved input configuration - Keyboard shortcuts - More functionality exposed directly through GUI - Better looking icons Windows Shell: Changes: - Updated icons, about dialog, copyright - Merged the remaining features from Unofficial 1.41.1 ---------------------------------------------------------------- 1.42 ---------------------------------------------------------------- Linux Shell: Additions: - Added native support for D-pads (Hat Switches) - Added an About dialog box - Added icons and a desktop menu entry Fixes: - Fixed the 100% CPU usage bug - Fixed the "Error writing setting!" bug (patch from Arch Linux) ---------------------------------------------------------------- 1.41 ---------------------------------------------------------------- Linux shell: Fixes: - Fixed a braindead SRAM path issue Windows Shell: Changes: - Merged win32 fixes from Unofficial Build 1.41.1 ---------------------------------------------------------------- 1.40-undead ---------------------------------------------------------------- Linux Shell: Additions: - Added install/uninstall targets to Makefile Changes: - Ported to GTK+3 - Changed default sound API to ALSA (SDL audio has problems on some computers) - Changed default renderer to OpenGL with a scale factor of 2 - Changed binary name to "nestopia" - SRAM now saves to ~/.nestopia/save (for people who have roms on a read-only network share) - Automatically install a new nstcontrols file to ~/.nestopia if it doesn't exist - Install NstDatabase.xml to a proper location on the filesystem instead of forcing the user to manually copy it to ~/.nestopia Fixes: - Fixed numerous compiler warnings. ---------------------------------------------------------------- Unofficial 1.41.1 - by Geestarraw (geestarraw@gmail.com) (May 17, 2011) ---------------------------------------------------------------- Shell: Changes: - Added fullscreen support for non-primary monitor displays. - Modified Video Options dialog component layout and added device index to identify mutiple monitors. - Refactoring. - Code documentation. Fixes: - Fixed so menu is still displayed after fullscreen monitor to monitor switch. Project: Changes: - Converted solution and projects to Visual Studio 2010. - Improved version enumeration previously locked to x.xx (exactly 3 digits) to be anything from y.y, y.y.y, and y.y.y.y (where y can be up to 4 digits). - Changed build output target to nestopia.exe. Fixes: - Fixed bug in version enumeration always excluding highest version number. - Moved unofficial 1.41 release notes to official changelog file. ---------------------------------------------------------------- Unofficial 1.41 - by Keith Kelly (c0d3h4x0r@hotmail.com) (March 29, 2010) ---------------------------------------------------------------- This is an unofficial maintenance release I created to fix an annoying joystick lag issue. This lag was particularly bad when VSync was enabled. The original Nestopia author (Martin Freij) appears to have abandoned the official Nestopia project on SourceForge and has not responded to any of my e-mails, so I am left with no choice but to provide this unofficial release as a public service to the emulation community. Changes: 1. Removed manual option to set priority of Nestopia's main emulation loop thread. Instead, Nestopia now boosts its own process base priority AND its own main emulation thread priority whenever it is the active foreground window (and/or running in full-screen mode). This brings Nestopia much closer to real-time performance and responsiveness. 2. Removed some screwy input polling logic, and added some calls to input.Poll(), to ensure that the input devices are always polled immediately before the input state is utilized. This was the key change that got rid of most of the lag. 3. Removed some screwy input timing logic that was causing input polling to work only on certain clock intervals, rather than allowing it to work every time it was called. (As far as I can tell on my own hardware configuration, these three changes taken together have completely eliminated the lag problems that have been present in Nestopia for several releases. Your mileage may vary.) 4. Updated the Visual Studio solution/project to build successfully under Visual C++ 2008 Express Edition. 5. Added this releasenotes.txt file and bumped the version number to 1.41. ---------------------------------------------------------------- 1.40 Release A-H - by R. Belmont ---------------------------------------------------------------- Linux Shell: Additions: - XML ROM support - More flexible video configuration including OpenGL hardware scaling - Input mapping in the GUI - Cheat Manager with flexible support and import/export capability (win32 compatible format) - Core logging is now enabled to the terminal you start NEStopia from for easier diagnosis of problems - Automatic soft-patching added - Coin inputs added for Vs. system - Audio filters added for fun - [Release C] Proper default nstcontrols file included - [Release E] Added SDL audio driver, should be most compatible - [Release G] Cheat Manager now shows descriptions on imported XML files. Also fixed a CM crash. Changes: - Complains more if it's unable to write to the settings file - Archive browser comes up automatically if you select a zip or 7zip archive with multiple NES files in it - Option to select favored console - [Release E] Refactored to get UI code out of main.cpp - [Release G] Settings window auto-hides during emulation [enik] Fixes: - Fixed bug where keyboard input could stick - [Release B] Cleaned up some crashy issues with the control configurator - [Release D] Fixed ability to remap "meta" keys (keys that control NEStopia itself), fixed documentation on defaults. - [Release E] Fixed quicksave/quickload - [Release F] Fixed keyboard to ignore numlock/capslock - [Release G] Taskbar description is set properly for the game window [enik] ---------------------------------------------------------------- 1.40 ---------------------------------------------------------------- Shell: Additions: - New cheat dialog features and improvements. - Automatic cheat load/save support in Paths dialog. - Option to mute sound when running in alt. speed mode. Changes: - Icon improvements by Pongbashi. - Default fullscreen resolution depending on monitor's aspect ratio. - Refactoring. Fixes: - Various minor things. Core: Additions: - Preliminary Dendy console support. Fixes Magistr (Subor) and some other 'clone exclusives'. Info from Flamer and HardWareMan. - DMC DMA read conflicts. Info from blargg and bunnyboy. - Mapper 177, 179, 219 and 221. Info from CaH4e3. - Database entries. Changes: - Better and more flexible PPU address line implementation at the expense of some speed. - Database entries. - Refactoring. Fixes: - Wrong palette sometimes when switching to/from VS images. - Wrong image information sometimes, e.g. battery when there isn't any. - Save state NTSC/PAL mode saving. - Minor save state inaccuacy fix with tape recording. ---------------------------------------------------------------- 1.39 ---------------------------------------------------------------- Shell: Additions: - "Don't show again" checkbox in DIP switches popup window. - Soft-patching status in image info dialog. Changes: - More descriptive error messages. - Refactoring. Fixes: - Netplay file opening error leading to crash. - Recent files locking bug on exit. - Last visited image file directory bug on exit. - Esc not working sometimes when disabling dialog controls (Windows quirk). - Crash on cancel when exporting to AVI. - Correct screen height with NTSC filter when exporting to AVI. - Typos in GUI. Core: Additions: - Core API documentation in HTML through cppdoc. - UPS patching format support. - Database lookup on soft-patching. - Database entries. Info from Bootgod. - More recognized boards. Info from Bootgod. Changes: - FDS saves through UPS instead of IPS. - Database entries. Info from Bootgod. - Refactoring. Fixes: - FDS file saving bug. - NTSC burst phase incrementing bug. - Potential memory leak in database loader. - UTF16 to wchar_t portability fix in XML parser. - Const-correctness bug caught by GCC 4.0. ---------------------------------------------------------------- 1.38 ---------------------------------------------------------------- Shell: Additions: - Option to select favored console in preferences dialog. Changes: - Some video filtering work offloaded to the GPU. - Most settings now stored in XML format. - Misc launcher dialog display properties. - Refactoring. Fixes: - Netplay input communication. - Netplay movie recording bug (menu item accidently grayed). Core: Additions: - ROM sets and external database support using new XML format co-developed with Bootgod. - Mapper 36, 103, 104, 106, 120, 126, 175, 176, 223 and 224. Info from mad dumper, CaH4e3 and Temryu. - UNIF boards GS-2013 and BS-5. info from CaH4e3. - Emulation of bus conflicts for certain boards. - Database entries. Changes: - PPU power/reset timing and register states. Info from blargg. - Misc IRQ/NMI/BRK/DMA special-case behavior. Info from blargg. - NTSC/PAL switch during emulation will now force a hard-reset. - Misc mapper emulation improvements. Info from Bootgod. - NES-EVENT board timer more accurate. - Board names. Info from Bootgod. - Refactoring and mapper codebase overhaul. - Speed optimizations (accuracy NOT compromised!). - Mappers 21, 23, 25 and 185 no longer supported using plain iNES files because of format restrictions. Fixes: - MMC3 soft-reset IRQ bug. - Database entries. ---------------------------------------------------------------- 1.37 ---------------------------------------------------------------- Shell: Additions: - Menu option for DIP switch window popup on file load. - Movie recording now supported during netplay. Changes: - Smaller netplay data packets. - Minor GUI adjustments. - Refactoring. Fixes: - Scaling artifacts with NTSC filter on certain resolutions. - Auto NTSC/PAL window resize bug. - Sound stuttering on window clicks. - Netplay bugs/quirks. - Joystick auto-calibration bug. Core: Additions: - Mapper 63. - Mapper 121 and 134. Info from CaH4e3. - Mapper 136 for Sachen board SA-002 3011. Info from Enri. - Mapper 178 for "San Guo Zhong Lie Zhuan (Ch)". Info from temryu. - UNIF boards: AX5705, T-230, CTC-65 and 190IN1. Info from CaH4e3. - Adaptive sound streaming synchronization. - More optimization hints for GCC. - Database entries. Changes: - Movie file format rewritten. Older files will no longer work (sorry, had to be done sooner or later). New format is much more flexible and extendable. - Lower memory consumption. - APU speed optimizations. - Most DIP switches are now configurable through dialogs instead being soft-reset-triggered. - Board names. Info from Pongbashi and Bootgod. - Refactoring. Fixes: - Mapper 41 and 43. - Mapper 112. Fixes "Fighting Hero III". Info from temryu. - Minor save state inaccuracy. - FDS sound emulation inaccuracy. Fixes "Nazo no Magazine Disk - Nazoraa Land Dai 3 Gou". - Small rewinder bug. - Database entries. ---------------------------------------------------------------- 1.36 ---------------------------------------------------------------- Shell: Additions: - Joystick calibrate button in the input dialog. Changes: - Now possible to make save states (slots only) during netplay. - Some error messages more descriptive. - Log file now enabled by default. - Lazy loading of some resources, notably the launcher file database. - Various aesthetic GUI fixes and improvements. - Refactoring. Fixes: - Lightgun trigger no longer registered if screen is occluded by a window. - Various things, subtle and not-so-subtle. Core: Additions: - Power Glove peripheral support. - Mapper 38, 108 and 173. Info from CaH4e3. - UNIF boards: TF1201, KS7038 and GS-2004. Info from CaH4e3. - Mapper 150 reset-triggered DIP switch toggling. - Database entries. Changes: - Speed optimizations (NO accuracy trade-off). - blargg's nes_ntsc updated to version 0.2.2. - HSB/RGB calculation method. - 8bit video mode rendering removed. - 2xSaI filters removed. Use hqx or ScaleX instead. - Even stricter ANSI/ISO compliance. - More compiler options and detections through the preprocessor. Refer to "NstApiConfig.hpp" as starting point for porting work. - Board names. Info from Pongbashi. - Refactoring. Fixes: - Mapper 234. - Mapper 242. Fixes "Dragon Quest VIII (Ch)". - Database entries. - Various things, subtle and not-so-subtle. ---------------------------------------------------------------- 1.35 ---------------------------------------------------------------- Shell: Additions: - Memory pool select for sound buffers. - Famicom and NES four player adapter select in menu. - More cartridge info in image file dialog. Changes: - Better sound synchronization. - Launcher fixes and improvements. - Workaround for bugs in E-MU sound drivers. - Workaround for bug in ::D3DXSaveSurfaceToFile() using D3DXIFF_BMP. - MBC strings now passed in netplay chat. - Aspect ratio option now preserved on ALT+S in fullscreen mode. - VSync now disabled by default. Fixes: - Settings for compressed palette and FDS BIOS files now properly saved on exit. - AVISTREAMINFO::fccHandler. - Relative paths in Paths dialog. Core: Additions: - Preliminary support for NES 2.0 file headers. - R.O.B / Famicom Robot peripheral support. - Mapper 14, 196, 214 and 169 (partially). Info from CaH4e3. - Mapper 171 (KAISER KS7058) for "Tui Do Woo Ma Jeung". - Mapper 172 (IDEA-TEK CNROM +SECURITY) for "1991 Du Ma Racing" (unaltered version). - Database entries. Changes: - PAL APU noise channel rates and frame sequencer steps. Info from Blargg. - Emphasis color calculations on user palettes. - Better board type detection for several mappers, particulary 1 and 4. - Board names. Info from Pongbashi. - Removed worthless mapper 100. - Refactoring. Fixes: - Mapper 12 to use MMC3A revision. Fixes "Dragon Ball Z 5". - Mapper 15, 147 and 222. Info from CaH4e3. - Mapper 99, PRG-ROM bank switching. Fixes "VS Gumshoe". - Mapper 115 and moved "Bao Qing Tian" to it. - Mapper 156. Fixes "Ko Ko Eo Deu Ben Ce" and "Metal Force". - Mapper 163. Info from CaH4e3 and tpu. - Mapper 230. Fixes "Contra" in "22-in-1". - Mapper 232. Fixes the Quattro games. - Right mouse button for light gun firing off-screen. - Minor sound volume control bug. - AbsX 3-byte NOP instruction timing. - Database entries. ---------------------------------------------------------------- 1.34 ---------------------------------------------------------------- Shell: Changes: - Better method for CPU/GPU frame synchronization. Disabled when triple buffering is enabled. - Suitable default settings for auto frame skip, triple buffering and clock source based on system info. - Blargg's nes_ntsc back again with new version 0.2.1. - AVISTREAMINFO::szName no longer used since its presence seem to cause loading failures in some AVI file editors. Fixes: - Frame timing bug. Could cause severe slowdown on some systems. - Wrong speed at higher refresh rates. - Non-blocking input key commands. Core: Fixes: - "Quattro Sports: BMX Simulator" now responds to input again. ---------------------------------------------------------------- 1.33b ---------------------------------------------------------------- Shell: Fixes: - Removed use of DirectInput8 event notifications. Caused too much problems and some joysticks refused to work with it. ---------------------------------------------------------------- 1.33 ---------------------------------------------------------------- Shell: Additions: - Adjustable screen curvature. - Auto scale option for Hqx and ScaleX video filters. - Auto color settings option for NTSC filter. - 'Condition' column in launcher. - Hex and current entry view in palette editor. - Fast way to supply a missing FDS BIOS file on disk image loading. - 'Default' button in FDS dialog. - More FDS info in log file and image info dialog. Changes: - Reduced input latency and improved overall frame flow by rearranging wait loops and making use of Direct3D9 query events (or dummy texture locks if unsupported) to force CPU/GPU sync on each frame. - Improved emu input granularity with use of DirectInput8 event notification. Fixes "BMX Simulator" in "Quattro Sports". - Reclaim of ::Sleep() time on timed intervals in frame timer. - Warning message now issued whenever the database corrects a nes file with bad header. - Filelist controls now accept double clicks. - Pressing ESC now closes most dialogs. - No menu check marks when disk is ejected. - WMM timer now used by default because of QPF/QPC unsafety on dual-core CPUs. - Refactoring. Fixes: - Wrong HSB values in palette editor. - Speed throttle bug when vsync was enabled. - Incorrect window size on startup after a previous exit with a PAL sized window. - Auto cursor hiding (didn't always work). Core: Additions: - Hq4x video filter. - Support for extended 512*3 byte palettes (for emphasis colors). - FDS screen text for disk reads/writes. - Database entries. Changes: - Better RGB to YUV conversion for VS System. - Better VS System detection strategy. - VS DIP switch descriptions for "Battle City", "RBI Baseball", "Super Sky Kid" and "Super Xevious". - Rewinder optimizations. Faster but more memory consuming. - More accurate FDS disk drive emulation. Fixes "Aspic-Majaou no Noroi", "Hao Kun no Fushigina Tabi" and possibly others. - Switched to Blargg's snes_ntsc in order to make it work with custom palettes. - Refactoring and optimizations. Fixes: - Mapper 117. Fixes "La Bi Xiao Xin". Info from tpu. - Change side bug for single sided FDS disks. - Game Genie decoder bug when using certain compare values. - Database entries. ---------------------------------------------------------------- 1.32 ---------------------------------------------------------------- Shell: Additions: - Language plugin system using compiled resource DLLs. LDK included in the source. - Date and time for last state slot write now displayed in the menu. - Most option dialogs now carry a cancel button. - Launcher window size preserved and optionally saved on exit. - More detailed info in some error messages. Changes: - Various aesthetic fixes and improvements to the GUI. - Alternative screen font for a few selected countries. - Many hardcoded strings moved to the resource string table. - No default directory creation if already user specified. - Swapped load/save state keys (N/SHIFT+N) for a more standard setup. - Different meaning to the SHIFT+0/0 key for save/load state slots. SHIFT+0 to overwrite oldest slot, 0 to load from newest slot. - Auto monitor frequency option in video dialog now enabled by default. - Updated to newer version of unrar.dll. - unrar.dll and kaillera.dll now only loaded on demand. - Lots of refactoring. - Cleaned up tabs and spaces in source files via internal utility. - Cleaned up HTML in readme file. Fixes: - More menu/dialog items grayed out when not applicable. - Menu disappearance sometimes after exiting menus/dialogs in fullscreen mode. - Filter settings now properly reset on 'Default' button clicks in the video options dialog. - Display of the 'Name' and 'Maker' launcher column entries now in proper ANSI code page. - Directory string parsing bug if failed to create a default directory. - Auto window sizing quirk. - Incorrect image file properties in some of the database corrected entries in the launcher dialog. Refresh your file list to force the fix to take effect. Core: Additions: - Pachinko (via mouse wheel) and Hori Track (via mouse) controllers. Info from Enri. - Nantettatte Baseball Double Cassette System for mapper 68. Info from CaH4e3 and Enri. - Mapper 170 for "Fujiya Thinking Games". Info from Enri. - Mapper 197 for "Super Fighter III". Info from CaH4e3. - Backup-switch for the Family BASIC and Playbox BASIC cartridges (DIP Switches dialog). Info from Enri. - RP2C04 VS Unisystem palettes. Info from Quietust and Kevtris. - New entries for auto-detection of controllers. - Database entries. Changes: - Moved "Subor (Russian)" to mapper 166. - Moved "Seicross (J)" back to mapper 185. - Controller names. Info from Pongbashi. Fixes: - DIP switch setting for "VS.Bomb Jack". - Lightgun in "VS.Duck Hunt" and "VS.Hogan's Alley" now works again. - Database entries. ---------------------------------------------------------------- 1.31 ---------------------------------------------------------------- Shell: Fixes: - NSF text info bug from v1.30. ---------------------------------------------------------------- 1.30 ---------------------------------------------------------------- Shell: Changes: - Updated 7zxa.dll. Fixes: - NSF text info is now displayed in the proper ANSI code page. Core: Additions: - Bandai Karaoke Studio michrophone support through keyboard. - Sound sample support for: "Family Trainer - Aerobics Studio" -> "ftaerobi" "Moe Pro! '90 - Kandou Hen" -> "moepro90" "Moe Pro! - Saikyou Hen" -> "mpsaikyo" "Moero!! Pro Tennis" -> "mptennis" "Moero!! Pro Yakyuu" -> "moepro" "Moero!! Pro Yakyuu '88 - Ketteiban" -> "moepro88" "Shin Moero!! Pro Yakyuu" -> "smoepro" "Terao no Dosukoi Oozumou" -> "terao" Info from Hap and Pongbashi. - Mapper 132. Info from CaH4e3. - Unif Boards "UNL-603-5052", "A65AS" and "EDU2000". Info from CaH4e3. - Mouse support for "Educational Computer 2000". Info from CaH4e3. Changes: - Board/Chip names. Info from Pongbashi. - Moved the following games to new mappers: "Crystalis (ch)" -> mapper 195 "Captain Tsubasa Vol 2 - Super Striker (ch)" -> mapper 195 "Dragon Ball Z 2 - Gekishin Freeza! (ch)" -> mapper 199 "Dragon Ball Z Gaiden - Saiya Jin Zetsumetsu Keikaku (ch)" -> mapper 199 "San Guo Zhi 2 (ch)" -> mapper 199 Fixes: - More accurate PAL APU DMC rates. Info from Blargg. - Mapper 4. Now defaulting to MMC3B IRQ hardware. Fixes "Star Trek - 25th Anniversary". - Mapper 19. Fixes "Final Lap". - Mapper 60, menu select for "TN 95-in-1" and "Super 35-in-1" via soft reset. Info from CaH4e3. - Mapper 163. Fixes "Kou Dai Bao Shi - Hong (ch)" and "Kou Dai Bao Shi - Lan (ch)". - Mapper 198, CHR banking. Fixes "Super Fighter III". Info from CaH4e3. - Mapper 209, CHR 4K PPU latch mode. Fixes "Power Rangers" and others. Info from CaH4e3. - Database entries. ---------------------------------------------------------------- 1.29 ---------------------------------------------------------------- Shell: Additions: - TV Aspect option. - UI contrast slider. Changes: - UI color slider scales. - Increase of auto-fire speed and granularity. - Smoother fullscreen entering/exiting. - Real-time updates with the video filter UI controls. - Better compability across different compilers. Fixes: - Horizontal scroll-bar in the 'Open' dialog for compressed files. - User input bug in the 'UNIF-to-mapper' dialog. - NTSC/PAL window size issue on startup. - Various GUI fixes. Core: Additions: - UNIF boards "KOF97", "64-IN-1 No Repeat", "SHERO", "T-262" and "FK23C". Info from CaH4e3. - Mapper 43 and 236. Info from FE. - Database entries. Changes: - Update to version 0.2.0 of Blargg's NTSC video filter. - Board/Chip names. Info from Pongbashi. - Rewinder no longer forces alignment to a specific frame. - Sprite overflow timing and flag quirks. Info from Blargg. - Automatic use of ::_controlfp(..) for FPU double-precision mode or better. - Mapper 95 now derived from NAMCOT 118 instead of MMC3. - Mappers 189, 198 and 208 now derived from MMC3. - Mapper 211 now derived from JY-xxx (90). - Various mapper code cleanups. - Moved the following games to new mappers: "SMB+Tetris+NWC" -> mapper 37 "Jia A Fung Yun (chinese)" -> mapper 74 "Aladdin (pirate)" -> mapper 90 "Seicross (redump)" -> mapper 181 "Ying Lie Qun Xia Zhuan (chinese)" -> mapper 192 "Young Chivalry (chinese)" -> mapper 192 "Dai-2-Ji - Super Robot Taisen (chinese)" -> mapper 194 Fixes: - APU sample rate counter overflow bug. - Rewinder stop bug when running at non-default speed. - FDS IRQ counter. Fixes "Druid - Kyoufu no Tobira". - Mapper 45, no bankswitching with CHR-RAM. Fixes "Famicom Yarou Vol.1 7-in-1". - Mapper 57, menu switch on soft-reset. Info from CaH4e3. - Mapper 58, 115, 222, 150 and 188. Info from CaH4e3. - Mapper 74. Fixes "Sangokushi (chinese)" and others. - Mapper 83, language mode on soft-reset for "World Heroes 2" and "Fatal Fury 2". - Mapper 90/209/211, M2 based IRQ counter added. Fixes "Goal!!" in "45-in-1". - Mapper 117, IRQ counter. Fixes "San Guo Zhi 4 - Chi Bi Feng Yun". - Mapper 255, menu screen bugs as on the real cart. - Soft reset for mapper 230 and 255. - Small VRC7 sound chip load-state bug. - Database entries. ---------------------------------------------------------------- 1.28 ---------------------------------------------------------------- Windows: Additions: - Sound volume level sliders. - More NTSC video filter options. - Scanline darkening level sliders. Changes: - Pressing the ALT-key when the menu is hidden should no longer cause "hickups" during play. - Recent files/directories menu lock state is now saved on exit. Fixes: - Window placement bug. Emulator: Additions: - Non-linear APU sound output. - Mapper 116 for "AV-Girl Fighting". - Mapper 163 and 167. Info from tpu. - Database entries. Changes: - Update to version 0.1.7 of Blargg's NTSC composite video filter. - Fine-tuned the volume levels of the external sound chips. - More accurate SUNSOFT5B sound chip emulation. - Moved "Shanghai" to mapper 93. - Patch for "Dragon Ball Z II - Gekishin Freeza!! (redump)" to use the proper EEPROM type. - 'No Sprite Limit' option should now be more responsive to games that make heavy use of OAM cycling. Fixes: - Mapper 45, 53, 74, 90, 93, 164 and 165. - Dip-switch and input fixes for some VS.System games. - Database entries. ---------------------------------------------------------------- 1.27 ---------------------------------------------------------------- Windows: Additions: - Any input key may now be mapped to a joystick. - Alternative set of icons provided by Pongbashi. Changes: - Auto-monitor-frequency setting is now applied after exiting the dialog. Fixes: - Grayed Power-off menu item. - Controllers in netplay. Emulator: Additions: - Mapper 102 (SUNSOFT-3R) for "Shanghai (redump)". - RP2C03B/RC2C05-03 palette. Info from Kevtris. - Color decoder control via R-Y/G-Y/B-Y angle+gain. Comes with three presets. - Support for NSF files that use more than one external soundchip. Changes: - More accurate NES chroma/luma coefficients. Info from Blargg. Fixes: - Mapper 83. Fixes intro in "World Heroes 2". - Mapper 185. Patch for "Seicross (redump)". - APU triangle step-sequencer reset bug. - Some NSF player bugs. - Some database entries. ---------------------------------------------------------------- 1.26 ---------------------------------------------------------------- Windows: Additions: - Automatic joystick axes recalibration. - More video filter options. Changes: - ::GetLongPathName() is now used in conjunction with ::GetCommandLine(). - Better logic for when and when not to preserve the NES picture scale factor in fullscreen. - Minor aestetic fixes. Fixes: - Crash on start in 98/ME. - Crash on exit when two or more video devices are present. - Invalid fullscreen view on dual displays. - Parameter change in ::CompareString() for 98/ME/2k compatibility. - Correct LIB linking order for MSLU. - Bug in WM_DROPFILES and WM_COPYDATA handlers. - Certain input keys are now ignored. Fixes some japanese keyboards. - Can now parse unquoted filenames from the command-line. Emulator: Additions: - MD5 instead of CRC when checking for modified data. - New image file CRCs for auto detection of controllers. - Database entries. Changes: - NTSC filter optimizations. - Minor palette modifications. - __attribute__ ((fastcall)) removed. Seems to be broken in GCC. Fixes: - Some NTSC filter bugs. - Patch for "My Life My Love - Boku no Yume - Watashi no Negai" to use another revision of the MMC3 chip. - NST_ASSERT() macro bug on platforms other than Win32. ---------------------------------------------------------------- 1.25 ---------------------------------------------------------------- Windows: Fixes: - Configuration file parse error after cheats were saved. - Unquoted executable name on the command line. - Archive filenames using non-ascii characters. - File association bug. - Katakana characters when using the 'clipboard-to-NES-screen' feature. - Slight texel-to-pixel mapping inaccuracy. Emulator: Additions: - NTSC composite video emulation. Requires a fast computer. Implementation by Blargg and NewRisingSun. - Mapper 27. Changes: - Took out the database names. Too many errors. Fixes: - Mapper 16 IRQ timing. Fixes SD Gundam Gaiden - Knight Gundam Monogatari 2 - Hikari no Kishi. - King of Fighters 99 (no-frame-IRQ hack). - Save state errors with MMC3 games. - Blitter producing garbage on screen (rare occasions). - Some ISO C++ misstakes. ---------------------------------------------------------------- 1.24 ---------------------------------------------------------------- Windows Port: Additions: - Unicode support. Win98/Me users need to obtain the Unicode Layer DLL (unicows.dll) from Microsoft's site and place it in the same directory as Nestopia. Evil hotlink: http://download.microsoft.com/download/b/7/5/b75eace3-00e2-4aa0-9a6f-0b6882c71642/unicows.exe - Palette editor (video options dialog). - NSV movie to AVI converter. - Several new NSP file commands. - Clipboard text can now be pasted into the screen through the menu or F12 when the Family Basic or Subor keyboard is in use. Changes: - Original kailleraclient.dll replaced with Anti3D's version. - Localized keyboard layout names. - Better DirectInput to Family Basic keyboard mapping. - Default save file path is now .\save instead of .\cartridge for consistency as some of the new save file types aren't technically part of a cartridge. - Various aestetic fixes. Fixes: - Menu->File->Sound Recorder->Rewind command is now disabled during recording. - Workaround for the notorious VC8 iostream memory leak bug. Emulation Core: Additions: - VRC7 sound chip (Lagrange Point). - Mappers 137,138,139,141,143,145,146,147,148 and 149. Info from CaH4e3. - UNIF boards 8157 and CC-21. Info from CaH4e3. - Family Trainer, Subor Keyboard, Doremikko Keyboard (partial) and Party Tap expansion port devices. - Turbo File using *.tf as file extension (some games by ASCII). - Data Recorder using *.tp as file extension (Family Basic, Mach Rider, Excitebike, others). - Datach Joint ROM System and Barcode Battler. - 24C01+24C02 serial EEPROM for mapper 16 and 157. - Secondary controller pad microphone via button press. - Sound samples for Moero!! Pro Yakyuu. - Option for allowing up/down and left/right button presses simultaneously. - Some game database entries. Fixes: - FME-07 sound pitch. - Mappers 76 and 83. - Longer delay for FDS block-start reads. Fixes Time Twist. - Some game database entries. - NSF player bug with some FDS songs. - Frame IRQ disabled by default (hack) for King of Fighters 97/98 and Sonic 3D Blast 6. - Coefficients for the color emphasis modes. Info from Quietust. ---------------------------------------------------------------- 1.23 ---------------------------------------------------------------- Windows Port: - Upgraded compiler. - Added an option in the video dialog to automatically take advantage of other display frequencies. It's disabled by default for compatibility reasons but should be enabled for best performance. - IDirect3DDevice9::SetDialogBoxMode() and D3DPRESENTFLAG_LOCKABLE_BACKBUFFER are now ONLY set when a menu or window is visible in full-screen mode. Improves speed and vsync timing. - Added an option for tripple-buffering in the timing dialog. - Emulation is now stopped upon menubar activation. - The last selected file type in the launcher dialog is now remembered throughout the application lifetime. - File names that are too long to fit inside the screen message field are now truncated using ellipses. - Minor bug fixes. ---------------------------------------------------------------- 1.22 ---------------------------------------------------------------- Windows Port: - Added support for RAR and 7-Zip files. - Enabled use of XP visual styles. - Cleaned up the GUI a bit and fixed proper tab ordering. - Added cheat search support. - Added some joystick options. People having joystick problems in earlier versions can now disable the buggy axes. - Improved auto frame skipping performance. - Fixed an FDS BIOS path saving bug. - Fixed an auto IPS patching bug. - Fixed a Wave file recording bug. - Fixed an Alt+Tab from fullscreen bug. - Fixed a cheats delete/clear bug. Emulation Core: - Added real-time rewinding support (up to 1 minute). To use it, assign it to any key and enable it in the Timing dialog. - Added support for cheats in the whole address range. - Added support for "Pro Action Rocky" cheat codes. - Added DPCM channel sample interpolation and DC offset removal. - Improved PPU vblank timing and flag behaviour, info from Blargg. - Fixed mapper 6 and moved "Mi Hu Chen (hFFE)" to it, info from CaH4e3. - Moved "Shin Samurai Spirits 2", "Power Rangers III" and "Power Rangers IV" to mapper 209. - Moved "Mortal Kombat 3 - Special 56 People" to mapper 90. - Hacked mapper 90, more games are playable now, - Added mapper 148 and moved "Sugoro Quest - Dice no Senshitachi (asia)" to it. - Added mapper 183, info from CaH4e3. - Added mapper 186, info from CaH4e3. - Fixed mapper 187, "King Of Fighters 96" is now playable. - Added mapper 216, info from CaH4e3. - Added DreamTech UNIF board, info from CaH4e3. - Added H2288 UNIF board, info from Kevtris and CaH4e3. - Added proper handling of FDS disk insert/eject during movie playing/recording. ---------------------------------------------------------------- 1.21 ---------------------------------------------------------------- - Adjusted PPU cold reset timing, fixes Time Lord. - Removed $4017.7 check for DMC IRQ, fixes Silent Service and Time Lord. - Added an option for preserving the window size and position after exit. - Added A12 hook for $2007(R/W). - Added a newer version of ZLib. - Fixed a window focus bug. - Fixed a window size on startup bug. - Fixed two minor APU save/load state bugs. - Fixed a minor PPU sprite overflow bug. - Corrected a VS palette entry, VS.Goonies looks better now. - Options in the machine section in the menu are now saved on exit. - Improved compatibility with DirectInput devices. ---------------------------------------------------------------- 1.20 ---------------------------------------------------------------- Given the fact that it has taken almost two years to complete this release I've basically lost track of the shitload of changes and fixes I've made throughout this time, but I'll try to cover the most notable new additions. But first, I'd like to thank all the beta testers who helped shaping up this release, especially Hellsbane, Michael Walsemann, Benjamin Siskoo and Robert Tuccitto for their dedicated time and effort in searching for bugs. The Windows port has been rewritten from scratch (which proved to be more time consuming than I initially thought). The emulation core has gone through a complete overhaul as well. Some of the new features: - DirectDraw kicked out and replaced by Direct3D (DirectX 9.0c now required) - More video filtering options - More multitasking friendly - Configurable menu keys - Less cumbersome to take screenshots and no more GDI+ requirement - Selectable auto-fire speed - Recent directories - Ability to lock and clear the recent files and directories lists - Selectable LED source for FDS disk access - Alternative emulation speed via assignable key/button - Ability to change the menu color - Changes to brightness/saturation/hue takes effect immediately - More logfile (disabled by default now) diagnostics - Cursor gets auto-hidden - Many hard-coded strings now moved into the resource section - Image info for FDS and NSF files - Can make IPS files out of changes to FDS disk files - Can edit iNes file headers - Hq2x/Hq3x filter support - Additional GUI improvements New iNes mappers: 53, 56, 142, 158, 164, 165, 193, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 215, 217 Fixed iNes mappers: *many* New UNIF boards: Mario 1 Malee 2, Novel Diamond 9999999-in-1, Super Game 8237 Super 24-in-1, WS 40-in-1 New controllers: Oeka Kids Tablet, Hyper Shot, Crazy Climber, Mahjong, Exciting Boxing Top Rider, Pokkun Moguraa Other emu core related things: - More standard conformant C++ code - Easier to port to other platforms using a new written API - Many speed optimizations (but at NO cost of emulation accuracy) - Save state and movie file formats rewritten, old files will no longer work - More accurate APU and PPU emulation thanks to RE work by Blargg, Kevtris and Quietust - Perfectly time-aligned sound sample output by using a common clocking rate - Uses new updated palette by BMF - Better (but not perfect) NTSC color generation algorithm based on tweaks by AWJ - ROM database fixes and additions - Support for phantom stereo sound output - More accurate FDS emulation - Better sound quality with the external sound chips - Auto-selects between Famicom and NES 4-player adapter based on game CRC - More accurate emulation for several controllers - More accurate hard/soft reset behaviour That covers most of it. If you like this release and would like to thank me for eating Nestopia, sleeping Nestopia and breathing Nestopia during these past two years consider donating a few bucks through the pay-pal link at http://sourceforge.net/projects/nestopia. ---------------------------------------------------------------- 1.09 ---------------------------------------------------------------- -Added netplay (Kaillera). -Added Scale2x/3x graphic filters. -Menu can now be toggled in window mode. -'Unlimited Sprites' bug fixed. -Fixed FDS IRQ counter, glitches gone in SMB2(j). -Fixed mapper 5, glitches gone in all KOEI games plus others. Save games and states fixed as well. -Added mapper 12, info from VirtuaNES. -Tweaked mapper 17 IRQ counter, fixes a few more FFE F8 games. -Reassigned mapper 48 to 33 (Flintstones - The Rescue of Dino & Hoppy (j)). -Fixed mapper 65, glitches gone in "Kaiketsu Yanchamaru 3 - Taiketsu! Zouringen" among others. -Fixed mapper 69, "Honoo no Toukyuuji - Dodge Danpei" plus others work. -Fixed mapper 182, glitches gone in "Super Donkey Kong". -Added mapper 200, info from CaH4e3. -Added mapper 201, info from CaH4e3. -Added mapper 202, info from CaH4e3. -Fixed mapper 245, "Yong Zhe Dou E Long - Dragon Quest 7" plus others work. -Fixed mapper 249, glitches gone in "Shui Hu Zhuan" plus others. -Added mapper 252, info from saro. -Added mapper 254, info from VirtuaNES. -A warning message is displayed when encrypted games are loaded. -Added auto PRG-ROM size correction on known 512k MMC1 games (Dragon Warrior/Quest 4). -OAM address is now cleared on VBLANK start, fixes sprite errors in "Titanic 1912", "Godzilla" and possibly other games. -Made some PPU optimizations (scanline tile caching). -Fixed a minor thread priority bug. -Fixed a PPU reset bug, fixes machine resets in "Knight Rider". -Changed the way CPU RAM gets initialized during power on, fixes first intro screen in "Super Donkey Kong - Xiang Jiao Chuan". -Removed IRQ triggering hacks for mappers 19,21,23,25,33,40,50,65,67,83 and 183. -Swapped p1/p2 controls on some VS games. ---------------------------------------------------------------- 1.08 ---------------------------------------------------------------- -Added a launcher. -Added support for drag-drop files. -Added some more options in the preferences dialog. -Changed so that relative paths are preserved. -Fixed mapper 1, glitches gone in "Air Fortress". -Fixed mapper 4, sound in "Startropics" & "Startropics 2 - Zoda's Revenge" works (MMC6B games which differs from MMC3). -Fixed mapper 10, "Fire Emblem" plus others work. -Fixed mapper 18, "Toukon Club" plus others work (minor glitches still there though). -Fixed mapper 19, "Family Circuit '91" and "Wagan Land 3" plus others work. -Fixed mapper 23, all valid versions of "Akumajou Special - Boku Dracula Kun" should now work. -Fixed mapper 32, "Ai Sensei no Oshiete - Watashi no Hoshi" and "Major League" works. -Fixed mapper 33, glitches gone in "Captain Saver". -Fixed mapper 51, "11-in-one Ball Games" works again. -Fixed mapper 58, "Study and Game 32-in-1" works. -Fixed mapper 60, "Reset Based 4-in-1" works. -Fixed mapper 62, "Super 700-in-1" works. -Fixed mapper 68, "Maharaja" works. -Fixed mapper 70, less glitches in "Gegege no Kitarou 2 - Youkai Gundan no Chousen". -Fixed mapper 82, glitches gone in "Kyuukyoku Harikiri Stadium 3" plus others. -Fixed mapper 87, "City Connection", "Ninja Jajamaru Kun" plus others work. -Fixed mapper 88, glitches gone in "Dragon Spirit - Aratanaru Densetsu" plus others. -Fixed mapper 90, less glitches in "Mortal Kombat 3 - Special 56 Peoples". -Fixed mapper 101, "Urusei Yatsura - Lum no Wedding Bell" works. -Fixed mapper 113, glitches gone in "16 Mahjang". -Fixed mapper 119, glitches gone in "Pinbot" and "Highspeed". -Fixed mapper 185, "Bird Week" works. -Fixed Game Genie bug (certain codes would either not work or crash the application). -Improved CPU/PPU synchronization. Screen shaking gone in many games ("Times of Lore", "Kick Master"). -Tweaked the DMC and noise channel's output frequencies for PAL mode. PAL sound is now more accurate. -Tweaked the DMC DMA/IRQ counters. Most games relying on correctly timed DMC IRQ triggering should now work (Codemasters games, Ian Bell's Tank Demo). ---------------------------------------------------------------- 1.07 ---------------------------------------------------------------- -Added support for file associations (preferences dialog). -Added an option to select between single and multiple application instances (preferences dialog). -Fixed a bug that caused the key mapping for a second joystick device to be reset every time Nestopia was restarted. -Changed so that all Game Genie codes are saved on exit. -Moved most of the on-screen-messages into the resource string table to make life easier for people making translation patches. -Updated the rom database. Thanks again to [yang] for the new compilation. -Fixed so that ns1..ns9 (save slots) files will show up when browsing files. -Added command line parameter support. -Added a status bar (menu). -Added an FPS counter (menu). -Added an option to force the window on top (menu). -Added an option to disable the performance counter timer (timer dialog). -Added an option to disable configuration saving on exit (preferences dialog). -Added some more shortcut keys to the menu. -Better multitasking. -Added automatic thread priority control (preferences dialog). -Changed so that even a totally screwed up iNes file header may pass thru the loader if the file can be found in the database. -Improved the timers. -Made new icons. -Many bug fixes. ---------------------------------------------------------------- 1.06 ---------------------------------------------------------------- -Fixed the input bug that sneaked up in v1.05. IDirectInputDevice8::Poll() was the cause. I forgot it could return DI_NOEFFECT which is not the same as DI_OK. The bug affected devices that didn't need manual polling. -Fixed a bug that caused all soundcards without support for hardware-mixed secondary buffers to not work. -Did some small optimizations in the PPU core. -Changed so that state slots are flushed to files (if enabled) every time the user saves instead of only during load/close. -Modified the path dialog. Two check mark buttons now control the auto loading and saving of state slots. -Less sound stutter when toggling the menu in fullscreen. -Tweaked the render queue and put a limit on how many frames behind the GPU can be. This is to prevent sudden jerks and input lag. ---------------------------------------------------------------- 1.05 ---------------------------------------------------------------- -Corrected the CRC database searcher (several games had the wrong name displayed in the title bar) -Fixed a bug that made the user defined paths not to be saved properly. -Changed so that images with support for both PAL and NTSC will prioritize NTSC and not PAL as in earlier versions when "auto mode" is selected. -Added mapper 107 ("Magic Dragon") -Added mapper 134 ("Olympiq IQ") -Added mapper 135 ("Super Pang") -Added mapper 198 (chinese version of "Destiny of an Emperor") -Fixed a bug in the UNIF loader that caused all files having a board name beginning with NES-,UNL-,HVC-,BTL- or BMC- to be parsed wrongly. -Fixed a bug that caused the application to hang and/or crash when Alt-Tabbing. -Removed most of the sound clicks and pops heard when the audio gets disabled (menu entering, window moving etc). -Made so that all the save slots automatically gets imported/exported to/from files using .ns1 through ns9 on load/close. It's ON by default. -Fixed a PPU bug that could cause the application to crash when loading up a game in the middle of an NSF tune. -Fixed the frame rate timer. In previous versions it had the potential to cause serious lagging. -Fixed the fullscreen mode cursor, sometimes it could get visible/invisible when it really shouldn't. -Changed to using C++ exceptions, way better error handling now. -Added the option to add custom keys to the "save to next slot" and "load from last slot" commands. -Added 8bit graphic mode. filters are not supported for this one. -Improved the TV-mode graphic filter and removed all visual artifacts in the marginals. -Added an option in the preferences dialog to disable the use of the ROM database. -Added more logfile info. ---------------------------------------------------------------- 1.04 ---------------------------------------------------------------- -Added a TV-mode graphic filter. -Moved the timing options into a separate dialog and added some more features. Speed throttling can now be toggled by F5 (default). -Did some further improvements to the sound quality. -Fixed mapper 64, "Skull & Crossbones" and "Klax" are now playable, thanks to Xodnizel for his findings on this insane mapper. -Fixed mapper 70, "Kamen Rider Kurabu" and "Space Shadow" are now playable. -Fixed mapper 83, "Garou Densetsu 2 (Fatal Fury)" and "World Heroes 2" are now playable. -Added mapper 133 ("Jovial Race") -Fixed mapper 232, "Maxi 15" is now playable. -Fixed mapper 244, now "Decathlon (Asia)" suffers from less glitches. -Changed the configuration file, now it's text based and more hacker friendly. -Changed the shortcut key for fullscreen/window mode switch to ALT+RETURN. -In addition to the right mouse button ESCAPE now also toggles the menu in fullscreen mode. -Fixed a bug that prevented new battery-ram files from being created. -Cleaned up a few things in the DirectSound manager. Hopefully this fixes the sound problems a few people have had. -Added many new file CRC's to the internal database. Thanks to [yang] for the assembling. -Now Nestopia remembers the last selected screen/window size. -Optimized the scanline graphic filter renderer. -Added some more logfile output messages. ---------------------------------------------------------------- 1.03 ---------------------------------------------------------------- -Added 2xSaI, Super 2xSaI and Super Eagle graphic filters. -Added support for all the graphic filters in window mode. -Added game configuration file support. -Improved sound quality. -Added some more file CRC's to the zapper-auto-detector. -Added an option to map all keys in one go. -Added an option in the preferences dialog to force the application's thread to be in high priority mode. -Corrected an entry in the pAPU's length counter LUT. -Changed the square channel's default frequency limit. This fixes the sound in "Mega Man 2" and possibly a few other games. -Fixed a bug that caused some save states not to load correctly. -Lowered the output volume on the FDS sound chip. -Fixed mapper 78, "Holy Diver" and "Uchuusen - Cosmo Carrier" are now playable. -Fixed a frame IRQ counter bug, now "Akagawa no Yuurei Ressha" and "Dragon Warrior" among others work as they should. -Fixed a bug which sometimes caused the user defined IPS path to be ignored. -Rewrote a few parts in the movie player/recorder. Should be more stable now. -Cleaned up a few thing in the GUI. ---------------------------------------------------------------- 1.02 ---------------------------------------------------------------- -Added UNIF support. -Fixed a bug in the Game Genie decoder, now eight-character codes works correctly. -Added support for more axis buttons (sliders, pov etc). Havn't tested them tough as I don't have that kind of joystick, can anyone confirm they work? -Fixed so that Nestopia will recognise the Twin Famicom BIOS ROM. -Added adjustable dipswitches for "Nintendo World Championship" (mapper 105), now you can control and display the timer. -Fixed mapper 91 (IRQ counter thing), now all mapper 91 games shows the correct graphic. -Fixed mapper 187, now "Street Fighter Zero 2 '97" works. -Fixed a bug in the Sunsoft FME-07 sound core. -Did some cleanup in the application error handling routines - no more page-faults on known errors. -No more distortion in screen when enabling/disabling the menu in fullscreen mode (LockWindowUpdate() to the rescue). -Fixed a bug which sometimes caused the window, when coming out of fullscreen, to be maximized and stretched to the size of the desktop. -Fixed a bug that caused the switching from window to fullscreen with the same display mode to fail. -Fixed a bug in the PDXSTRING class, nothing that affected previous versions of Nestopia though. -Lowered the system requirements to Pentium MMX, users with processors that lacks the CMOV instruction can now run Nestopia. -Added some menu options to control the size of the window/screen (works both in window and fullscreen mode). ---------------------------------------------------------------- 1.01 ---------------------------------------------------------------- Fixed a bug that caused the application to exit with the "DirectSoundCreate8() failed" message. ---------------------------------------------------------------- 1.00 ---------------------------------------------------------------- Initial release. nestopia-1.51.1/Makefile.am000066400000000000000000001175731411157722000154730ustar00rootroot00000000000000############### # Definitions # ############### bin_PROGRAMS = nestopia EXTRA_DIST = doc nestopia_CPPFLAGS = \ -I$(top_srcdir)/source \ -I$(top_srcdir)/source/fltkui \ -DDATADIR=\"$(datadir)/nestopia\" \ -DDATAROOTDIR=\"$(datarootdir)\" \ -DNST_PRAGMA_ONCE \ $(ZLIB_CFLAGS) \ $(LIBARCHIVE_CFLAGS) \ $(SDL2_CFLAGS) \ $(FLTK_CFLAGS) nestopia_LDADD = \ $(ZLIB_LIBS) \ $(LIBARCHIVE_LIBS) \ $(SDL2_LIBS) \ $(FLTK_LIBS) ################ # Installation # ################ # program-specific files databasedir = $(datadir)/nestopia dist_database_DATA = NstDatabase.xml # freedesktop.org-specific files desktopdir = $(datarootdir)/applications dist_desktop_DATA = icons/nestopia.desktop icon32dir = $(datarootdir)/icons/hicolor/32x32/apps dist_icon32_DATA = icons/32/nestopia.png icon48dir = $(datarootdir)/icons/hicolor/48x48/apps dist_icon48_DATA = icons/48/nestopia.png icon64dir = $(datarootdir)/icons/hicolor/64x64/apps dist_icon64_DATA = icons/64/nestopia.png icon96dir = $(datarootdir)/icons/hicolor/96x96/apps dist_icon96_DATA = icons/96/nestopia.png icon128dir = $(datarootdir)/icons/hicolor/128x128/apps dist_icon128_DATA = icons/128/nestopia.png iconsvgdir = $(datarootdir)/icons/hicolor/scalable/apps dist_iconsvg_DATA = icons/svg/nestopia.svg icons/svg/nespad.svg # documentation dist_doc_DATA = ChangeLog README.md dist_html_DATA = readme.html ##################### # Source code files # ##################### EXTRA_DIST += \ source/core/NstVideoFilterHq3x.inl \ source/core/NstVideoFilterHq4x.inl \ source/core/NstVideoFilterHq2x.inl \ source/core/NstSoundRenderer.inl \ source/nes_ntsc/nes_ntsc.inl nestopia_SOURCES = \ source/core/NstTrackerMovie.hpp \ source/core/NstFile.hpp \ source/core/NstAssert.cpp \ source/core/NstIoLine.hpp \ source/core/NstCartridgeInes.cpp \ source/core/NstSoundRenderer.hpp \ source/core/NstMachine.hpp \ source/core/NstFile.cpp \ source/core/NstVideoFilterxBR.cpp \ source/core/NstChecksum.hpp \ source/core/NstVideoFilterNone.cpp \ source/core/NstPatcherUps.cpp \ source/core/NstCartridgeRomset.hpp \ source/core/input/NstInpBarcodeWorld.hpp \ source/core/input/NstInpKonamiHyperShot.hpp \ source/core/input/NstInpPowerGlove.hpp \ source/core/input/NstInpTopRider.cpp \ source/core/input/NstInpMouse.hpp \ source/core/input/NstInpCrazyClimber.cpp \ source/core/input/NstInpSuborKeyboard.hpp \ source/core/input/NstInpPowerPad.hpp \ source/core/input/NstInpPowerGlove.cpp \ source/core/input/NstInpOekaKidsTablet.cpp \ source/core/input/NstInpMouse.cpp \ source/core/input/NstInpAdapter.hpp \ source/core/input/NstInpPartyTap.hpp \ source/core/input/NstInpFamilyTrainer.cpp \ source/core/input/NstInpExcitingBoxing.hpp \ source/core/input/NstInpPartyTap.cpp \ source/core/input/NstInpPaddle.hpp \ source/core/input/NstInpMahjong.cpp \ source/core/input/NstInpDevice.hpp \ source/core/input/NstInpTurboFile.cpp \ source/core/input/NstInpBarcodeWorld.cpp \ source/core/input/NstInpRob.hpp \ source/core/input/NstInpPad.hpp \ source/core/input/NstInpPad.cpp \ source/core/input/NstInpZapper.hpp \ source/core/input/NstInpFamilyKeyboard.cpp \ source/core/input/NstInpMahjong.hpp \ source/core/input/NstInpPachinko.hpp \ source/core/input/NstInpAdapter.cpp \ source/core/input/NstInpRob.cpp \ source/core/input/NstInpDoremikkoKeyboard.cpp \ source/core/input/NstInpPachinko.cpp \ source/core/input/NstInpOekaKidsTablet.hpp \ source/core/input/NstInpKonamiHyperShot.cpp \ source/core/input/NstInpFamilyTrainer.hpp \ source/core/input/NstInpZapper.cpp \ source/core/input/NstInpTopRider.hpp \ source/core/input/NstInpHoriTrack.cpp \ source/core/input/NstInpPokkunMoguraa.hpp \ source/core/input/NstInpBandaiHyperShot.hpp \ source/core/input/NstInpCrazyClimber.hpp \ source/core/input/NstInpTurboFile.hpp \ source/core/input/NstInpFamilyKeyboard.hpp \ source/core/input/NstInpExcitingBoxing.cpp \ source/core/input/NstInpPowerPad.cpp \ source/core/input/NstInpDoremikkoKeyboard.hpp \ source/core/input/NstInpSuborKeyboard.cpp \ source/core/input/NstInpPokkunMoguraa.cpp \ source/core/input/NstInpBandaiHyperShot.cpp \ source/core/input/NstInpPaddle.cpp \ source/core/input/NstInpHoriTrack.hpp \ source/core/NstCartridge.hpp \ source/core/NstStream.cpp \ source/core/NstCheats.hpp \ source/core/NstHomebrew.hpp \ source/core/vssystem/NstVsSystem.hpp \ source/core/vssystem/NstVsRbiBaseball.hpp \ source/core/vssystem/NstVsSuperXevious.cpp \ source/core/vssystem/NstVsRbiBaseball.cpp \ source/core/vssystem/NstVsSuperXevious.hpp \ source/core/vssystem/NstVsTkoBoxing.cpp \ source/core/vssystem/NstVsSystem.cpp \ source/core/vssystem/NstVsTkoBoxing.hpp \ source/core/NstTracker.cpp \ source/core/NstChips.hpp \ source/core/NstIoMap.hpp \ source/core/NstVideoFilterxBR.hpp \ source/core/NstXml.cpp \ source/core/NstProperties.cpp \ source/core/NstCpu.cpp \ source/core/NstXml.hpp \ source/core/NstVideoFilterHqX.hpp \ source/core/NstVideoRenderer.cpp \ source/core/NstPatcherIps.cpp \ source/core/NstVideoFilterScaleX.hpp \ source/core/NstImageDatabase.hpp \ source/core/NstVideoRenderer.hpp \ source/core/NstImage.hpp \ source/core/NstTrackerRewinder.cpp \ source/core/NstVector.cpp \ source/core/NstLog.cpp \ source/core/NstSoundPlayer.cpp \ source/core/NstSoundRenderer.cpp \ source/core/NstCartridge.cpp \ source/core/NstIoAccessor.hpp \ source/core/NstDipSwitches.hpp \ source/core/NstFds.hpp \ source/core/NstChips.cpp \ source/core/NstApu.cpp \ source/core/NstState.hpp \ source/core/NstSha1.hpp \ source/core/NstVideoFilter2xSaI.hpp \ source/core/NstVideoFilterHqX.cpp \ source/core/NstPatcherUps.hpp \ source/core/NstCore.hpp \ source/core/NstSha1.cpp \ source/core/NstVideoScreen.hpp \ source/core/NstTracker.hpp \ source/core/NstRam.cpp \ source/core/NstTimer.hpp \ source/core/NstState.cpp \ source/core/api/NstApiEmulator.hpp \ source/core/api/NstApiVideo.cpp \ source/core/api/NstApiCheats.cpp \ source/core/api/NstApiHomebrew.cpp \ source/core/api/NstApiMovie.hpp \ source/core/api/NstApiCartridge.cpp \ source/core/api/NstApi.hpp \ source/core/api/NstApiMachine.hpp \ source/core/api/NstApiRewinder.hpp \ source/core/api/NstApiMovie.cpp \ source/core/api/NstApiTapeRecorder.cpp \ source/core/api/NstApiEmulator.cpp \ source/core/api/NstApiRewinder.cpp \ source/core/api/NstApiNsf.cpp \ source/core/api/NstApiFds.cpp \ source/core/api/NstApiNsf.hpp \ source/core/api/NstApiMachine.cpp \ source/core/api/NstApiDipSwitches.cpp \ source/core/api/NstApiUser.hpp \ source/core/api/NstApiUser.cpp \ source/core/api/NstApiTapeRecorder.hpp \ source/core/api/NstApiBarcodeReader.hpp \ source/core/api/NstApiConfig.hpp \ source/core/api/NstApiFds.hpp \ source/core/api/NstApiVideo.hpp \ source/core/api/NstApiCheats.hpp \ source/core/api/NstApiHomebrew.hpp \ source/core/api/NstApiBarcodeReader.cpp \ source/core/api/NstApiInput.hpp \ source/core/api/NstApiInput.cpp \ source/core/api/NstApiSound.cpp \ source/core/api/NstApiSound.hpp \ source/core/api/NstApiDipSwitches.hpp \ source/core/api/NstApiCartridge.hpp \ source/core/NstCartridgeUnif.hpp \ source/core/NstProperties.hpp \ source/core/NstVideoScreen.cpp \ source/core/NstFpuPrecision.hpp \ source/core/NstRam.hpp \ source/core/NstCheats.cpp \ source/core/NstHomebrew.cpp \ source/core/NstZlib.cpp \ source/core/NstStream.hpp \ source/core/NstBase.hpp \ source/core/NstCartridgeUnif.cpp \ source/core/NstCore.cpp \ source/core/NstImage.cpp \ source/core/NstPatcherIps.hpp \ source/core/NstLog.hpp \ source/core/NstVideoFilter2xSaI.cpp \ source/core/NstMemory.cpp \ source/core/NstImageDatabase.cpp \ source/core/NstMachine.cpp \ source/core/NstAssert.hpp \ source/core/NstPins.cpp \ source/core/NstApu.hpp \ source/core/NstIoPort.hpp \ source/core/NstPpu.cpp \ source/core/NstTrackerMovie.cpp \ source/core/NstPatcher.cpp \ source/core/NstPpu.hpp \ source/core/NstMemory.hpp \ source/core/NstVideoFilterNone.hpp \ source/core/board/NstBoardBmcHero.hpp \ source/core/board/NstBoardVsSystem.cpp \ source/core/board/NstBoardBmcSuperVision16in1.hpp \ source/core/board/NstBoardBmc72in1.cpp \ source/core/board/NstBoardBandaiDatach.hpp \ source/core/board/NstBoardSunsoft3.hpp \ source/core/board/NstBoardUnlTf1201.cpp \ source/core/board/NstBoardMmc4.hpp \ source/core/board/NstBoardNRom.hpp \ source/core/board/NstBoardBmcResetBased4in1.cpp \ source/core/board/NstBoardKay.hpp \ source/core/board/NstBoardBmcSuper22Games.hpp \ source/core/board/NstBoardBmc20in1.cpp \ source/core/board/NstBoardBtlShuiGuanPipe.hpp \ source/core/board/NstBoardSuperGameBoogerman.hpp \ source/core/board/NstBoardKonamiVrc6.cpp \ source/core/board/NstBoardKonamiVrc2.cpp \ source/core/board/NstBoardSachenS8259.cpp \ source/core/board/NstBoardCneDecathlon.hpp \ source/core/board/NstBoardJalecoJf17.cpp \ source/core/board/NstBoardBmcVrc4.cpp \ source/core/board/NstBoardIremLrog017.hpp \ source/core/board/NstBoardWaixingSgzlz.cpp \ source/core/board/NstBoardUnlA9746.cpp \ source/core/board/NstBoardNtdec.hpp \ source/core/board/NstBoardJalecoJf17.hpp \ source/core/board/NstBoardNamcot175.cpp \ source/core/board/NstBoardNamcot340.cpp \ source/core/board/NstBoardCamerica.cpp \ source/core/board/NstBoardGouder.hpp \ source/core/board/NstBoardJalecoJf16.cpp \ source/core/board/NstBoardBmc31in1.hpp \ source/core/board/NstBoardBmcA65as.hpp \ source/core/board/NstBoardTxc.cpp \ source/core/board/NstBoardCamerica.hpp \ source/core/board/NstBoardKonamiVsSystem.hpp \ source/core/board/NstBoardFxRom.hpp \ source/core/board/NstBoardBmcSuperGun20in1.hpp \ source/core/board/NstBoardDiscrete.cpp \ source/core/board/NstBoardBmcY2k64in1.hpp \ source/core/board/NstBoardAveD1012.cpp \ source/core/board/NstBoardSachenSa0036.hpp \ source/core/board/NstBoardTxcTw.hpp \ source/core/board/NstBoard.cpp \ source/core/board/NstBoardBmcPowerjoy84in1.cpp \ source/core/board/NstBoardBtlSmb2a.hpp \ source/core/board/NstBoardTaitoX1005.cpp \ source/core/board/NstBoardBandaiLz93d50ex.hpp \ source/core/board/NstBoardBmc64in1.hpp \ source/core/board/NstBoardEvent.hpp \ source/core/board/NstBoardBtlMarioBaby.cpp \ source/core/board/NstBoardDxRom.hpp \ source/core/board/NstBoardMmc3.cpp \ source/core/board/NstBoardWaixingZs.cpp \ source/core/board/NstBoardJxRom.hpp \ source/core/board/NstBoardBmc36in1.cpp \ source/core/board/NstBoardWaixingSecurity.cpp \ source/core/board/NstBoardBmcGoldenGame260in1.cpp \ source/core/board/NstBoardBandaiLz93d50.hpp \ source/core/board/NstBoardAve.hpp \ source/core/board/NstBoardBtl6035052.cpp \ source/core/board/NstBoardNitra.cpp \ source/core/board/NstBoardWaixingPs2.hpp \ source/core/board/NstBoardHosenkan.cpp \ source/core/board/NstBoardUnlSuperFighter3.cpp \ source/core/board/NstBoardWaixingSh2.hpp \ source/core/board/NstBoardBtlT230.hpp \ source/core/board/NstBoardKonamiVrc7.hpp \ source/core/board/NstBoardSuperGamePocahontas2.hpp \ source/core/board/NstBoardUxRom.hpp \ source/core/board/NstBoardRcm.hpp \ source/core/board/NstBoardBmcSuperGun20in1.cpp \ source/core/board/NstBoardCne.hpp \ source/core/board/NstBoardNanjing.hpp \ source/core/board/NstBoardBmcVrc4.hpp \ source/core/board/NstBoardKonamiVrc6.hpp \ source/core/board/NstBoardBmc9999999in1.cpp \ source/core/board/NstBoardFfe.cpp \ source/core/board/NstBoardBmcA65as.cpp \ source/core/board/NstBoardMmc5.cpp \ source/core/board/NstBoardTaitoTc0190fmcPal16r4.hpp \ source/core/board/NstBoardRexSoft.hpp \ source/core/board/NstBoardKonamiVrc2.hpp \ source/core/board/NstBoardMmc2.cpp \ source/core/board/NstBoardIremHolyDiver.cpp \ source/core/board/NstBoardJaleco.hpp \ source/core/board/NstBoardHenggedianzi.hpp \ source/core/board/NstBoardRexSoftSl1632.hpp \ source/core/board/NstBoardNamcot175.hpp \ source/core/board/NstBoardNamcot340.hpp \ source/core/board/NstBoardBmcSuper700in1.hpp \ source/core/board/NstBoardBmc21in1.cpp \ source/core/board/NstBoardBmc8157.cpp \ source/core/board/NstBoardSxRom.hpp \ source/core/board/NstBoardGouder.cpp \ source/core/board/NstBoardBmcGolden190in1.hpp \ source/core/board/NstBoardBmcGoldenGame260in1.hpp \ source/core/board/NstBoardMmc3.hpp \ source/core/board/NstBoardSuperGame.hpp \ source/core/board/NstBoardBtlPikachuY2k.cpp \ source/core/board/NstBoardSunsoftDcs.hpp \ source/core/board/NstBoardCaltron.cpp \ source/core/board/NstBoardSachenSa0037.hpp \ source/core/board/NstBoardBmcGamestarB.hpp \ source/core/board/NstBoardUnlKingOfFighters97.cpp \ source/core/board/NstBoardFfe.hpp \ source/core/board/NstBoardBmcNovelDiamond.cpp \ source/core/board/NstBoardBtlPikachuY2k.hpp \ source/core/board/NstBoardSunsoftDcs.cpp \ source/core/board/NstBoardTxRom.cpp \ source/core/board/NstBoardBmcY2k64in1.cpp \ source/core/board/NstBoardTxcTw.cpp \ source/core/board/NstBoardTengen.cpp \ source/core/board/NstBoardUnlCc21.cpp \ source/core/board/NstBoardBxRom.cpp \ source/core/board/NstBoardJalecoJf19.hpp \ source/core/board/NstBoardBmcNovelDiamond.hpp \ source/core/board/NstBoardBandaiOekaKids.cpp \ source/core/board/NstBoardSunsoft5b.hpp \ source/core/board/NstBoardNamcot163.hpp \ source/core/board/NstBoardKonami.hpp \ source/core/board/NstBoardCneShlz.hpp \ source/core/board/NstBoardOpenCorp.cpp \ source/core/board/NstBoardMmc4.cpp \ source/core/board/NstBoardJalecoJf16.hpp \ source/core/board/NstBoardSachenSa72008.cpp \ source/core/board/NstBoardUnlWorldHero.hpp \ source/core/board/NstBoardKonamiVrc1.cpp \ source/core/board/NstBoardDreamtech.cpp \ source/core/board/NstBoardBandaiAerobicsStudio.cpp \ source/core/board/NstBoardCxRom.cpp \ source/core/board/NstBoardHosenkan.hpp \ source/core/board/NstBoardBmc64in1.cpp \ source/core/board/NstBoardJalecoJf11.cpp \ source/core/board/NstBoardBtlGeniusMerioBros.cpp \ source/core/board/NstBoardBtlSmb2c.hpp \ source/core/board/NstBoardBmcSuperHiK300in1.hpp \ source/core/board/NstBoardSubor.cpp \ source/core/board/NstBoardBtlSuperBros11.hpp \ source/core/board/NstBoardUnlKingOfFighters97.hpp \ source/core/board/NstBoardHxRom.hpp \ source/core/board/NstBoardIremG101.cpp \ source/core/board/NstBoardFutureMedia.hpp \ source/core/board/NstBoardBtlTobidaseDaisakusen.hpp \ source/core/board/NstBoardIremKaiketsu.cpp \ source/core/board/NstBoardWaixingPs2.cpp \ source/core/board/NstBoardBmcSuper700in1.cpp \ source/core/board/NstBoardSunsoft5b.cpp \ source/core/board/NstBoardNtdec.cpp \ source/core/board/NstBoardBmcSuperHiK300in1.cpp \ source/core/board/NstBoardBmcHero.cpp \ source/core/board/NstBoardWaixingSgz.cpp \ source/core/board/NstBoardBmc35in1.cpp \ source/core/board/NstBoardBmcVt5201.hpp \ source/core/board/NstBoardBtlSmb2b.cpp \ source/core/board/NstBoardSachenTca01.hpp \ source/core/board/NstBoardSunsoft1.cpp \ source/core/board/NstBoardMmc6.hpp \ source/core/board/NstBoardIremKaiketsu.hpp \ source/core/board/NstBoardUxRom.cpp \ source/core/board/NstBoardBenshengBs5.cpp \ source/core/board/NstBoardMmc1.hpp \ source/core/board/NstBoardFujiya.cpp \ source/core/board/NstBoardTaitoX1005.hpp \ source/core/board/NstBoardBandai24c0x.cpp \ source/core/board/NstBoardSachen74x374.cpp \ source/core/board/NstBoardWaixingSgz.hpp \ source/core/board/NstBoardBenshengBs5.hpp \ source/core/board/NstBoardWaixingZs.hpp \ source/core/board/NstBoardAe.hpp \ source/core/board/NstBoardWaixingSh2.cpp \ source/core/board/NstBoardBmc76in1.cpp \ source/core/board/NstBoardBmcSuper24in1.cpp \ source/core/board/NstBoardAcclaim.hpp \ source/core/board/NstBoardJalecoSs88006.cpp \ source/core/board/NstBoardIremLrog017.cpp \ source/core/board/NstBoardSuperGameLionKing.cpp \ source/core/board/NstBoardBmcMarioParty7in1.hpp \ source/core/board/NstBoardBmc800in1.cpp \ source/core/board/NstBoardUnlEdu2000.cpp \ source/core/board/NstBoardBtlAx5705.hpp \ source/core/board/NstBoardAcclaimMcAcc.cpp \ source/core/board/NstBoardRexSoftDb5z.hpp \ source/core/board/NstBoardBtl6035052.hpp \ source/core/board/NstBoardUnlA9746.hpp \ source/core/board/NstBoardTxcMxmdhtwo.cpp \ source/core/board/NstBoardBmcFamily4646B.hpp \ source/core/board/NstBoardBmcCtc65.cpp \ source/core/board/NstBoardBmc36in1.hpp \ source/core/board/NstBoardBmcBallgames11in1.hpp \ source/core/board/NstBoardSuperGameBoogerman.cpp \ source/core/board/NstBoardBtlSmb2a.cpp \ source/core/board/NstBoardSachenStreetHeroes.hpp \ source/core/board/NstBoardKaiser.cpp \ source/core/board/NstBoardBmcT262.cpp \ source/core/board/NstBoardAveNina.hpp \ source/core/board/NstBoardFb.hpp \ source/core/board/NstBoardSachenTcu.cpp \ source/core/board/NstBoardKonamiVrc4.cpp \ source/core/board/NstBoardIremG101.hpp \ source/core/board/NstBoardJalecoJf13.cpp \ source/core/board/NstBoardKayPandaPrince.cpp \ source/core/board/NstBoardTaitoX1017.cpp \ source/core/board/NstBoardBmc110in1.hpp \ source/core/board/NstBoardHes.cpp \ source/core/board/NstBoardSachenStreetHeroes.cpp \ source/core/board/NstBoardUnlMortalKombat2.cpp \ source/core/board/NstBoardKonamiVsSystem.cpp \ source/core/board/NstBoardBandaiKaraokeStudio.cpp \ source/core/board/NstBoardBtlAx5705.cpp \ source/core/board/NstBoardExRom.hpp \ source/core/board/NstBoardBtl2708.hpp \ source/core/board/NstBoardBtl2708.cpp \ source/core/board/NstBoardBandaiLz93d50.cpp \ source/core/board/NstBoardUnlEdu2000.hpp \ source/core/board/NstBoardTengenRambo1.hpp \ source/core/board/NstBoardBmcT262.hpp \ source/core/board/NstBoardCony.hpp \ source/core/board/NstBoardBmc150in1.hpp \ source/core/board/NstBoardEvent.cpp \ source/core/board/NstBoardFutureMedia.cpp \ source/core/board/NstBoardRumbleStation.hpp \ source/core/board/NstBoardSomeriTeamSl12.hpp \ source/core/board/NstBoardBtlSmb3.hpp \ source/core/board/NstBoardUnlSuperFighter3.hpp \ source/core/board/NstBoardBmcSuperBig7in1.cpp \ source/core/board/NstBoardIremHolyDiver.hpp \ source/core/board/NstBoardBmc22Games.hpp \ source/core/board/NstBoardMmc2.hpp \ source/core/board/NstBoardJyCompany.cpp \ source/core/board/NstBoardSachenSa0036.cpp \ source/core/board/NstBoardTxRom.hpp \ source/core/board/NstBoardKonamiVrc3.hpp \ source/core/board/NstBoardTengenRambo1.cpp \ source/core/board/NstBoardFb.cpp \ source/core/board/NstBoardCnePsb.hpp \ source/core/board/NstBoardBmcGamestarA.hpp \ source/core/board/NstBoardBtlGeniusMerioBros.hpp \ source/core/board/NstBoardAcclaimMcAcc.hpp \ source/core/board/NstBoardBandai24c0x.hpp \ source/core/board/NstBoardKayH2288.hpp \ source/core/board/NstBoardBmcCh001.hpp \ source/core/board/NstBoardKonamiVrc4.hpp \ source/core/board/NstBoardBtlSmb3.cpp \ source/core/board/NstBoardJalecoSs88006.hpp \ source/core/board/NstBoardKonamiVrc1.hpp \ source/core/board/NstBoardBmc15in1.cpp \ source/core/board/NstBoardRumbleStation.cpp \ source/core/board/NstBoardTxcPoliceman.hpp \ source/core/board/NstBoardBmcFk23c.cpp \ source/core/board/NstBoardBmc21in1.hpp \ source/core/board/NstBoardSubor.hpp \ source/core/board/NstBoardUnlWorldHero.cpp \ source/core/board/NstBoardBandaiDatach.cpp \ source/core/board/NstBoardUnlXzy.cpp \ source/core/board/NstBoardTxc.hpp \ source/core/board/NstBoardTxcPoliceman.cpp \ source/core/board/NstBoardWaixing.cpp \ source/core/board/NstBoardKonamiVrc3.cpp \ source/core/board/NstBoardNamcot.hpp \ source/core/board/NstBoardSunsoft4.hpp \ source/core/board/NstBoardAe.cpp \ source/core/board/NstBoardBtlDragonNinja.hpp \ source/core/board/NstBoardJyCompany.hpp \ source/core/board/NstBoardBtlSuperBros11.cpp \ source/core/board/NstBoardBmc110in1.cpp \ source/core/board/NstBoardNxRom.hpp \ source/core/board/NstBoardBmcSuperVision16in1.cpp \ source/core/board/NstBoardAveD1012.hpp \ source/core/board/NstBoardUnlMortalKombat2.hpp \ source/core/board/NstBoardSunsoft4.cpp \ source/core/board/NstBoardBmcCh001.cpp \ source/core/board/NstBoardBmcSuper40in1.cpp \ source/core/board/NstBoardAxRom.cpp \ source/core/board/NstBoardBmcSuper24in1.hpp \ source/core/board/NstBoardKayH2288.cpp \ source/core/board/NstBoardSachen.hpp \ source/core/board/NstBoardIremH3001.hpp \ source/core/board/NstBoardSunsoftFme7.hpp \ source/core/board/NstBoardBmcGoldenCard6in1.cpp \ source/core/board/NstBoardSuperGameLionKing.hpp \ source/core/board/NstBoardRcm.cpp \ source/core/board/NstBoardUnlKingOfFighters96.hpp \ source/core/board/NstBoardGxRom.hpp \ source/core/board/NstBoardNamcot34xx.cpp \ source/core/board/NstBoardTaitoX1017.hpp \ source/core/board/NstBoardGxRom.cpp \ source/core/board/NstBoardBmcMarioParty7in1.cpp \ source/core/board/NstBoardMmc1.cpp \ source/core/board/NstBoardNanjing.cpp \ source/core/board/NstBoardBmcFamily4646B.cpp \ source/core/board/NstBoardBtlT230.cpp \ source/core/board/NstBoardBmc1200in1.hpp \ source/core/board/NstBoardMagicKidGoogoo.cpp \ source/core/board/NstBoardMagicSeries.cpp \ source/core/board/NstBoardSunsoft2.hpp \ source/core/board/NstBoardBmcGoldenCard6in1.hpp \ source/core/board/NstBoardAveNina.cpp \ source/core/board/NstBoardMmc6.cpp \ source/core/board/NstBoardTaitoTc0190fmc.hpp \ source/core/board/NstBoardBmc35in1.hpp \ source/core/board/NstBoardBmc9999999in1.hpp \ source/core/board/NstBoardKasing.cpp \ source/core/board/NstBoardCxRom.hpp \ source/core/board/NstBoardUnlCc21.hpp \ source/core/board/NstBoardJalecoJf19.cpp \ source/core/board/NstBoardSachenS8259.hpp \ source/core/board/NstBoardFukutake.hpp \ source/core/board/NstBoardBandai.hpp \ source/core/board/NstBoardZz.cpp \ source/core/board/NstBoardDreamtech.hpp \ source/core/board/NstBoardBmc72in1.hpp \ source/core/board/NstBoardHenggedianzi.cpp \ source/core/board/NstBoardOpenCorp.hpp \ source/core/board/NstBoardBmcPowerjoy84in1.hpp \ source/core/board/NstBoardCneShlz.cpp \ source/core/board/NstBoardKaiser.hpp \ source/core/board/NstBoardKonamiVrc7.cpp \ source/core/board/NstBoardBmc22Games.cpp \ source/core/board/NstBoardBmcCtc65.hpp \ source/core/board/NstBoard.hpp \ source/core/board/NstBoardBmcGamestarB.cpp \ source/core/board/NstBoardWaixingSecurity.hpp \ source/core/board/NstBoardIrem.hpp \ source/core/board/NstBoardUnlN625092.cpp \ source/core/board/NstBoardBtlSmb2b.hpp \ source/core/board/NstBoardBmc150in1.cpp \ source/core/board/NstBoardBmcSuperHiK4in1.cpp \ source/core/board/NstBoardBtlShuiGuanPipe.cpp \ source/core/board/NstBoardBtlMarioBaby.hpp \ source/core/board/NstBoardBmc800in1.hpp \ source/core/board/NstBoardCnePsb.cpp \ source/core/board/NstBoardSuperGamePocahontas2.cpp \ source/core/board/NstBoardSunsoft1.hpp \ source/core/board/NstBoardSachenSa0037.cpp \ source/core/board/NstBoardVsSystem.hpp \ source/core/board/NstBoardHes.hpp \ source/core/board/NstBoardWhirlwind.hpp \ source/core/board/NstBoardSunsoftFme7.cpp \ source/core/board/NstBoardSachen74x374.hpp \ source/core/board/NstBoardBmcBallgames11in1.cpp \ source/core/board/NstBoardFukutake.cpp \ source/core/board/NstBoardCaltron.hpp \ source/core/board/NstBoardUnlN625092.hpp \ source/core/board/NstBoardIremH3001.cpp \ source/core/board/NstBoardTaitoTc0190fmcPal16r4.cpp \ source/core/board/NstBoardKayPandaPrince.hpp \ source/core/board/NstBoardTaitoTc0190fmc.cpp \ source/core/board/NstBoardBmcGolden190in1.cpp \ source/core/board/NstBoardQj.cpp \ source/core/board/NstBoardBmcResetBased4in1.hpp \ source/core/board/NstBoardBmcGamestarA.cpp \ source/core/board/NstBoardTaito.hpp \ source/core/board/NstBoardWaixingFfv.hpp \ source/core/board/NstBoardNamcot34xx.hpp \ source/core/board/NstBoardBtlSmb2c.cpp \ source/core/board/NstBoardSachenSa72008.hpp \ source/core/board/NstBoardKasing.hpp \ source/core/board/NstBoardSunsoft2.cpp \ source/core/board/NstBoardWaixingFfv.cpp \ source/core/board/NstBoardBxRom.hpp \ source/core/board/NstBoardBmcFk23c.hpp \ source/core/board/NstBoardBmc15in1.hpp \ source/core/board/NstBoardBtlDragonNinja.cpp \ source/core/board/NstBoardSunsoft.hpp \ source/core/board/NstBoardSunsoft3.cpp \ source/core/board/NstBoardJalecoJf13.hpp \ source/core/board/NstBoardDiscrete.hpp \ source/core/board/NstBoardWaixingSgzlz.hpp \ source/core/board/NstBoardNitra.hpp \ source/core/board/NstBoardZz.hpp \ source/core/board/NstBoardUnlXzy.hpp \ source/core/board/NstBoardRexSoftSl1632.cpp \ source/core/board/NstBoardSachenTca01.cpp \ source/core/board/NstBoardBtlTobidaseDaisakusen.cpp \ source/core/board/NstBoardQj.hpp \ source/core/board/NstBoardBandaiOekaKids.hpp \ source/core/board/NstBoardAxRom.hpp \ source/core/board/NstBoardBandaiKaraokeStudio.hpp \ source/core/board/NstBoardMxRom.hpp \ source/core/board/NstBoardTengen.hpp \ source/core/board/NstBoardSomeriTeamSl12.cpp \ source/core/board/NstBoardJalecoJf11.hpp \ source/core/board/NstBoardBmc31in1.cpp \ source/core/board/NstBoardUnlKingOfFighters96.cpp \ source/core/board/NstBoardTxcMxmdhtwo.hpp \ source/core/board/NstBoardAgci.cpp \ source/core/board/NstBoardBmcSuper40in1.hpp \ source/core/board/NstBoardBmcVt5201.cpp \ source/core/board/NstBoardNihon.hpp \ source/core/board/NstBoardMagicSeries.hpp \ source/core/board/NstBoardPxRom.hpp \ source/core/board/NstBoardUnlTf1201.hpp \ source/core/board/NstBoardCneDecathlon.cpp \ source/core/board/NstBoardBandaiAerobicsStudio.hpp \ source/core/board/NstBoardBmcSuperHiK4in1.hpp \ source/core/board/NstBoardRexSoftDb5z.cpp \ source/core/board/NstBoardWhirlwind.cpp \ source/core/board/NstBoardBmcSuper22Games.cpp \ source/core/board/NstBoardBandaiLz93d50ex.cpp \ source/core/board/NstBoardSachenSa72007.cpp \ source/core/board/NstBoardFujiya.hpp \ source/core/board/NstBoardBmc1200in1.cpp \ source/core/board/NstBoardMmc5.hpp \ source/core/board/NstBoardSomeriTeam.hpp \ source/core/board/NstBoardBmc76in1.hpp \ source/core/board/NstBoardBmc20in1.hpp \ source/core/board/NstBoardSachenSa72007.hpp \ source/core/board/NstBoardBmc8157.hpp \ source/core/board/NstBoardAgci.hpp \ source/core/board/NstBoardNamcot163.cpp \ source/core/board/NstBoardWaixing.hpp \ source/core/board/NstBoardBmcSuperBig7in1.hpp \ source/core/board/NstBoardCony.cpp \ source/core/board/NstBoardNihon.cpp \ source/core/board/NstBoardSachenTcu.hpp \ source/core/board/NstBoardInlNsf.cpp \ source/core/board/NstBoardInlNsf.hpp \ source/core/board/NstBoardAction53.cpp \ source/core/board/NstBoardAction53.hpp \ source/core/board/NstBoardWaixingFs304.cpp \ source/core/board/NstBoardWaixingFs304.hpp \ source/core/NstPins.hpp \ source/core/NstNsf.hpp \ source/core/NstTrackerRewinder.hpp \ source/core/NstFds.cpp \ source/core/NstVector.hpp \ source/core/NstPatcher.hpp \ source/core/NstVideoFilterScaleX.cpp \ source/core/NstCartridgeInes.hpp \ source/core/NstNsf.cpp \ source/core/NstSoundPcm.cpp \ source/core/NstSoundPcm.hpp \ source/core/NstVideoFilterNtsc.hpp \ source/core/NstCartridgeRomset.cpp \ source/core/NstVideoFilterNtsc.cpp \ source/core/NstChecksum.cpp \ source/core/NstVideoFilterNtscCfg.cpp \ source/core/NstZlib.hpp \ source/core/NstCrc32.cpp \ source/core/NstHook.hpp \ source/core/NstSoundPlayer.hpp \ source/core/NstBarcodeReader.hpp \ source/core/NstCpu.hpp \ source/core/NstCrc32.hpp \ source/nes_ntsc/nes_ntsc_impl.h \ source/nes_ntsc/nes_ntsc_config.h \ source/nes_ntsc/nes_ntsc.h \ source/nes_ntsc/demo_impl.h nestopia_SOURCES += \ source/fltkui/nstcommon.cpp \ source/fltkui/nstcommon.h \ source/fltkui/cheats.cpp \ source/fltkui/cheats.h \ source/fltkui/homebrew.cpp \ source/fltkui/homebrew.h \ source/fltkui/cli.cpp \ source/fltkui/cli.h \ source/fltkui/config.cpp \ source/fltkui/config.h \ source/fltkui/video.cpp \ source/fltkui/video.h \ source/fltkui/input.cpp \ source/fltkui/input.h \ source/fltkui/samples.cpp \ source/fltkui/samples.h \ source/fltkui/font.h \ source/fltkui/ini.cpp \ source/fltkui/ini.h \ source/fltkui/png.cpp \ source/fltkui/png.h \ source/fltkui/audio.cpp \ source/fltkui/audio.h nestopia_SOURCES += \ source/fltkui/fltkui_config.h \ source/fltkui/fltkui_archive.h \ source/fltkui/fltkui_archive.cpp \ source/fltkui/fltkui_cheats.h \ source/fltkui/fltkui_cheats.cpp \ source/fltkui/fltkui.cpp \ source/fltkui/fltkui.h \ source/fltkui/fltkui_config.cpp # install full HTML suite if ENABLE_FULL_HTML dist_html_DATA += \ doc/index.html \ doc/index-deprecated-list.html \ doc/index-allclasses-frame.html \ doc/index-overview-tree.html \ doc/index-all.html \ doc/index-overview-summary.html \ doc/index-overview-frame.html htmldetailscoredir = $(htmldir)/details/core dist_htmldetailscore_DATA = \ doc/details/core/Nes..Core..CpuModel.html \ doc/details/core/Nes..Core..System.html \ doc/details/core/Nes..uchar.html \ doc/details/core/Nes..schar.html \ doc/details/core/Nes.html \ doc/details/core/Nes..Core.html \ doc/details/core/Nes..Core..ImplicitBool..Type.html \ doc/details/core/Nes..dword.html \ doc/details/core/Nes..ulong.html \ doc/details/core/project-frame.html \ doc/details/core/Nes..Core..ImplicitBool.html \ doc/details/core/Nes..Core..PpuModel.html \ doc/details/core/Nes..Result.html \ doc/details/core/Nes..Core..FavoredSystem.html \ doc/details/core/project-summary.html \ doc/details/core/Nes..ushort.html \ doc/details/core/Nes..byte.html \ doc/details/core/Nes..uint.html \ doc/details/core/Nes..Core..Region.html \ doc/details/core/Nes..word.html \ doc/details/core/project-tree.html htmldetailsapidir = $(htmldir)/details/api dist_htmldetailsapi_DATA = \ doc/details/api/Nes..Api..TapeRecorder.html \ doc/details/api/Nes..Api..Cartridge..Profile..Property.html \ doc/details/api/Nes..Core..Sound..Output..Unlocker.html \ doc/details/api/Nes..Api..DipSwitches.html \ doc/details/api/Nes..Api..Input.html \ doc/details/api/Nes..Api..BarcodeReader.html \ doc/details/api/Nes..Api..Cartridge..Profile..Board..Wram.html \ doc/details/api/Nes..Api..Fds..DiskData..File.html \ doc/details/api/Nes..Api..Video..Output.html \ doc/details/api/Nes..Api..User..LogCallback.html \ doc/details/api/Nes..Core..Input..Controllers..Pachinko.html \ doc/details/api/Nes..Core..Input..Controllers..OekaKidsTablet.html \ doc/details/api/Nes..Api..Cartridge..NesHeader..Mirroring.html \ doc/details/api/Nes..Core..Video..Output..UnlockCallback.html \ doc/details/api/Nes..Api..Cartridge..ChooseProfileCaller.html \ doc/details/api/Nes..Api..Sound..Speaker.html \ doc/details/api/Nes..Api..Cartridge..Profile..System..Ppu.html \ doc/details/api/Nes..Core..Input..Controllers..Mouse..PollCallback.html \ doc/details/api/Nes..Core..Input..Controllers..PowerGlove.html \ doc/details/api/Nes..Api..Cartridge..Profile..System..Cpu.html \ doc/details/api/Nes..Core..Input..Controllers..PollCaller1.html \ doc/details/api/Nes..Core..Input..Controllers..Pachinko..PollCallback.html \ doc/details/api/Nes..Api..Sound..Channel.html \ doc/details/api/Nes..Core..Video..Output..Unlocker.html \ doc/details/api/Nes..Core..Input..Controllers..Zapper..PollCallback.html \ doc/details/api/Nes..Core..Input.html \ doc/details/api/Nes..Core..Sound.html \ doc/details/api/Nes..Api..Fds..Event.html \ doc/details/api/Nes..Api..Video..RenderState..Filter.html \ doc/details/api/Nes..Core..Input..Controllers..KaraokeStudio..PollCallback.html \ doc/details/api/Nes..Api..Cartridge..Profile..System.html \ doc/details/api/Nes..Core..Input..Controllers..Mouse.html \ doc/details/api/Nes..Api..Rewinder.html \ doc/details/api/Nes..Core..Sound..Output..Locker.html \ doc/details/api/Nes..Core..Sound..Output..LockCallback.html \ doc/details/api/Nes..Api..Rewinder..State.html \ doc/details/api/Nes..Api..User..Question.html \ doc/details/api/Nes..Api..Video..Palette..Mode.html \ doc/details/api/Nes.html \ doc/details/api/Nes..Api..Video..Palette.html \ doc/details/api/Nes..Core..Input..Controllers..OekaKidsTablet..PollCallback.html \ doc/details/api/Nes..Core.html \ doc/details/api/Nes..Api..Emulator..Core.html \ doc/details/api/Nes..Core..Input..Controllers..Zapper.html \ doc/details/api/Nes..Api..Input..ControllerCallback.html \ doc/details/api/Nes..Api..Rewinder..Direction.html \ doc/details/api/Nes..Core..Video..Output..LockCallback.html \ doc/details/api/Nes..Api..TapeRecorder..Event.html \ doc/details/api/Nes..Api..Machine.html \ doc/details/api/Nes..Api..User..File..Patch.html \ doc/details/api/Nes..Api..User..FileIoCallback.html \ doc/details/api/Nes..Api..Cheats..Code.html \ doc/details/api/Nes..Api..Video..Decoder.html \ doc/details/api/Nes..Api..Video..DecoderPreset.html \ doc/details/api/Nes..Api..Cartridge..Profile..Properties.html \ doc/details/api/Nes..Api..Machine..AskProfile.html \ doc/details/api/Nes..Api..User..File.html \ doc/details/api/Nes..Api..User..EventCaller.html \ doc/details/api/Nes..Api..Emulator.html \ doc/details/api/Nes..Api..Fds..DiskData..File..Type.html \ doc/details/api/Nes..Api..Cartridge..Profile..Board..Roms.html \ doc/details/api/Nes..Api..Rewinder..StateCallback.html \ doc/details/api/Nes..Api..Cartridge..Database..Entry.html \ doc/details/api/Nes..Core..Input..Controllers..Paddle.html \ doc/details/api/Nes..Api..Cartridge..Profile..Board.html \ doc/details/api/Nes..Core..Input..Controllers.html \ doc/details/api/Nes..Api..Fds..Motor.html \ doc/details/api/Nes..Api..Fds..DiskData..Files.html \ doc/details/api/Nes..Api..Cartridge..Profile..Dump..State.html \ doc/details/api/Nes..Core..Input..Controllers..KonamiHyperShot.html \ doc/details/api/Nes..Core..Input..Controllers..VsSystem..PollCallback.html \ doc/details/api/Nes..Api..Movie.html \ doc/details/api/Nes..Api..Machine..Compression.html \ doc/details/api/Nes..Api..Fds..DiskCaller.html \ doc/details/api/Nes..Core..Input..Controllers..DoremikkoKeyboard.html \ doc/details/api/Nes..Core..Input..Controllers..Paddle..PollCallback.html \ doc/details/api/Nes..Core..Input..Controllers..PollCaller3.html \ doc/details/api/Nes..Api..Sound..Output.html \ doc/details/api/Nes..Api..Input..Type.html \ doc/details/api/Nes..Api..Video..Palette..Colors.html \ doc/details/api/Nes..Core..Input..Controllers..Mahjong.html \ doc/details/api/Nes..Core..Video.html \ doc/details/api/Nes..Api..Video..RenderState..Bits..Mask.html \ doc/details/api/Nes..Core..Input..Controllers..PowerGlove..Gesture.html \ doc/details/api/Nes..Api..Cartridge..NesHeader..System.html \ doc/details/api/Nes..Api..User.html \ doc/details/api/Nes..Api..Input..ControllerCaller.html \ doc/details/api/Nes..Api..Video..RenderState.html \ doc/details/api/Nes..Api..Video.html \ doc/details/api/Nes..Core..Input..Controllers..Mahjong..PollCallback.html \ doc/details/api/Nes..Api..Cartridge..Profile.html \ doc/details/api/Nes..Core..Input..Controllers..HoriTrack.html \ doc/details/api/Nes..Core..Input..Controllers..TopRider..PollCallback.html \ doc/details/api/Nes..Core..Video..Output.html \ doc/details/api/Nes..Core..Input..Controllers..PowerGlove..PollCallback.html \ doc/details/api/Nes..Api..Cartridge..NesHeader..Region.html \ doc/details/api/Nes..Core..Input..Controllers..PartyTap.html \ doc/details/api/Nes..Api..User..EventCallback.html \ doc/details/api/Nes..Api..User..Event.html \ doc/details/api/Nes..Api..Rewinder..StateCaller.html \ doc/details/api/Nes..Core..Input..Controllers..Pad..PollCallback.html \ doc/details/api/Nes..Api..Cartridge..Profile..Board..Sample.html \ doc/details/api/Nes..Core..Input..Controllers..CrazyClimber..PollCallback.html \ doc/details/api/Nes..Api..Nsf..Event.html \ doc/details/api/Nes..Core..Input..Controllers..BandaiHyperShot..PollCallback.html \ doc/details/api/Nes..Api..Cartridge..Profile..Board..Rams.html \ doc/details/api/Nes..Api..User..QuestionCaller.html \ doc/details/api/Nes..Api..Cartridge..Profile..Dump.html \ doc/details/api/project-frame.html \ doc/details/api/Nes..Api..Cartridge..Profile..Board..Vram.html \ doc/details/api/Nes..Api..Cheats.html \ doc/details/api/Nes..Core..Input..Controllers..BandaiHyperShot.html \ doc/details/api/Nes..Core..Input..Controllers..PartyTap..PollCallback.html \ doc/details/api/Nes..Api..Machine..Event.html \ doc/details/api/Nes..Core..Input..Controllers..TopRider.html \ doc/details/api/Nes..Core..Input..Controllers..KonamiHyperShot..PollCallback.html \ doc/details/api/Nes..Core..Input..Controllers..PokkunMoguraa..PollCallback.html \ doc/details/api/Nes..Core..Sound..Output..UnlockCallback.html \ doc/details/api/Nes..Core..Input..Controllers..FamilyKeyboard.html \ doc/details/api/Nes..Api..Cartridge.html \ doc/details/api/Nes..Api..Fds..DiskCallback.html \ doc/details/api/Nes..Api..Input..AdapterCaller.html \ doc/details/api/Nes..Api..User..Answer.html \ doc/details/api/Nes..Api..Video..Palette..CustomType.html \ doc/details/api/Nes..Api..Cartridge..Profile..Board..Chips.html \ doc/details/api/Nes..Api..Fds.html \ doc/details/api/Nes..Api..Fds..DiskData.html \ doc/details/api/Nes..Api..Machine..FavoredSystem.html \ doc/details/api/Nes..Core..Input..Controllers..FamilyTrainer..PollCallback.html \ doc/details/api/Nes..Core..Input..Controllers..DoremikkoKeyboard..PollCallback.html \ doc/details/api/Nes..Api..Machine..EventCallback.html \ doc/details/api/Nes..Api..TapeRecorder..EventCallback.html \ doc/details/api/project-summary.html \ doc/details/api/Nes..Core..Input..Controllers..PowerPad.html \ doc/details/api/Nes..Api..Cartridge..Profile..Board..Rom.html \ doc/details/api/Nes..Api..Movie..EventCaller.html \ doc/details/api/Nes..Core..Input..Controllers..PowerPad..PollCallback.html \ doc/details/api/Nes..Api..Cheats..RAM_SIZE.html \ doc/details/api/Nes..Api..Movie..EventCallback.html \ doc/details/api/Nes..Core..Input..Controllers..Pad.html \ doc/details/api/Nes..Api..Nsf..EventCallback.html \ doc/details/api/Nes..Api..Machine..Mode.html \ doc/details/api/Nes..Api..Fds..DiskData..Data.html \ doc/details/api/Nes..Api..Cartridge..Profile..System..Type.html \ doc/details/api/Nes..Api..Cartridge..Profile..Board..Ram.html \ doc/details/api/Nes..Api..Sound.html \ doc/details/api/Nes..Api..Input..Controllers.html \ doc/details/api/Nes..Api..Cartridge..Profile..Board..Pins.html \ doc/details/api/Nes..Api..Cartridge..Profile..Board..Samples.html \ doc/details/api/Nes..Api..Movie..Event.html \ doc/details/api/Nes..Api..Cartridge..Profile..Board..Pin.html \ doc/details/api/Nes..Core..Input..Controllers..ExcitingBoxing..PollCallback.html \ doc/details/api/Nes..Api..User..LogCaller.html \ doc/details/api/Nes..Api..Machine..Patch.html \ doc/details/api/Nes..Core..Input..Controllers..ExcitingBoxing.html \ doc/details/api/Nes..Core..Input..Controllers..VsSystem.html \ doc/details/api/Nes..Core..Input..Controllers..PokkunMoguraa.html \ doc/details/api/Nes..Api..Machine..EventCaller.html \ doc/details/api/Nes..Api..User..QuestionCallback.html \ doc/details/api/Nes..Core..Input..Controllers..HoriTrack..PollCallback.html \ doc/details/api/Nes..Core..Sound..Output.html \ doc/details/api/Nes..Core..Input..Controllers..FamilyTrainer.html \ doc/details/api/Nes..Api..TapeRecorder..EventCaller.html \ doc/details/api/Nes..Core..Video..Output..Locker.html \ doc/details/api/Nes..Api..Cartridge..NesHeader..Ppu.html \ doc/details/api/Nes..Api..Fds..DriveCallback.html \ doc/details/api/Nes..Api..Cartridge..Profile..Game.html \ doc/details/api/Nes..Api..Cartridge..Profile..Board..Prg.html \ doc/details/api/Nes..Core..Input..Controllers..KaraokeStudio.html \ doc/details/api/Nes..Api..User..File..Action.html \ doc/details/api/Nes..Api..Fds..DriveCaller.html \ doc/details/api/Nes..Api..Cartridge..Profile..Board..Chr.html \ doc/details/api/Nes..Api..Video..RenderState..Bits.html \ doc/details/api/Nes..Core..Input..Controllers..SuborKeyboard.html \ doc/details/api/Nes..Api..Nsf..EventCaller.html \ doc/details/api/Nes..Api..Cartridge..NesHeader.html \ doc/details/api/Nes..Core..Input..Controllers..SuborKeyboard..PollCallback.html \ doc/details/api/Nes..Api..Cartridge..Database.html \ doc/details/api/Nes..Api..User..FileIoCaller.html \ doc/details/api/Nes..Api..Nsf.html \ doc/details/api/Nes..Api..Video..RenderState..Scale.html \ doc/details/api/Nes..Core..Input..Controllers..CrazyClimber.html \ doc/details/api/Nes..Core..Input..Controllers..PollCaller2.html \ doc/details/api/Nes..Api..Input..AdapterCallback.html \ doc/details/api/Nes..Api.html \ doc/details/api/Nes..Api..Nsf..TuneMode.html \ doc/details/api/Nes..Api..Cartridge..Profile..Hash.html \ doc/details/api/Nes..Api..Input..Adapter.html \ doc/details/api/project-tree.html \ doc/details/api/Nes..Api..Cartridge..ChooseProfileCallback.html \ doc/details/api/Nes..Api..Cartridge..Profile..Board..Chip.html \ doc/details/api/Nes..Core..Input..Controllers..FamilyKeyboard..PollCallback.html \ doc/details/api/Nes..Api..Movie..How.html endif nestopia-1.51.1/NstDatabase.xml000066400000000000000000036761111411157722000163530ustar00rootroot00000000000000 nestopia-1.51.1/README.md000066400000000000000000000032331411157722000147010ustar00rootroot00000000000000## About This project is a fork of the original Nestopia source code, plus the Linux port. The purpose of the project is to make sure people who want a standalone GUI for the Nestopia emulator have this option available. Current Project Goals: * Maintain a functional GUI for the Nestopia emulator on Linux, BSD, and Windows platforms Contributing/Issues: * Contributions will be reviewed for anything related to the standalone GUI builds * Issues related to core emulation will be closed. This project no longer maintains the core emulator. * When not using a tagged release, please understand that the code is volatile and nothing is set in stone. The following platforms are supported: * Linux, BSD, Windows Libretro notes: The libretro port is no longer maintained in this repo, and is now maintained by the libretro community. For libretro-specific issues, please use the libretro repository: https://github.com/libretro/nestopia This project depends on the following libraries: FLTK 1.3, SDL2, libarchive, zlib ## Installing Dependencies Install dependencies required for building on Debian-based Linux distributions: ``` apt-get install build-essential autoconf autoconf-archive automake autotools-dev libfltk1.3-dev libsdl2-dev libarchive-dev zlib1g-dev ``` ## FLTK Build To build using Autotools (optional arguments in square brackets): ``` autoreconf -vif ./configure [--enable-doc] make ``` Optionally: ``` make install ``` ## Win32 Build To build the win32 solution with Visual Studio 2010: 1. Ensure you have the DirectX 9 SDK 2. Manually zip NstDatabase.xml to the destination source/core/database/NstDatabase.zip 3. Open projects/nestopia.sln 4. Build in release mode nestopia-1.51.1/configure.ac000066400000000000000000000056741411157722000157230ustar00rootroot00000000000000dnl Initialise Autoconf AC_PREREQ([2.69]) AC_INIT( [nestopia], [1.51.1]) AC_CONFIG_SRCDIR([source]) AC_LANG([C++]) dnl ======================================================================== dnl Check whether we want to set defaults for CXXFLAGS, CPPFLAGS and LDFLAGS dnl ======================================================================== AC_MSG_CHECKING([whether configure should try to set CXXFLAGS/CPPFLAGS/LDFLAGS]) AS_IF([test "x${CXXFLAGS+set}" = "xset" || test "x${CPPFLAGS+set}" = "xset" || test "x${LDFLAGS+set}" = "xset"], [enable_flags_setting=no], [enable_flags_setting=yes] ) AC_MSG_RESULT([${enable_flags_setting}]) AX_CHECK_ENABLE_DEBUG AS_IF([test "x${enable_debug}" = "xno"], [ cxxflags_test="-O3" cppflags_test="" AC_CANONICAL_HOST AS_CASE([${host_os}], [darwin*], [ldflags_test="-Wl,-dead_strip_dylibs"], [linux*], [ldflags_test="-Wl,-O1 -Wl,--as-needed"] ) ] ) dnl ======================================= dnl Check for standard headers and programs dnl ======================================= AX_COMPILER_VENDOR AX_COMPILER_VERSION AC_PROG_SED AC_PROG_CXX dnl ================================== dnl Set CXXFLAGS, CPPFLAGS and LDFLAGS dnl ================================== AS_IF([test "x${enable_flags_setting}" = "xyes" && test "x${enable_debug}" = "xno"], [ AX_APPEND_COMPILE_FLAGS([${cxxflags_test} -Wno-narrowing], [CXXFLAGS]) CXXFLAGS=$( echo ${CXXFLAGS} | $SED -e 's/^ *//' -e 's/ *$//' ) AX_APPEND_COMPILE_FLAGS([${cppflags_test}], [CPPFLAGS]) CPPFLAGS=$( echo ${CPPFLAGS} | $SED -e 's/^ *//' -e 's/ *$//' ) AX_APPEND_LINK_FLAGS([${ldflags_test}], [LDFLAGS]) LDFLAGS=$( echo ${LDFLAGS} | $SED -e 's/^ *//' -e 's/ *$//' ) ] ) dnl ====================== dnl Check for dependencies dnl ====================== dnl zlib PKG_CHECK_MODULES([ZLIB], [zlib]) dnl libarchive PKG_CHECK_MODULES([LIBARCHIVE], [libarchive]) dnl SDL2 PKG_CHECK_MODULES([SDL2], [sdl2]) AC_CHECK_PROG(FLTKCONFIG,fltk-config,[fltk-config],[no]) test "$FLTKCONFIG" == "no" && AC_MSG_ERROR([Cannot find the fltk-config executable. Is FLTK installed?]) AC_SUBST(FLTK_CFLAGS,"$(fltk-config --use-gl --use-images --cxxflags)") AC_SUBST(FLTK_LIBS,"-lGL $(fltk-config --use-gl --use-images --ldflags)") dnl full HTML suite AC_ARG_ENABLE([doc], AS_HELP_STRING([--enable-doc], [Install full HTML documentation])) AM_CONDITIONAL([ENABLE_FULL_HTML], [test "x$enable_doc" = "xyes"]) dnl =================== dnl Initialise Automake dnl =================== AM_INIT_AUTOMAKE([1.15 foreign dist-bzip2 no-dist-gzip subdir-objects silent-rules]) AM_SILENT_RULES([yes]) dnl ======== dnl Finalise dnl ======== AC_CONFIG_FILES([Makefile]) AC_OUTPUT dnl ============================ dnl Report configuration to user dnl ============================ AC_MSG_RESULT([ ${PACKAGE_NAME} ${VERSION} Using ${ax_cv_cxx_compiler_vendor}, ${ax_cv_cxx_compiler_version} CXX: ${CXX} CXXFLAGS: ${CXXFLAGS} CPPFLAGS: ${CPPFLAGS} LDFLAGS: ${LDFLAGS} ]) nestopia-1.51.1/doc/000077500000000000000000000000001411157722000141665ustar00rootroot00000000000000nestopia-1.51.1/doc/details/000077500000000000000000000000001411157722000156135ustar00rootroot00000000000000nestopia-1.51.1/doc/details/api/000077500000000000000000000000001411157722000163645ustar00rootroot00000000000000nestopia-1.51.1/doc/details/api/Nes..Api..BarcodeReader.html000066400000000000000000000216071411157722000233320ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::BarcodeReader
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Class Nes::Api::BarcodeReader

Base
   |
   +--Nes::Api::BarcodeReader


class Nes::Api::BarcodeReader
extends Base

Bar code reader interface.


Constructor Summary
BarcodeReader( T& instance )
          Interface constructor.
 
Method Summary
 bool CanTransfer() const
          Checks if the reader is ready to scan.
 bool IsConnected() const
          Checks if a reader is connected.
 bool IsDigitsSupported( uint length ) const
          Checks if the number of bar code digits is supported.
 uint Randomize( char(& string )[ MAX_DIGITS+ 1] ) const
          Generates a randomized bar code.
 Result Transfer( const char* string, uint length )
          Transfers a bar code to the reader.
 

Constructor Detail

BarcodeReader

public BarcodeReader( T& instance );
Interface constructor.
Parameters:
instance - emulator instance


Method Detail

CanTransfer

public bool CanTransfer() const throw();
Checks if the reader is ready to scan.
Returns:
true if ready

IsConnected

public bool IsConnected() const;
Checks if a reader is connected.
Returns:
true if connected

IsDigitsSupported

public bool IsDigitsSupported( uint length ) const throw();
Checks if the number of bar code digits is supported.
Parameters:
length - number of digits in the range 8 to 13
Returns:
true if supported

Randomize

public uint Randomize( char(& string )[ MAX_DIGITS+ 1] ) const throw();
Generates a randomized bar code.
Parameters:
string - string to be filled
Returns:
length of randomized bar code, 0 if reader is disconnected

Transfer

public Result Transfer( const char* string, uint length ) throw();
Transfers a bar code to the reader.
Parameters:
string - bar code string
length - string length
Returns:
result code

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..ChooseProfileCallback.html000066400000000000000000000106711411157722000270060ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::ChooseProfileCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Cartridge::ChooseProfileCallback

Cartridge profile chooser callback prototype.

Parameters:
userData - optional user data
profiles - pointer to an array of profiles
profileNames - pointer to a wide-string array of profile names
numProfiles - number of profiles to choose between
Returns:
array index of chosen profile



Details

ChooseProfileCallback

public typedef uint( NST_CALLBACK* ChooseProfileCallback )( UserData userData, const Profile* profiles, const std::wstring* profileNames, uint numProfiles );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..ChooseProfileCaller.html000066400000000000000000000117261411157722000265160ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::ChooseProfileCaller
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Cartridge::ChooseProfileCaller

Core::UserCallback
   |
   +--Nes::Api::Cartridge::ChooseProfileCaller


struct Nes::Api::Cartridge::ChooseProfileCaller
extends Core::UserCallback

Cartridge profile chooser callback invoker. Used internally by the core.


Method Summary
 uint operator()( const Profile* profiles, const std::wstring* names, uint count ) const
          
 

Method Detail

operator()

public uint operator()( const Profile* profiles, const std::wstring* names, uint count ) const;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Database..Entry.html000066400000000000000000000344301411157722000255110ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Database::Entry
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Class Nes::Api::Cartridge::Database::Entry

Core::ImplicitBool
   |
   +--Nes::Api::Cartridge::Database::Entry


class Nes::Api::Cartridge::Database::Entry
extends Core::ImplicitBool

Database entry.


Constructor Summary
  Entry()
          Default constructor.
private  Entry( const void* r )
          
 
Method Summary
 dword GetChrRom() const
          Returns total size of CHR-ROM.
 Profile::Dump::State GetDumpState() const
          Returns the dump state.
 const Profile::Hash* GetHash() const
          Returns hash code of ROM chips combined.
 uint GetMapper() const
          Returns mapper ID.
 dword GetPrgRom() const
          Returns total size of PRG-ROM.
 Result GetProfile( Profile& profile ) const
          Returns the profile of this entry.
 const wchar_t* GetRegion() const
          Returns the target region.
 Profile::System::Type GetSystem() const
          Returns the target system.
 const wchar_t* GetTitle() const
          Returns the game title.
 uint GetVram() const
          Returns total size of V-RAM.
 uint GetWram() const
          Returns total size of W-RAM.
 bool HasBattery() const
          Returns battery status.
 bool IsMultiRegion() const
          Checks if the game targets multiple regions.
 bool operator!() const
          Checks if entry is invalid.
 

Constructor Detail

Entry

public Entry();
Default constructor.

Entry

private Entry( const void* r );


Method Detail

GetChrRom

public dword GetChrRom() const throw();
Returns total size of CHR-ROM.
Returns:
size or 0 on invalid entry

GetDumpState

public Profile::Dump::State GetDumpState() const throw();
Returns the dump state.
Returns:
dump state

GetHash

public const Profile::Hash* GetHash() const throw();
Returns hash code of ROM chips combined.
Returns:
hash code or NULL on invalid entry

GetMapper

public uint GetMapper() const throw();
Returns mapper ID.
Returns:
mapper ID or 0 on invalid entry

GetPrgRom

public dword GetPrgRom() const throw();
Returns total size of PRG-ROM.
Returns:
size or 0 on invalid entry

GetProfile

public Result GetProfile( Profile& profile ) const throw();
Returns the profile of this entry.
Parameters:
profile - object to be filled
Returns:
result code

GetRegion

public const wchar_t* GetRegion() const throw();
Returns the target region.
Returns:
target region or empty string on invalid entry

GetSystem

public Profile::System::Type GetSystem() const throw();
Returns the target system.
Returns:
target system

GetTitle

public const wchar_t* GetTitle() const throw();
Returns the game title.
Returns:
game title or empty string on invalid entry

GetVram

public uint GetVram() const throw();
Returns total size of V-RAM.
Returns:
size or 0 on invalid entry

GetWram

public uint GetWram() const throw();
Returns total size of W-RAM.
Returns:
size or 0 on invalid entry

HasBattery

public bool HasBattery() const throw();
Returns battery status.
Returns:
true if a battery is present

IsMultiRegion

public bool IsMultiRegion() const throw();
Checks if the game targets multiple regions.
Returns:
true if targeting multiple regions

operator!

public bool operator!() const;
Checks if entry is invalid.
Returns:
true if invalid

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Database.html000066400000000000000000000304751411157722000243400ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Database
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Class Nes::Api::Cartridge::Database


class Nes::Api::Cartridge::Database

Database interface


Inner Classes, Typedefs, and Enums
class Nes::Api::Cartridge::Database::Entry
          Database entry.
 
Constructor Summary
Database( Core::Machine& instance )
          Interface constructor.
 
Method Summary
 Result Enable( bool state = true )
          Enables image corrections.
 Nes::Api::Cartridge::Database::Entry FindEntry( const void* mem, ulong size, Machine::FavoredSystem system ) const
          Attempts to locate and return an entry from one of the databases.
 Nes::Api::Cartridge::Database::Entry FindEntry( const Profile::Hash& hash, Machine::FavoredSystem system ) const
          Attempts to locate and return an entry from one of the databases.
 bool IsEnabled() const
          Checks if image corrections are enabled.
 bool IsLoaded() const
          Checks if any database has been loaded into the system.
 Result Load( std::istream& streamInternal, std::istream& streamExternal )
          Resets and loads internal and external XML databases.
 Result Load( std::istream& stream )
          Resets and loads internal XML database.
 void Unload()
          Removes all databases from the system.
 

Constructor Detail

Database

public Database( Core::Machine& instance );
Interface constructor.
Parameters:
instance - emulator instance


Method Detail

Enable

public Result Enable( bool state = true ) throw();
Enables image corrections.
Parameters:
state - true to enable, default is true
Returns:
result code

FindEntry

public Nes::Api::Cartridge::Database::Entry FindEntry( const void* mem, ulong size, Machine::FavoredSystem system ) const throw();
Attempts to locate and return an entry from one of the databases.
Parameters:
mem - pointer to memory of combined ROMs
size - size of memory
system - preferred system in case of multiple profiles
Returns:
entry found

FindEntry

public Nes::Api::Cartridge::Database::Entry FindEntry( const Profile::Hash& hash, Machine::FavoredSystem system ) const throw();
Attempts to locate and return an entry from one of the databases.
Parameters:
hash - hash code of combined ROMs
system - preferred system in case of multiple profiles
Returns:
entry found

IsEnabled

public bool IsEnabled() const throw();
Checks if image corrections are enabled.
Returns:
true if enabled

IsLoaded

public bool IsLoaded() const throw();
Checks if any database has been loaded into the system.
Returns:
true if loaded

Load

public Result Load( std::istream& streamInternal, std::istream& streamExternal ) throw();
Resets and loads internal and external XML databases.
Parameters:
streamInternal - input stream to internal XML database
streamExternal - input stream to external XML database
Returns:
result code

Load

public Result Load( std::istream& stream ) throw();
Resets and loads internal XML database.
Parameters:
stream - input stream
Returns:
result code

Unload

public void Unload() throw();
Removes all databases from the system.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..NesHeader..Mirroring.html000066400000000000000000000142231411157722000265100ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::NesHeader::Mirroring
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Cartridge::NesHeader::Mirroring

Name-table mirroring type.


Field Summary
MIRRORING_CONTROLLED
          Software-controlled mirroring.
MIRRORING_FOURSCREEN
          Four-screen mirroring.
MIRRORING_HORIZONTAL
          Horizontal mirroring.
MIRRORING_SINGLESCREEN
          Single-screen mirroring.
MIRRORING_VERTICAL
          Vertical mirroring.
 

Field Detail

MIRRORING_CONTROLLED

public MIRRORING_CONTROLLED
Software-controlled mirroring.

MIRRORING_FOURSCREEN

public MIRRORING_FOURSCREEN
Four-screen mirroring.

MIRRORING_HORIZONTAL

public MIRRORING_HORIZONTAL
Horizontal mirroring.

MIRRORING_SINGLESCREEN

public MIRRORING_SINGLESCREEN
Single-screen mirroring.

MIRRORING_VERTICAL

public MIRRORING_VERTICAL
Vertical mirroring.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..NesHeader..Ppu.html000066400000000000000000000257111411157722000253100ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::NesHeader::Ppu
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Cartridge::NesHeader::Ppu

PPU type.


Field Summary
PPU_RC2C03B = Core : : PPU_RC2C03B
          RC2C03B RGB PPU.
PPU_RC2C03C = Core : : PPU_RC2C03C
          RC2C03C RGB PPU.
PPU_RC2C05_01 = Core : : PPU_RC2C05_01
          RC2C05-01 RGB PPU.
PPU_RC2C05_02 = Core : : PPU_RC2C05_02
          RC2C05-02 RGB PPU.
PPU_RC2C05_03 = Core : : PPU_RC2C05_03
          RC2C05-03 RGB PPU.
PPU_RC2C05_04 = Core : : PPU_RC2C05_04
          RC2C05-04 RGB PPU.
PPU_RC2C05_05 = Core : : PPU_RC2C05_05
          RC2C05-05 RGB PPU.
PPU_RP2C02 = Core : : PPU_RP2C02
          RP2C02 NTSC PPU.
PPU_RP2C03B = Core : : PPU_RP2C03B
          RP2C03B RGB PPU.
PPU_RP2C03G = Core : : PPU_RP2C03G
          RP2C03G RGB PPU.
PPU_RP2C04_0001 = Core : : PPU_RP2C04_0001
          RP2C04-0001 RGB PPU.
PPU_RP2C04_0002 = Core : : PPU_RP2C04_0002
          RP2C04-0002 RGB PPU.
PPU_RP2C04_0003 = Core : : PPU_RP2C04_0003
          RP2C04-0003 RGB PPU.
PPU_RP2C04_0004 = Core : : PPU_RP2C04_0004
          RP2C04-0004 RGB PPU.
PPU_RP2C07 = Core : : PPU_RP2C07
          RP2C07 PAL PPU.
 

Field Detail

PPU_RC2C03B

public PPU_RC2C03B = Core : : PPU_RC2C03B
RC2C03B RGB PPU.

PPU_RC2C03C

public PPU_RC2C03C = Core : : PPU_RC2C03C
RC2C03C RGB PPU.

PPU_RC2C05_01

public PPU_RC2C05_01 = Core : : PPU_RC2C05_01
RC2C05-01 RGB PPU.

PPU_RC2C05_02

public PPU_RC2C05_02 = Core : : PPU_RC2C05_02
RC2C05-02 RGB PPU.

PPU_RC2C05_03

public PPU_RC2C05_03 = Core : : PPU_RC2C05_03
RC2C05-03 RGB PPU.

PPU_RC2C05_04

public PPU_RC2C05_04 = Core : : PPU_RC2C05_04
RC2C05-04 RGB PPU.

PPU_RC2C05_05

public PPU_RC2C05_05 = Core : : PPU_RC2C05_05
RC2C05-05 RGB PPU.

PPU_RP2C02

public PPU_RP2C02 = Core : : PPU_RP2C02
RP2C02 NTSC PPU.

PPU_RP2C03B

public PPU_RP2C03B = Core : : PPU_RP2C03B
RP2C03B RGB PPU.

PPU_RP2C03G

public PPU_RP2C03G = Core : : PPU_RP2C03G
RP2C03G RGB PPU.

PPU_RP2C04_0001

public PPU_RP2C04_0001 = Core : : PPU_RP2C04_0001
RP2C04-0001 RGB PPU.

PPU_RP2C04_0002

public PPU_RP2C04_0002 = Core : : PPU_RP2C04_0002
RP2C04-0002 RGB PPU.

PPU_RP2C04_0003

public PPU_RP2C04_0003 = Core : : PPU_RP2C04_0003
RP2C04-0003 RGB PPU.

PPU_RP2C04_0004

public PPU_RP2C04_0004 = Core : : PPU_RP2C04_0004
RP2C04-0004 RGB PPU.

PPU_RP2C07

public PPU_RP2C07 = Core : : PPU_RP2C07
RP2C07 PAL PPU.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..NesHeader..Region.html000066400000000000000000000120451411157722000257630ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::NesHeader::Region
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Cartridge::NesHeader::Region

Region type.


Field Summary
REGION_BOTH
          Both PAL and NTSC.
REGION_NTSC = 1
          NTSC only.
REGION_PAL
          PAL only.
 

Field Detail

REGION_BOTH

public REGION_BOTH
Both PAL and NTSC.

REGION_NTSC

public REGION_NTSC = 1
NTSC only.

REGION_PAL

public REGION_PAL
PAL only.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..NesHeader..System.html000066400000000000000000000120331411157722000260210ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::NesHeader::System
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Cartridge::NesHeader::System

System type.


Field Summary
SYSTEM_CONSOLE
          Console.
SYSTEM_PC10
          PlayChoice-10
SYSTEM_VS
          Vs System
 

Field Detail

SYSTEM_CONSOLE

public SYSTEM_CONSOLE
Console.

SYSTEM_PC10

public SYSTEM_PC10
PlayChoice-10

SYSTEM_VS

public SYSTEM_VS
Vs System

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..NesHeader.html000066400000000000000000000417771411157722000245010ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::NesHeader
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Cartridge::NesHeader


struct Nes::Api::Cartridge::NesHeader

iNES header format context.


Inner Classes, Typedefs, and Enums
enum Nes::Api::Cartridge::NesHeader::Mirroring
          Name-table mirroring type.
enum Nes::Api::Cartridge::NesHeader::Ppu
          PPU type.
enum Nes::Api::Cartridge::NesHeader::Region
          Region type.
enum Nes::Api::Cartridge::NesHeader::System
          System type.
 
Field Summary
 dword chrNvRam
          Non-volatile CHR-RAM (aka V-RAM) size.
 dword chrRam
          volatile CHR-RAM (aka V-RAM) size.
 dword chrRom
          CHR-ROM size.
 ushort mapper
          Mapper ID.
 Nes::Api::Cartridge::NesHeader::Mirroring mirroring
          Name-table mirroring.
 Nes::Api::Cartridge::NesHeader::Ppu ppu
          PPU.
 dword prgNvRam
          Non-volatile PRG-RAM (aka W-RAM) size.
 dword prgRam
          volatile PRG-RAM (aka W-RAM) size.
 dword prgRom
          PRG-ROM size.
 Nes::Api::Cartridge::NesHeader::Region region
          Region.
 uchar security
          Vs System security bits.
 uchar subMapper
          Sub-mapper ID.
 Nes::Api::Cartridge::NesHeader::System system
          System.
 bool trainer
          Trainer.
 uchar version
          iNES version number.
 
Constructor Summary
NesHeader()
          
 
Method Summary
 void Clear()
          Clears settings.
 Result Export( void* mem, ulong size ) const
          Exports settings to iNES file header in memory.
 Result Import( const void* mem, ulong size )
          Imports settings from iNES file header in memory.
 

Field Detail

chrNvRam

public dword chrNvRam;
Non-volatile CHR-RAM (aka V-RAM) size.

chrRam

public dword chrRam;
volatile CHR-RAM (aka V-RAM) size.

chrRom

public dword chrRom;
CHR-ROM size.

mapper

public ushort mapper;
Mapper ID.

mirroring

public Nes::Api::Cartridge::NesHeader::Mirroring mirroring;
Name-table mirroring.

ppu

public Nes::Api::Cartridge::NesHeader::Ppu ppu;
PPU.

prgNvRam

public dword prgNvRam;
Non-volatile PRG-RAM (aka W-RAM) size.

prgRam

public dword prgRam;
volatile PRG-RAM (aka W-RAM) size.

prgRom

public dword prgRom;
PRG-ROM size.

region

public Nes::Api::Cartridge::NesHeader::Region region;
Region.

security

public uchar security;
Vs System security bits.

subMapper

public uchar subMapper;
Sub-mapper ID.

system

public Nes::Api::Cartridge::NesHeader::System system;
System.

trainer

public bool trainer;
Trainer.

version

public uchar version;
iNES version number.


Constructor Detail

NesHeader

public NesHeader() throw();


Method Detail

Clear

public void Clear() throw();
Clears settings.

Export

public Result Export( void* mem, ulong size ) const throw();
Exports settings to iNES file header in memory.
Parameters:
pointer - to iNES header at least 16 byte in size
size - size of memory
Returns:
result code

Import

public Result Import( const void* mem, ulong size ) throw();
Imports settings from iNES file header in memory.
Parameters:
pointer - to iNES header at least 16 byte in size
size - size of memory
Returns:
result code

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..Board..Chip.html000066400000000000000000000176741411157722000263060ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::Board::Chip
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Cartridge::Profile::Board::Chip


struct Nes::Api::Cartridge::Profile::Board::Chip

Custom chip.


Field Summary
 bool battery
          battery connected to custom chip.
 std::wstring file
          File pointing to custom chip.
 std::wstring package
          Custom chip package type.
 Pins pins
          Custom chip pins.
 Samples samples
          Analogue sound samples for custom chip.
 std::wstring type
          Custom chip type.
 
Constructor Summary
Chip()
          
 

Field Detail

battery

public bool battery;
battery connected to custom chip.

file

public std::wstring file;
File pointing to custom chip.

package

public std::wstring package;
Custom chip package type.

pins

public Pins pins;
Custom chip pins.

samples

public Samples samples;
Analogue sound samples for custom chip.

type

public std::wstring type;
Custom chip type.


Constructor Detail

Chip

public Chip() throw();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..Board..Chips.html000066400000000000000000000076061411157722000264630ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::Board::Chips
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Cartridge::Profile::Board::Chips

Custom chips.




Details

Chips

public typedef std::vector< Chip > Chips;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..Board..Chr.html000066400000000000000000000075501411157722000261270ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::Board::Chr
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Cartridge::Profile::Board::Chr

CHR-ROM chips.




Details

Chr

public typedef Roms Chr;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..Board..Pin.html000066400000000000000000000140051411157722000261320ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::Board::Pin
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Cartridge::Profile::Board::Pin


struct Nes::Api::Cartridge::Profile::Board::Pin

Pin context.


Field Summary
 std::wstring function
          Pin function.
 uint number
          Pin number.
 
Constructor Summary
Pin()
          
 

Field Detail

function

public std::wstring function;
Pin function.

number

public uint number;
Pin number.


Constructor Detail

Pin

public Pin() throw();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..Board..Pins.html000066400000000000000000000075651411157722000263320ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::Board::Pins
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Cartridge::Profile::Board::Pins

Pins.




Details

Pins

public typedef std::vector< Pin > Pins;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..Board..Prg.html000066400000000000000000000075501411157722000261430ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::Board::Prg
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Cartridge::Profile::Board::Prg

PRG-ROM chips.




Details

Prg

public typedef Roms Prg;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..Board..Ram.html000066400000000000000000000174561411157722000261400ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::Board::Ram
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Cartridge::Profile::Board::Ram


struct Nes::Api::Cartridge::Profile::Board::Ram

RAM chip.


Field Summary
 bool battery
          Battery connected to RAM chip.
 std::wstring file
          File pointing to RAM chip.
 dword id
          RAM chip ID.
 std::wstring package
          RAM chip package method.
 Pins pins
          RAM chip pins.
 dword size
          RAM chip size.
 
Constructor Summary
Ram()
          
 

Field Detail

battery

public bool battery;
Battery connected to RAM chip.

file

public std::wstring file;
File pointing to RAM chip.

id

public dword id;
RAM chip ID.

package

public std::wstring package;
RAM chip package method.

pins

public Pins pins;
RAM chip pins.

size

public dword size;
RAM chip size.


Constructor Detail

Ram

public Ram() throw();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..Board..Rams.html000066400000000000000000000075721411157722000263210ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::Board::Rams
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Cartridge::Profile::Board::Rams

RAM chips.




Details

Rams

public typedef std::vector< Ram > Rams;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..Board..Rom.html000066400000000000000000000203111411157722000261360ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::Board::Rom
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Cartridge::Profile::Board::Rom


struct Nes::Api::Cartridge::Profile::Board::Rom

ROM chip.


Field Summary
 std::wstring file
          File pointing to ROM chip.
 Hash hash
          ROM chip checksum.
 dword id
          ROM chip ID.
 std::wstring name
          ROM chip name.
 std::wstring package
          ROM chip package method.
 Pins pins
          ROM chip pins.
 dword size
          ROM chip size.
 
Constructor Summary
Rom()
          
 

Field Detail

file

public std::wstring file;
File pointing to ROM chip.

hash

public Hash hash;
ROM chip checksum.

id

public dword id;
ROM chip ID.

name

public std::wstring name;
ROM chip name.

package

public std::wstring package;
ROM chip package method.

pins

public Pins pins;
ROM chip pins.

size

public dword size;
ROM chip size.


Constructor Detail

Rom

public Rom() throw();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..Board..Roms.html000066400000000000000000000075721411157722000263370ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::Board::Roms
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Cartridge::Profile::Board::Roms

ROM chips.




Details

Roms

public typedef std::vector< Rom > Roms;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..Board..Sample.html000066400000000000000000000140341411157722000266270ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::Board::Sample
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Cartridge::Profile::Board::Sample


struct Nes::Api::Cartridge::Profile::Board::Sample

Analogue sound sample context.


Field Summary
 std::wstring file
          Sound sample file.
 uint id
          Sound sample id.
 
Constructor Summary
Sample()
          
 

Field Detail

file

public std::wstring file;
Sound sample file.

id

public uint id;
Sound sample id.


Constructor Detail

Sample

public Sample() throw();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..Board..Samples.html000066400000000000000000000076421411157722000270210ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::Board::Samples
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Cartridge::Profile::Board::Samples

Analogue sound samples.




Details

Samples

public typedef std::vector< Sample > Samples;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..Board..Vram.html000066400000000000000000000075561411157722000263260ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::Board::Vram
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Cartridge::Profile::Board::Vram

V-RAM chips.




Details

Vram

public typedef Rams Vram;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..Board..Wram.html000066400000000000000000000075561411157722000263270ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::Board::Wram
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Cartridge::Profile::Board::Wram

W-RAM chips.




Details

Wram

public typedef Rams Wram;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..Board.html000066400000000000000000000507011411157722000253320ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::Board
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Class Nes::Api::Cartridge::Profile::Board


class Nes::Api::Cartridge::Profile::Board

Board context.


Inner Classes, Typedefs, and Enums
struct Nes::Api::Cartridge::Profile::Board::Chip
          Custom chip.
typedef Nes::Api::Cartridge::Profile::Board::Chips
          Custom chips.
typedef Nes::Api::Cartridge::Profile::Board::Chr
          CHR-ROM chips.
struct Nes::Api::Cartridge::Profile::Board::Pin
          Pin context.
typedef Nes::Api::Cartridge::Profile::Board::Pins
          Pins.
typedef Nes::Api::Cartridge::Profile::Board::Prg
          PRG-ROM chips.
struct Nes::Api::Cartridge::Profile::Board::Ram
          RAM chip.
typedef Nes::Api::Cartridge::Profile::Board::Rams
          RAM chips.
struct Nes::Api::Cartridge::Profile::Board::Rom
          ROM chip.
typedef Nes::Api::Cartridge::Profile::Board::Roms
          ROM chips.
struct Nes::Api::Cartridge::Profile::Board::Sample
          Analogue sound sample context.
typedef Nes::Api::Cartridge::Profile::Board::Samples
          Analogue sound samples.
typedef Nes::Api::Cartridge::Profile::Board::Vram
          V-RAM chips.
typedef Nes::Api::Cartridge::Profile::Board::Wram
          W-RAM chips.
 
Field Summary
 Nes::Api::Cartridge::Profile::Board::Chips chips
          Custom chips.
 Nes::Api::Cartridge::Profile::Board::Chr chr
          CHR-ROM.
 std::wstring cic
          CIC type.
 uint mapper
          Mapper ID.
 std::wstring pcb
          Board PCB name.
 Nes::Api::Cartridge::Profile::Board::Prg prg
          PRG-ROM.
 uint solderPads
          Solder pads.
 std::wstring type
          Board type.
 Nes::Api::Cartridge::Profile::Board::Vram vram
          V-RAM.
 Nes::Api::Cartridge::Profile::Board::Wram wram
          W-RAM.
 
Constructor Summary
Board()
          
~Board()
          
 
Method Summary
 dword GetChr() const
          Returns total size of CHR-ROM.
 dword GetPrg() const
          Returns total size of PRG-ROM.
 dword GetVram() const
          Returns total size of V-RAM.
 dword GetWram() const
          Returns total size of W-RAM.
 bool HasBattery() const
          Returns battery status.
 bool HasMmcBattery() const
          Returns custom chip battery status.
 bool HasWramBattery() const
          Returns W-RAM battery status.
 

Field Detail

chips

public Nes::Api::Cartridge::Profile::Board::Chips chips;
Custom chips.

chr

public Nes::Api::Cartridge::Profile::Board::Chr chr;
CHR-ROM.

cic

public std::wstring cic;
CIC type.

mapper

public uint mapper;
Mapper ID.

pcb

public std::wstring pcb;
Board PCB name.

prg

public Nes::Api::Cartridge::Profile::Board::Prg prg;
PRG-ROM.

solderPads

public uint solderPads;
Solder pads.

type

public std::wstring type;
Board type.

vram

public Nes::Api::Cartridge::Profile::Board::Vram vram;
V-RAM.

wram

public Nes::Api::Cartridge::Profile::Board::Wram wram;
W-RAM.


Constructor Detail

Board

public Board() throw();

~Board

public ~Board() throw();


Method Detail

GetChr

public dword GetChr() const throw();
Returns total size of CHR-ROM.
Returns:
size

GetPrg

public dword GetPrg() const throw();
Returns total size of PRG-ROM.
Returns:
size

GetVram

public dword GetVram() const throw();
Returns total size of V-RAM.
Returns:
size

GetWram

public dword GetWram() const throw();
Returns total size of W-RAM.
Returns:
size

HasBattery

public bool HasBattery() const throw();
Returns battery status.
Returns:
true if a battery is present

HasMmcBattery

public bool HasMmcBattery() const throw();
Returns custom chip battery status.
Returns:
true if a battery is present and connected to a custom chip

HasWramBattery

public bool HasWramBattery() const throw();
Returns W-RAM battery status.
Returns:
true if a battery is present and connected to W-RAM

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..Dump..State.html000066400000000000000000000116531411157722000263500ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::Dump::State
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Cartridge::Profile::Dump::State

Dump state type.


Field Summary
BAD
          Bad dump.
OK
          Good dump.
UNKNOWN
          Unknown dump.
 

Field Detail

BAD

public BAD
Bad dump.

OK

public OK
Good dump.

UNKNOWN

public UNKNOWN
Unknown dump.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..Dump.html000066400000000000000000000163311411157722000252110ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::Dump
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Cartridge::Profile::Dump


struct Nes::Api::Cartridge::Profile::Dump

Dump context.


Inner Classes, Typedefs, and Enums
enum Nes::Api::Cartridge::Profile::Dump::State
          Dump state type.
 
Field Summary
 std::wstring by
          Dumped by.
 std::wstring date
          Dump date.
 Nes::Api::Cartridge::Profile::Dump::State state
          Dump state.
 
Constructor Summary
Dump()
          
 

Field Detail

by

public std::wstring by;
Dumped by.

date

public std::wstring date;
Dump date.

state

public Nes::Api::Cartridge::Profile::Dump::State state;
Dump state.


Constructor Detail

Dump

public Dump() throw();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..Game.html000066400000000000000000000261501411157722000251550ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::Game
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Cartridge::Profile::Game


struct Nes::Api::Cartridge::Profile::Game

Game context.


Field Summary
 Input::Adapter adapter
          Utilized controller adapter.
 std::wstring altTitle
          Alternative game title.
 std::wstring catalog
          Catalog.
 std::wstring clss
          Class.
 Input::Type[ 5 ] controllers
          Utilized controllers.
 std::wstring developer
          Developer.
 uint players
          Number of players.
 std::wstring portDeveloper
          Port Developer.
 std::wstring publisher
          Publisher.
 std::wstring region
          Region.
 std::wstring revision
          Revision.
 std::wstring subClss
          Sub-class.
 std::wstring title
          Game title.
 
Constructor Summary
Game()
          
 

Field Detail

adapter

public Input::Adapter adapter;
Utilized controller adapter.

altTitle

public std::wstring altTitle;
Alternative game title.

catalog

public std::wstring catalog;
Catalog.

clss

public std::wstring clss;
Class.

controllers

public Input::Type controllers[ 5 ];
Utilized controllers.

developer

public std::wstring developer;
Developer.

players

public uint players;
Number of players.

portDeveloper

public std::wstring portDeveloper;
Port Developer.

publisher

public std::wstring publisher;
Publisher.

region

public std::wstring region;
Region.

revision

public std::wstring revision;
Revision.

subClss

public std::wstring subClss;
Sub-class.

title

public std::wstring title;
Game title.


Constructor Detail

Game

public Game() throw();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..Hash.html000066400000000000000000000361001411157722000251630ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::Hash
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Class Nes::Api::Cartridge::Profile::Hash

Core::ImplicitBool
   |
   +--Nes::Api::Cartridge::Profile::Hash


class Nes::Api::Cartridge::Profile::Hash
extends Core::ImplicitBool

Hash checksum. Stores SHA-1 and CRC-32 combined or just one of the two.


Constructor Summary
Hash( const char* sha, const char* crc )
          Constructs new checksum from null-terminated strings.
Hash( const wchar_t* sha, const wchar_t* crc )
          Constructs new checksum from null-terminated wide-strings.
Hash( const dword* sha, dword crc )
          Constructs new checksum from input values.
Hash()
          Default constructor.
 
Method Summary
 void Assign( const wchar_t* sha, const wchar_t* crc )
          Assigns new checksum from null-terminated wide-strings.
 void Assign( const dword* sha, dword crc )
          Assigns new checksum from input values.
 void Assign( const char* sha, const char* crc )
          Assigns new checksum from null-terminated strings.
 void Clear()
          Clears the current checksum.
 void Compute( const void* mem, ulong length )
          Computes and updates checksum from input.
 void Get( char* sha, char* crc ) const
          Returns the current checksum.
 dword GetCrc32() const
          Returns the current CRC-32 value.
 const dword* GetSha1() const
          Returns the current SHA-1 values.
 bool operator!() const
          Checks if checksum is cleared.
 bool operator<( const Hash& hash ) const
          Tests for less-than.
 bool operator==( const Hash& hash ) const
          Tests for equality.
 

Constructor Detail

Hash

public Hash( const char* sha, const char* crc ) throw();
Constructs new checksum from null-terminated strings.
Parameters:
sha - SHA-1 string, set to NULL if values shouldn't be used
crc - CRC-32 string, set to NULL if value shouldn't be used

Hash

public Hash( const wchar_t* sha, const wchar_t* crc ) throw();
Constructs new checksum from null-terminated wide-strings.
Parameters:
sha - SHA-1 string, set to NULL if values shouldn't be used
crc - CRC-32 string, set to NULL if value shouldn't be used

Hash

public Hash( const dword* sha, dword crc ) throw();
Constructs new checksum from input values.
Parameters:
sha - SHA-1 value, set to NULL if values shouldn't be used
crc - CRC-32 value, set to 0 if value shouldn't be used

Hash

public Hash() throw();
Default constructor.


Method Detail

Assign

public void Assign( const wchar_t* sha, const wchar_t* crc ) throw();
Assigns new checksum from null-terminated wide-strings.
Parameters:
sha - SHA-1 string, set to NULL if values shouldn't be used
crc - CRC-32 string, set to NULL if value shouldn't be used

Assign

public void Assign( const dword* sha, dword crc ) throw();
Assigns new checksum from input values.
Parameters:
sha - SHA-1 value, set to NULL if values shouldn't be used
crc - CRC-32 value, set to 0 if value shouldn't be used

Assign

public void Assign( const char* sha, const char* crc ) throw();
Assigns new checksum from null-terminated strings.
Parameters:
sha - SHA-1 string, set to NULL if values shouldn't be used
crc - CRC-32 string, set to NULL if value shouldn't be used

Clear

public void Clear() throw();
Clears the current checksum.

Compute

public void Compute( const void* mem, ulong length ) throw();
Computes and updates checksum from input.
Parameters:
mem - pointer to memory
length - length of memory in bytes

Get

public void Get( char* sha, char* crc ) const throw();
Returns the current checksum.
Parameters:
sha - SHA-1 string to be filled, set to to NULL if not needed
crc - CRC-32 string to be filled, set to NULL if not needed

GetCrc32

public dword GetCrc32() const throw();
Returns the current CRC-32 value.
Returns:
CRC-32 value, 0 if unused

GetSha1

public const dword* GetSha1() const throw();
Returns the current SHA-1 values.
Returns:
SHA-1 values, zero-filled if unused

operator!

public bool operator!() const throw();
Checks if checksum is cleared.
Returns:
true if cleared

operator<

public bool operator<( const Hash& hash ) const throw();
Tests for less-than.
Parameters:
hash - hash to compare with
Returns:
true if input hash is less than this

operator==

public bool operator==( const Hash& hash ) const throw();
Tests for equality.
Parameters:
hash - hash to compare with
Returns:
true if hashes are equal

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..Properties.html000066400000000000000000000076361411157722000264500ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::Properties
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Cartridge::Profile::Properties

Cartridge properties.




Details

Properties

public typedef std::vector< Property > Properties;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..Property.html000066400000000000000000000117321411157722000261300ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::Property
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Cartridge::Profile::Property


struct Nes::Api::Cartridge::Profile::Property

Cartridge property.


Field Summary
 std::wstring name
          Name.
 std::wstring value
          Value.
 

Field Detail

name

public std::wstring name;
Name.

value

public std::wstring value;
Value.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..System..Cpu.html000066400000000000000000000124451411157722000263760ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::System::Cpu
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Cartridge::Profile::System::Cpu

CPU type.


Field Summary
CPU_DENDY = Core : : CPU_DENDY
          Dendy CPU (clone).
CPU_RP2A03 = Core : : CPU_RP2A03
          RP2A03 NTSC CPU.
CPU_RP2A07 = Core : : CPU_RP2A07
          RP2A07 PAL CPU.
 

Field Detail

CPU_DENDY

public CPU_DENDY = Core : : CPU_DENDY
Dendy CPU (clone).

CPU_RP2A03

public CPU_RP2A03 = Core : : CPU_RP2A03
RP2A03 NTSC CPU.

CPU_RP2A07

public CPU_RP2A07 = Core : : CPU_RP2A07
RP2A07 PAL CPU.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..System..Ppu.html000066400000000000000000000266371411157722000264230ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::System::Ppu
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Cartridge::Profile::System::Ppu

PPU type.


Field Summary
PPU_DENDY = Core : : PPU_DENDY
          Dendy PPU (clone).
PPU_RC2C03B = Core : : PPU_RC2C03B
          RC2C03B RGB PPU.
PPU_RC2C03C = Core : : PPU_RC2C03C
          RC2C03C RGB PPU.
PPU_RC2C05_01 = Core : : PPU_RC2C05_01
          RC2C05-01 RGB PPU.
PPU_RC2C05_02 = Core : : PPU_RC2C05_02
          RC2C05-02 RGB PPU.
PPU_RC2C05_03 = Core : : PPU_RC2C05_03
          RC2C05-03 RGB PPU.
PPU_RC2C05_04 = Core : : PPU_RC2C05_04
          RC2C05-04 RGB PPU.
PPU_RC2C05_05 = Core : : PPU_RC2C05_05
          RC2C05-05 RGB PPU.
PPU_RP2C02 = Core : : PPU_RP2C02
          RP2C02 NTSC PPU.
PPU_RP2C03B = Core : : PPU_RP2C03B
          RP2C03B RGB PPU.
PPU_RP2C03G = Core : : PPU_RP2C03G
          RP2C03G RGB PPU.
PPU_RP2C04_0001 = Core : : PPU_RP2C04_0001
          RP2C04-0001 RGB PPU.
PPU_RP2C04_0002 = Core : : PPU_RP2C04_0002
          RP2C04-0002 RGB PPU.
PPU_RP2C04_0003 = Core : : PPU_RP2C04_0003
          RP2C04-0003 RGB PPU.
PPU_RP2C04_0004 = Core : : PPU_RP2C04_0004
          RP2C04-0004 RGB PPU.
PPU_RP2C07 = Core : : PPU_RP2C07
          RP2C07 PAL PPU.
 

Field Detail

PPU_DENDY

public PPU_DENDY = Core : : PPU_DENDY
Dendy PPU (clone).

PPU_RC2C03B

public PPU_RC2C03B = Core : : PPU_RC2C03B
RC2C03B RGB PPU.

PPU_RC2C03C

public PPU_RC2C03C = Core : : PPU_RC2C03C
RC2C03C RGB PPU.

PPU_RC2C05_01

public PPU_RC2C05_01 = Core : : PPU_RC2C05_01
RC2C05-01 RGB PPU.

PPU_RC2C05_02

public PPU_RC2C05_02 = Core : : PPU_RC2C05_02
RC2C05-02 RGB PPU.

PPU_RC2C05_03

public PPU_RC2C05_03 = Core : : PPU_RC2C05_03
RC2C05-03 RGB PPU.

PPU_RC2C05_04

public PPU_RC2C05_04 = Core : : PPU_RC2C05_04
RC2C05-04 RGB PPU.

PPU_RC2C05_05

public PPU_RC2C05_05 = Core : : PPU_RC2C05_05
RC2C05-05 RGB PPU.

PPU_RP2C02

public PPU_RP2C02 = Core : : PPU_RP2C02
RP2C02 NTSC PPU.

PPU_RP2C03B

public PPU_RP2C03B = Core : : PPU_RP2C03B
RP2C03B RGB PPU.

PPU_RP2C03G

public PPU_RP2C03G = Core : : PPU_RP2C03G
RP2C03G RGB PPU.

PPU_RP2C04_0001

public PPU_RP2C04_0001 = Core : : PPU_RP2C04_0001
RP2C04-0001 RGB PPU.

PPU_RP2C04_0002

public PPU_RP2C04_0002 = Core : : PPU_RP2C04_0002
RP2C04-0002 RGB PPU.

PPU_RP2C04_0003

public PPU_RP2C04_0003 = Core : : PPU_RP2C04_0003
RP2C04-0003 RGB PPU.

PPU_RP2C04_0004

public PPU_RP2C04_0004 = Core : : PPU_RP2C04_0004
RP2C04-0004 RGB PPU.

PPU_RP2C07

public PPU_RP2C07 = Core : : PPU_RP2C07
RP2C07 PAL PPU.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..System..Type.html000066400000000000000000000173251411157722000265720ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::System::Type
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Cartridge::Profile::System::Type

System Type.


Field Summary
DENDY = Core : : SYSTEM_DENDY
          Dendy console (clone).
FAMICOM = Core : : SYSTEM_FAMICOM
          Famicom console.
NES_NTSC = Core : : SYSTEM_NES_NTSC
          NES NTSC console.
NES_PAL = Core : : SYSTEM_NES_PAL
          NES PAL console.
NES_PAL_A = Core : : SYSTEM_NES_PAL_A
          NES PAL-A console.
NES_PAL_B = Core : : SYSTEM_NES_PAL_B
          NES PAL-B console.
PLAYCHOICE_10 = Core : : SYSTEM_PLAYCHOICE_10
          PlayChoice-10 arcade.
VS_DUALSYSTEM = Core : : SYSTEM_VS_DUALSYSTEM
          Vs DualSystem arcade.
VS_UNISYSTEM = Core : : SYSTEM_VS_UNISYSTEM
          Vs UniSystem arcade.
 

Field Detail

DENDY

public DENDY = Core : : SYSTEM_DENDY
Dendy console (clone).

FAMICOM

public FAMICOM = Core : : SYSTEM_FAMICOM
Famicom console.

NES_NTSC

public NES_NTSC = Core : : SYSTEM_NES_NTSC
NES NTSC console.

NES_PAL

public NES_PAL = Core : : SYSTEM_NES_PAL
NES PAL console.

NES_PAL_A

public NES_PAL_A = Core : : SYSTEM_NES_PAL_A
NES PAL-A console.

NES_PAL_B

public NES_PAL_B = Core : : SYSTEM_NES_PAL_B
NES PAL-B console.

PLAYCHOICE_10

public PLAYCHOICE_10 = Core : : SYSTEM_PLAYCHOICE_10
PlayChoice-10 arcade.

VS_DUALSYSTEM

public VS_DUALSYSTEM = Core : : SYSTEM_VS_DUALSYSTEM
Vs DualSystem arcade.

VS_UNISYSTEM

public VS_UNISYSTEM = Core : : SYSTEM_VS_UNISYSTEM
Vs UniSystem arcade.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile..System.html000066400000000000000000000204251411157722000255670ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile::System
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Cartridge::Profile::System


struct Nes::Api::Cartridge::Profile::System

System context.


Inner Classes, Typedefs, and Enums
enum Nes::Api::Cartridge::Profile::System::Cpu
          CPU type.
enum Nes::Api::Cartridge::Profile::System::Ppu
          PPU type.
enum Nes::Api::Cartridge::Profile::System::Type
          System Type.
 
Field Summary
 Nes::Api::Cartridge::Profile::System::Cpu cpu
          CPU type.
 Nes::Api::Cartridge::Profile::System::Ppu ppu
          PPU type.
 Nes::Api::Cartridge::Profile::System::Type type
          System type.
 
Constructor Summary
System()
          
 

Field Detail

cpu

public Nes::Api::Cartridge::Profile::System::Cpu cpu;
CPU type.

ppu

public Nes::Api::Cartridge::Profile::System::Ppu ppu;
PPU type.

type

public Nes::Api::Cartridge::Profile::System::Type type;
System type.


Constructor Detail

System

public System() throw();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge..Profile.html000066400000000000000000000312641411157722000242310ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge::Profile
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Cartridge::Profile


struct Nes::Api::Cartridge::Profile

Cartridge profile context.


Inner Classes, Typedefs, and Enums
class Nes::Api::Cartridge::Profile::Board
          Board context.
struct Nes::Api::Cartridge::Profile::Dump
          Dump context.
struct Nes::Api::Cartridge::Profile::Game
          Game context.
class Nes::Api::Cartridge::Profile::Hash
          Hash checksum.
typedef Nes::Api::Cartridge::Profile::Properties
          Cartridge properties.
struct Nes::Api::Cartridge::Profile::Property
          Cartridge property.
struct Nes::Api::Cartridge::Profile::System
          System context.
 
Field Summary
 Nes::Api::Cartridge::Profile::Board board
          Board context.
 Nes::Api::Cartridge::Profile::Dump dump
          Dump context.
 Nes::Api::Cartridge::Profile::Game game
          Game context.
 Nes::Api::Cartridge::Profile::Hash hash
          Hash of ROM chips combined.
 bool multiRegion
          Multi-region game.
 bool patched
          Soft-patching state.
 Nes::Api::Cartridge::Profile::Properties properties
          Properties.
 Nes::Api::Cartridge::Profile::System system
          System context.
 
Constructor Summary
Profile()
          
~Profile()
          
 

Field Detail

board

public Nes::Api::Cartridge::Profile::Board board;
Board context.

dump

public Nes::Api::Cartridge::Profile::Dump dump;
Dump context.

game

public Nes::Api::Cartridge::Profile::Game game;
Game context.

hash

public Nes::Api::Cartridge::Profile::Hash hash;
Hash of ROM chips combined.

multiRegion

public bool multiRegion;
Multi-region game.

patched

public bool patched;
Soft-patching state.

properties

public Nes::Api::Cartridge::Profile::Properties properties;
Properties.

system

public Nes::Api::Cartridge::Profile::System system;
System context.


Constructor Detail

Profile

public Profile() throw();

~Profile

public ~Profile() throw();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cartridge.html000066400000000000000000000331521411157722000225520ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cartridge
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Class Nes::Api::Cartridge

Base
   |
   +--Nes::Api::Cartridge


class Nes::Api::Cartridge
extends Base

Cartridge interface.


Inner Classes, Typedefs, and Enums
typedef Nes::Api::Cartridge::ChooseProfileCallback
          Cartridge profile chooser callback prototype.
class Nes::Api::Cartridge::Database
          Database interface
struct Nes::Api::Cartridge::NesHeader
          iNES header format context.
struct Nes::Api::Cartridge::Profile
          Cartridge profile context.
 
Field Summary
 static Nes::Api::Cartridge::ChooseProfileCaller chooseProfileCallback
          Cartridge profile chooser callback manager.
 
Constructor Summary
Cartridge( T& instance )
          Interface constructor.
 
Method Summary
 Nes::Api::Cartridge::Database GetDatabase()
          Returns the database interface.
 const Nes::Api::Cartridge::Profile* GetProfile() const
          Returns the current cartridge profile.
 static Result ReadInes( std::istream& stream, Machine::FavoredSystem system, Nes::Api::Cartridge::Profile& profile )
          Creates a profile of an iNES file.
 static Result ReadRomset( std::istream& stream, Machine::FavoredSystem system, bool askProfile, Nes::Api::Cartridge::Profile& profile )
          Creates a profile of an XML ROM set file.
 static Result ReadUnif( std::istream& stream, Machine::FavoredSystem system, Nes::Api::Cartridge::Profile& profile )
          Creates a profile of a UNIF file.
 

Field Detail

chooseProfileCallback

public static Nes::Api::Cartridge::ChooseProfileCaller chooseProfileCallback;
Cartridge profile chooser callback manager. Static object used for adding the user defined callback.


Constructor Detail

Cartridge

public Cartridge( T& instance );
Interface constructor.
Parameters:
instance - emulator instance


Method Detail

GetDatabase

public Nes::Api::Cartridge::Database GetDatabase() throw();
Returns the database interface.
Returns:
database interface

GetProfile

public const Nes::Api::Cartridge::Profile* GetProfile() const throw();
Returns the current cartridge profile.
Returns:
pointer to current profile, NULL if no cartridge has been loaded into the system

ReadInes

public static Result ReadInes( std::istream& stream, Machine::FavoredSystem system, Nes::Api::Cartridge::Profile& profile ) throw();
Creates a profile of an iNES file.
Parameters:
stream - input stream to iNES file
system - preferred system in case of multiple profiles
profile - object to be filled
Returns:
result code

ReadRomset

public static Result ReadRomset( std::istream& stream, Machine::FavoredSystem system, bool askProfile, Nes::Api::Cartridge::Profile& profile ) throw();
Creates a profile of an XML ROM set file.
Parameters:
stream - input stream to XML file
system - preferred system in case of multiple profiles
askProfile - allow callback triggering for choosing between multiple profiles
profile - object to be filled
Returns:
result code

ReadUnif

public static Result ReadUnif( std::istream& stream, Machine::FavoredSystem system, Nes::Api::Cartridge::Profile& profile ) throw();
Creates a profile of a UNIF file.
Parameters:
stream - input stream to UNIF file
system - preferred system in case of multiple profiles
profile - object to be filled
Returns:
result code

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cheats..Code.html000066400000000000000000000162131411157722000230030ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cheats::Code
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Cheats::Code


struct Nes::Api::Cheats::Code

Cheat code.


Field Summary
 ushort address
          Address.
 uchar compare
          Compare-value.
 bool useCompare
          Compare-value enable.
 uchar value
          Value.
 
Constructor Summary
Code( ushort a = 0, uchar v = 0, uchar c = 0, bool u = false )
          Constructor.
 

Field Detail

address

public ushort address;
Address.

compare

public uchar compare;
Compare-value.

useCompare

public bool useCompare;
Compare-value enable.

value

public uchar value;
Value.


Constructor Detail

Code

public Code( ushort a = 0, uchar v = 0, uchar c = 0, bool u = false );
Constructor.
Parameters:
a - address
v - value
c - compare-value
u - compare-value enable

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cheats..RAM_SIZE.html000066400000000000000000000075411411157722000234060ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cheats::RAM_SIZE
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Cheats::RAM_SIZE

CPU RAM pointer reference.




Details

RAM_SIZE

public typedef const uchar(& Ram )[ RAM_SIZE];

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Cheats.html000066400000000000000000000366601411157722000220640ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Cheats
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Class Nes::Api::Cheats

Base
   |
   +--Nes::Api::Cheats


class Nes::Api::Cheats
extends Base

Cheats interface.


Inner Classes, Typedefs, and Enums
struct Nes::Api::Cheats::Code
          Cheat code.
typedef Nes::Api::Cheats::RAM_SIZE
          CPU RAM pointer reference.
 
Constructor Summary
Cheats( T& instance )
          Interface constructor.
 
Method Summary
 Result ClearCodes()
          Removes all existing codes.
 Result DeleteCode( ulong index )
          Removes an existing code.
 static Result NST_CALL GameGenieDecode( const char* string, Nes::Api::Cheats::Code& code )
          Decodes a Game Genie code.
 static Result NST_CALL GameGenieEncode( const Nes::Api::Cheats::Code& code, char(& string )[ 9] )
          Encodes into a Game Genie code.
 Result GetCode( ulong index, ushort* address, uchar* value, uchar* compare, bool* useCompare ) const
          Returns attributes of an existing code.
 Result GetCode( ulong index, Nes::Api::Cheats::Code& code ) const
          Returns an existing code.
 Ram GetRam() const
          Returns read-only content of CPU RAM.
 ulong NumCodes() const
          Returns current number of codes.
 static Result NST_CALL ProActionRockyDecode( const char* string, Nes::Api::Cheats::Code& code )
          Decodes a Pro-Action Rocky code.
 static Result NST_CALL ProActionRockyEncode( const Nes::Api::Cheats::Code& code, char(& string )[ 9] )
          Encodes into a Pro-Action Rocky code.
 Result SetCode( const Nes::Api::Cheats::Code& code )
          Adds a new code.
 

Constructor Detail

Cheats

public Cheats( T& instance );
Interface constructor.
Parameters:
instance - emulator instance


Method Detail

ClearCodes

public Result ClearCodes() throw();
Removes all existing codes.
Returns:
result code

DeleteCode

public Result DeleteCode( ulong index ) throw();
Removes an existing code.
Parameters:
index - code index
Returns:
result code

GameGenieDecode

public static Result NST_CALL GameGenieDecode( const char* string, Nes::Api::Cheats::Code& code ) throw();
Decodes a Game Genie code.
Parameters:
string - Game Genie encoded string
code - object to be filled
Returns:
result code

GameGenieEncode

public static Result NST_CALL GameGenieEncode( const Nes::Api::Cheats::Code& code, char(& string )[ 9] ) throw();
Encodes into a Game Genie code.
Parameters:
code - code to be encoded
string - Game Genie code string to be filled
Returns:
result code

GetCode

public Result GetCode( ulong index, ushort* address, uchar* value, uchar* compare, bool* useCompare ) const throw();
Returns attributes of an existing code.
Parameters:
index - code index
address - address to be filled or NULL if not needed
value - value to be filled or NULL if not needed
compare - compare-value to be filled or NULL if not needed
useCompare - compare-value enable to be filled or NULL if not needed
Returns:
result code

GetCode

public Result GetCode( ulong index, Nes::Api::Cheats::Code& code ) const throw();
Returns an existing code.
Parameters:
index - code index
code - object to be filled
Returns:
result code

GetRam

public Ram GetRam() const throw();
Returns read-only content of CPU RAM.
Returns:
CPU RAM

NumCodes

public ulong NumCodes() const throw();
Returns current number of codes.
Returns:
number

ProActionRockyDecode

public static Result NST_CALL ProActionRockyDecode( const char* string, Nes::Api::Cheats::Code& code ) throw();
Decodes a Pro-Action Rocky code.
Parameters:
string - Pro-Action Rocky encoded string
code - object to be filled
Returns:
result

ProActionRockyEncode

public static Result NST_CALL ProActionRockyEncode( const Nes::Api::Cheats::Code& code, char(& string )[ 9] ) throw();
Encodes into a Pro-Action Rocky code.
Parameters:
code - code to be encoded
string - Pro-Action Rocky code string to be filled
Returns:
result code

SetCode

public Result SetCode( const Nes::Api::Cheats::Code& code ) throw();
Adds a new code.
Parameters:
code - code, any existing code using the same address will be replaced
Returns:
result code

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..DipSwitches.html000066400000000000000000000242661411157722000231020ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::DipSwitches
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Class Nes::Api::DipSwitches

Base
   |
   +--Nes::Api::DipSwitches


class Nes::Api::DipSwitches
extends Base

DIP switches interface.


Constructor Summary
DipSwitches( T& instance )
          Interface constructor.
 
Method Summary
 bool CanModify() const
          Checks if the DIP switches can be changed at this time.
 const char* GetDipName( uint dip ) const
          Returns the name of a DIP switch.
 int GetValue( uint dip ) const
          Returns the current DIP switch value.
 const char* GetValueName( uint dip, uint value ) const
          Returns the name of a DIP switch value.
 uint NumDips() const
          Returns the number of available DIP switches.
 uint NumValues( uint dip ) const
          Returns the number of values that can be chosen for a DIP switch.
 Result SetValue( uint dip, uint value )
          Sets a DIP switch value.
 

Constructor Detail

DipSwitches

public DipSwitches( T& instance );
Interface constructor.
Parameters:
instance - emulator instance


Method Detail

CanModify

public bool CanModify() const throw();
Checks if the DIP switches can be changed at this time.
Returns:
true if DIP switches can be changed

GetDipName

public const char* GetDipName( uint dip ) const throw();
Returns the name of a DIP switch.
Parameters:
dip - DIP switch ID
Returns:
DIP switch name or NULL if unavailable

GetValue

public int GetValue( uint dip ) const throw();
Returns the current DIP switch value.
Parameters:
dip - DIP switch ID
Returns:
value ID or INVALID if unavailable

GetValueName

public const char* GetValueName( uint dip, uint value ) const throw();
Returns the name of a DIP switch value.
Parameters:
dip - DIP switch ID
value - value ID
Returns:
value name or NULL if unavailable

NumDips

public uint NumDips() const throw();
Returns the number of available DIP switches.
Returns:
number

NumValues

public uint NumValues( uint dip ) const throw();
Returns the number of values that can be chosen for a DIP switch.
Parameters:
dip - DIP switch ID
Returns:
number

SetValue

public Result SetValue( uint dip, uint value ) throw();
Sets a DIP switch value.
Parameters:
dip - DIP switch ID
value - value ID
Returns:
result code

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Emulator..Core.html000066400000000000000000000107041411157722000234010ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Emulator::Core
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Nes::Api::Emulator::Core


Nes::Api::Emulator::Core


Method Summary
 operator Machine&()
          
 

Method Detail

Machine&

public operator Machine&();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Emulator.html000066400000000000000000000172361411157722000224430ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Emulator
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Class Nes::Api::Emulator


class Nes::Api::Emulator

Emulator object instance.


Inner Classes, Typedefs, and Enums
Nes::Api::Emulator::Core
          
 
Constructor Summary
Emulator()
          
~Emulator()
          
 
Method Summary
 Result Execute( Core::Video::Output* video, Core::Sound::Output* sound, Core::Input::Controllers* input )
          Executes one frame.
 ulong Frame() const
          Returns the number of executed frames relative to the last machine power/reset.
 

Constructor Detail

Emulator

public Emulator();

~Emulator

public ~Emulator() throw();


Method Detail

Execute

public Result Execute( Core::Video::Output* video, Core::Sound::Output* sound, Core::Input::Controllers* input ) throw();
Executes one frame.
Parameters:
video - video context object or NULL to skip output
sound - sound context object or NULL to skip output
input - input context object or NULL to skip output
Returns:
result code

Frame

public ulong Frame() const throw();
Returns the number of executed frames relative to the last machine power/reset.
Returns:
number

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Fds..DiskCallback.html000066400000000000000000000102111411157722000237350ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Fds::DiskCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Fds::DiskCallback

Disk event callback prototype.

Parameters:
userData - optional user data
event - type of event
disk - disk number
disk - side, 0(A) or 1(B)



Details

DiskCallback

public typedef void( NST_CALLBACK* DiskCallback )( UserData userData, Event event, uint disk, uint side );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Fds..DiskCaller.html000066400000000000000000000114011411157722000234450ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Fds::DiskCaller
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Fds::DiskCaller

Core::UserCallback
   |
   +--Nes::Api::Fds::DiskCaller


struct Nes::Api::Fds::DiskCaller
extends Core::UserCallback

Disk event callback invoker. Used internally by the core.


Method Summary
 void operator()( Event event, uint disk, uint side ) const
          
 

Method Detail

operator()

public void operator()( Event event, uint disk, uint side ) const;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Fds..DiskData..Data.html000066400000000000000000000075171411157722000240570ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Fds::DiskData::Data
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Fds::DiskData::Data

Data content.




Details

Data

public typedef std::vector< uchar > Data;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Fds..DiskData..File..Type.html000066400000000000000000000125541411157722000250600ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Fds::DiskData::File::Type
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Fds::DiskData::File::Type

File type.


Field Summary
TYPE_CHR
          CHR data file.
TYPE_NMT
          Name-table data file.
TYPE_PRG
          PRG data file.
TYPE_UNKNOWN
          Unknown file.
 

Field Detail

TYPE_CHR

public TYPE_CHR
CHR data file.

TYPE_NMT

public TYPE_NMT
Name-table data file.

TYPE_PRG

public TYPE_PRG
PRG data file.

TYPE_UNKNOWN

public TYPE_UNKNOWN
Unknown file.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Fds..DiskData..File.html000066400000000000000000000206461411157722000240630ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Fds::DiskData::File
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Fds::DiskData::File


struct Nes::Api::Fds::DiskData::File

File on disk.


Inner Classes, Typedefs, and Enums
enum Nes::Api::Fds::DiskData::File::Type
          File type.
 
Field Summary
 ushort address
          File address.
 Data data
          File content.
 uchar id
          File ID.
 uchar index
          File index.
 char[ 12 ] name
          File name.
 Nes::Api::Fds::DiskData::File::Type type
          File type.
 
Constructor Summary
File()
          
 

Field Detail

address

public ushort address;
File address.

data

public Data data;
File content.

id

public uchar id;
File ID.

index

public uchar index;
File index.

name

public char name[ 12 ];
File name.

type

public Nes::Api::Fds::DiskData::File::Type type;
File type.


Constructor Detail

File

public File() throw();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Fds..DiskData..Files.html000066400000000000000000000075171411157722000242500ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Fds::DiskData::Files
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Fds::DiskData::Files

Files.




Details

Files

public typedef std::vector< File > Files;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Fds..DiskData.html000066400000000000000000000174451411157722000231320ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Fds::DiskData
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Fds::DiskData


struct Nes::Api::Fds::DiskData

Disk data context.


Inner Classes, Typedefs, and Enums
typedef Nes::Api::Fds::DiskData::Data
          Data content.
struct Nes::Api::Fds::DiskData::File
          File on disk.
typedef Nes::Api::Fds::DiskData::Files
          Files.
 
Field Summary
 Nes::Api::Fds::DiskData::Files files
          Files.
 Nes::Api::Fds::DiskData::Data raw
          Raw binary content.
 
Constructor Summary
DiskData()
          
~DiskData()
          
 

Field Detail

files

public Nes::Api::Fds::DiskData::Files files;
Files.

raw

public Nes::Api::Fds::DiskData::Data raw;
Raw binary content.


Constructor Detail

DiskData

public DiskData() throw();

~DiskData

public ~DiskData() throw();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Fds..DriveCallback.html000066400000000000000000000100511411157722000241160ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Fds::DriveCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Fds::DriveCallback

Drive event callback prototype.

Parameters:
userData - optional user data
event - type of event



Details

DriveCallback

public typedef void( NST_CALLBACK* DriveCallback )( UserData userData, Motor event );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Fds..DriveCaller.html000066400000000000000000000113101411157722000236230ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Fds::DriveCaller
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Fds::DriveCaller

Core::UserCallback
   |
   +--Nes::Api::Fds::DriveCaller


struct Nes::Api::Fds::DriveCaller
extends Core::UserCallback

Drive event callback invoker. Used internally by the core.


Method Summary
 void operator()( Motor motor ) const
          
 

Method Detail

operator()

public void operator()( Motor motor ) const;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Fds..Event.html000066400000000000000000000121041411157722000225120ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Fds::Event
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Fds::Event

Disk event.


Field Summary
DISK_EJECT
          Disk has been ejected.
DISK_INSERT
          Disk has been inserted.
DISK_NONSTANDARD
          Disk is in a non-standard format.
 

Field Detail

DISK_EJECT

public DISK_EJECT
Disk has been ejected.

DISK_INSERT

public DISK_INSERT
Disk has been inserted.

DISK_NONSTANDARD

public DISK_NONSTANDARD
Disk is in a non-standard format.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Fds..Motor.html000066400000000000000000000120151411157722000225320ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Fds::Motor
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Fds::Motor

Drive event.


Field Summary
MOTOR_OFF
          Drive motor is OFF.
MOTOR_READ
          Drive motor is ON reading.
MOTOR_WRITE
          Drive motor is ON writing.
 

Field Detail

MOTOR_OFF

public MOTOR_OFF
Drive motor is OFF.

MOTOR_READ

public MOTOR_READ
Drive motor is ON reading.

MOTOR_WRITE

public MOTOR_WRITE
Drive motor is ON writing.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Fds.html000066400000000000000000000443521411157722000213660ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Fds
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Class Nes::Api::Fds

Base
   |
   +--Nes::Api::Fds


class Nes::Api::Fds
extends Base

Famicom Disk System interface.


Inner Classes, Typedefs, and Enums
typedef Nes::Api::Fds::DiskCallback
          Disk event callback prototype.
struct Nes::Api::Fds::DiskData
          Disk data context.
typedef Nes::Api::Fds::DriveCallback
          Drive event callback prototype.
enum Nes::Api::Fds::Event
          Disk event.
enum Nes::Api::Fds::Motor
          Drive event.
 
Field Summary
 static Nes::Api::Fds::DiskCaller diskCallback
          Disk event callback manager.
 static Nes::Api::Fds::DriveCaller driveCallback
          Drive event callback manager.
 
Constructor Summary
Fds( T& instance )
          Interface constructor.
 
Method Summary
 bool CanChangeDiskSide() const
          Checks if the current disk can change side.
 Result ChangeSide()
          Changes disk side.
 Result EjectDisk()
          Ejects disk.
 Result GetBIOS( std::ostream& stream ) const
          Stores the current BIOS in an output stream.
 int GetCurrentDisk() const
          Returns the current disk inserted.
 int GetCurrentDiskSide() const
          Returns the current disk side.
 Result GetDiskData( uint side, Nes::Api::Fds::DiskData& data ) const
          Returns disk information.
 uint GetNumDisks() const
          Returns the total number of disks.
 uint GetNumSides() const
          Returns the total number of disks and their sides.
 bool HasBIOS() const
          Checks if a BIOS has been loaded.
 bool HasHeader() const
          Checks if the current loaded image comes with a file header.
 Result InsertDisk( uint disk, uint side )
          Inserts a disk.
 bool IsAnyDiskInserted() const
          Checks if a disk is inserted.
 Result SetBIOS( std::istream* stream )
          Sets BIOS.
 

Field Detail

diskCallback

public static Nes::Api::Fds::DiskCaller diskCallback;
Disk event callback manager. Static object used for adding the user defined callback.

driveCallback

public static Nes::Api::Fds::DriveCaller driveCallback;
Drive event callback manager. Static object used for adding the user defined callback.


Constructor Detail

Fds

public Fds( T& instance );
Interface constructor.
Parameters:
instance - emulator instance


Method Detail

CanChangeDiskSide

public bool CanChangeDiskSide() const throw();
Checks if the current disk can change side.
Returns:
true if disk can change side

ChangeSide

public Result ChangeSide() throw();
Changes disk side.
Returns:
result code

EjectDisk

public Result EjectDisk() throw();
Ejects disk.
Returns:
result code

GetBIOS

public Result GetBIOS( std::ostream& stream ) const throw();
Stores the current BIOS in an output stream.
Parameters:
output - stream
Returns:
result code

GetCurrentDisk

public int GetCurrentDisk() const throw();
Returns the current disk inserted.
Returns:
current disk or NO_DISK if none

GetCurrentDiskSide

public int GetCurrentDiskSide() const throw();
Returns the current disk side.
Returns:
0(A), 1(B) or NO_DISK if no disk inserted

GetDiskData

public Result GetDiskData( uint side, Nes::Api::Fds::DiskData& data ) const throw();
Returns disk information.
Parameters:
side - disks and sides index
data - object to be filled
Returns:
result code

GetNumDisks

public uint GetNumDisks() const throw();
Returns the total number of disks.
Returns:
number

GetNumSides

public uint GetNumSides() const throw();
Returns the total number of disks and their sides.
Returns:
number

HasBIOS

public bool HasBIOS() const throw();
Checks if a BIOS has been loaded.
Returns:
true if a BIOS has been loaded.

HasHeader

public bool HasHeader() const throw();
Checks if the current loaded image comes with a file header.
Returns:
true if it comes with a file header

InsertDisk

public Result InsertDisk( uint disk, uint side ) throw();
Inserts a disk.
Parameters:
disk - disk number
side - disk side, 0(A) or 1(B)
Returns:
result code

IsAnyDiskInserted

public bool IsAnyDiskInserted() const throw();
Checks if a disk is inserted.
Returns:
true if a disk is inserted

SetBIOS

public Result SetBIOS( std::istream* stream ) throw();
Sets BIOS.
Parameters:
input - stream to ROM binary or iNES file, set to NULL to remove current BIOS

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Input..Adapter.html000066400000000000000000000112351411157722000234000ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Input::Adapter
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Input::Adapter

Adapter type.


Field Summary
ADAPTER_FAMICOM
          Famicom adapter.
ADAPTER_NES
          NES adapter.
 

Field Detail

ADAPTER_FAMICOM

public ADAPTER_FAMICOM
Famicom adapter.

ADAPTER_NES

public ADAPTER_NES
NES adapter.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Input..AdapterCallback.html000066400000000000000000000102001411157722000250040ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Input::AdapterCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Input::AdapterCallback

Adapter event callback prototype. Will be invoked every time a new adapter is connected.

Parameters:
userData - optional user data
adapter - adapter type



Details

AdapterCallback

public typedef void( NST_CALLBACK* AdapterCallback )( UserData userData, Adapter adapter );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Input..AdapterCaller.html000066400000000000000000000113601411157722000245220ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Input::AdapterCaller
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Input::AdapterCaller

Core::UserCallback
   |
   +--Nes::Api::Input::AdapterCaller


struct Nes::Api::Input::AdapterCaller
extends Core::UserCallback

Adapter event callback invoker. Used internally by the core.


Method Summary
 void operator()( Adapter adapter ) const
          
 

Method Detail

operator()

public void operator()( Adapter adapter ) const;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Input..ControllerCallback.html000066400000000000000000000103071411157722000255570ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Input::ControllerCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Input::ControllerCallback

Controller event callback prototype. Will be invoked every time a new controller is connected to a port.

Parameters:
userData - optional user data
port - port
type - controller



Details

ControllerCallback

public typedef void( NST_CALLBACK* ControllerCallback )( UserData userData, uint port, Type type );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Input..ControllerCaller.html000066400000000000000000000114231411157722000252650ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Input::ControllerCaller
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Input::ControllerCaller

Core::UserCallback
   |
   +--Nes::Api::Input::ControllerCaller


struct Nes::Api::Input::ControllerCaller
extends Core::UserCallback

Controller event callback invoker. Used internally by the core.


Method Summary
 void operator()( uint port, Type type ) const
          
 

Method Detail

operator()

public void operator()( uint port, Type type ) const;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Input..Controllers.html000066400000000000000000000075711411157722000243360ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Input::Controllers
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Input::Controllers

Controllers context.




Details

Controllers

public typedef Core::Input::Controllers Controllers;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Input..Type.html000066400000000000000000000333001411157722000227360ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Input::Type
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Input::Type

Controller type.


Field Summary
BANDAIHYPERSHOT
          Bandai hypershot.
BARCODEWORLD
          Barcode World.
CRAZYCLIMBER
          Crazy Climber.
DOREMIKKOKEYBOARD
          Doremikko keyboard.
EXCITINGBOXING
          Exciting Boxing.
FAMILYKEYBOARD
          Family keyboard.
FAMILYTRAINER
          Family Trainer.
HORITRACK
          Horitrack.
KONAMIHYPERSHOT
          Konami hypershot.
MAHJONG
          Mahjong.
MOUSE
          Mouse.
OEKAKIDSTABLET
          Oeka Kids tablet.
PACHINKO
          Pachinko.
PAD1
          Standard pad #1
PAD2
          Standard pad #2
PAD3
          Standard pad #3
PAD4
          Standard pad #4
PADDLE
          Arkanoid paddle.
PARTYTAP
          Party Tap.
POKKUNMOGURAA
          Pokkun Moguraa.
POWERGLOVE
          Powerglove.
POWERPAD
          Powerpad.
ROB
          R.
SUBORKEYBOARD
          Subor keyboard.
TOPRIDER
          Top Rider bike.
TURBOFILE
          Turbo File.
UNCONNECTED
          Unconnected.
ZAPPER
          Zapper.
 

Field Detail

BANDAIHYPERSHOT

public BANDAIHYPERSHOT
Bandai hypershot.

BARCODEWORLD

public BARCODEWORLD
Barcode World.

CRAZYCLIMBER

public CRAZYCLIMBER
Crazy Climber.

DOREMIKKOKEYBOARD

public DOREMIKKOKEYBOARD
Doremikko keyboard.

EXCITINGBOXING

public EXCITINGBOXING
Exciting Boxing.

FAMILYKEYBOARD

public FAMILYKEYBOARD
Family keyboard.

FAMILYTRAINER

public FAMILYTRAINER
Family Trainer.

HORITRACK

public HORITRACK
Horitrack.

KONAMIHYPERSHOT

public KONAMIHYPERSHOT
Konami hypershot.

MAHJONG

public MAHJONG
Mahjong.

MOUSE

public MOUSE
Mouse.

OEKAKIDSTABLET

public OEKAKIDSTABLET
Oeka Kids tablet.

PACHINKO

public PACHINKO
Pachinko.

PAD1

public PAD1
Standard pad #1

PAD2

public PAD2
Standard pad #2

PAD3

public PAD3
Standard pad #3

PAD4

public PAD4
Standard pad #4

PADDLE

public PADDLE
Arkanoid paddle.

PARTYTAP

public PARTYTAP
Party Tap.

POKKUNMOGURAA

public POKKUNMOGURAA
Pokkun Moguraa.

POWERGLOVE

public POWERGLOVE
Powerglove.

POWERPAD

public POWERPAD
Powerpad.

ROB

public ROB
R.O.B.

SUBORKEYBOARD

public SUBORKEYBOARD
Subor keyboard.

TOPRIDER

public TOPRIDER
Top Rider bike.

TURBOFILE

public TURBOFILE
Turbo File.

UNCONNECTED

public UNCONNECTED
Unconnected.

ZAPPER

public ZAPPER
Zapper.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Input.html000066400000000000000000000371671411157722000217570ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Input
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Class Nes::Api::Input

Base
   |
   +--Nes::Api::Input


class Nes::Api::Input
extends Base

Controller input interface.


Inner Classes, Typedefs, and Enums
enum Nes::Api::Input::Adapter
          Adapter type.
typedef Nes::Api::Input::AdapterCallback
          Adapter event callback prototype.
typedef Nes::Api::Input::ControllerCallback
          Controller event callback prototype.
typedef Nes::Api::Input::Controllers
          Controllers context.
enum Nes::Api::Input::Type
          Controller type.
 
Field Summary
 static Nes::Api::Input::AdapterCaller adapterCallback
          Adapter event callback manager.
 static Nes::Api::Input::ControllerCaller controllerCallback
          Controller event callback manager.
 
Constructor Summary
Input( T& instance )
          Interface constructor.
 
Method Summary
 Result AutoSelectAdapter()
          Connects the most suited adapter for a game.
 Result AutoSelectController( uint port )
          Connects the most suited controller for a game into a port.
 Result AutoSelectControllers()
          Connects the most suited controllers for a game into all ports.
 Result ConnectAdapter( Nes::Api::Input::Adapter type )
          Connects an adapter.
 Result ConnectController( uint port, Nes::Api::Input::Type type )
          Connects a controller to a port.
 Nes::Api::Input::Adapter GetConnectedAdapter() const
          Returns the current connected adapter.
 Nes::Api::Input::Type GetConnectedController( uint port ) const
          Returns the current connected controller.
 bool IsControllerConnected( Nes::Api::Input::Type type ) const
          Checks if a specific controller is connected.
 

Field Detail

adapterCallback

public static Nes::Api::Input::AdapterCaller adapterCallback;
Adapter event callback manager. Static object used for adding the user defined callback.

controllerCallback

public static Nes::Api::Input::ControllerCaller controllerCallback;
Controller event callback manager. Static object used for adding the user defined callback.


Constructor Detail

Input

public Input( T& instance );
Interface constructor.
Parameters:
instance - emulator instance


Method Detail

AutoSelectAdapter

public Result AutoSelectAdapter() throw();
Connects the most suited adapter for a game.

AutoSelectController

public Result AutoSelectController( uint port ) throw();
Connects the most suited controller for a game into a port.
Parameters:
port - controller port
Returns:
result code

AutoSelectControllers

public Result AutoSelectControllers() throw();
Connects the most suited controllers for a game into all ports.
Returns:
result code

ConnectAdapter

public Result ConnectAdapter( Nes::Api::Input::Adapter type ) throw();
Connects an adapter.
Parameters:
type - adapter
Returns:
result code

ConnectController

public Result ConnectController( uint port, Nes::Api::Input::Type type ) throw();
Connects a controller to a port.
Parameters:
port - port
type - controller

GetConnectedAdapter

public Nes::Api::Input::Adapter GetConnectedAdapter() const throw();
Returns the current connected adapter.
Returns:
adapter

GetConnectedController

public Nes::Api::Input::Type GetConnectedController( uint port ) const throw();
Returns the current connected controller.
Parameters:
port - port
Returns:
controller

IsControllerConnected

public bool IsControllerConnected( Nes::Api::Input::Type type ) const throw();
Checks if a specific controller is connected.
Parameters:
type - controller
Returns:
true if connected

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Machine..AskProfile.html000066400000000000000000000115061411157722000243250ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Machine::AskProfile
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Machine::AskProfile

Image profile questioning state. Used for allowing callback triggering if an image has multiple media profiles.


Field Summary
ASK_PROFILE
          Trigger callback.
DONT_ASK_PROFILE
          Don't trigger callback (default).
 

Field Detail

ASK_PROFILE

public ASK_PROFILE
Trigger callback.

DONT_ASK_PROFILE

public DONT_ASK_PROFILE
Don't trigger callback (default).

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Machine..Compression.html000066400000000000000000000113731411157722000245710ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Machine::Compression
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Machine::Compression

Internal compression on states.


Field Summary
NO_COMPRESSION
          No compression.
USE_COMPRESSION
          Compression enabled (default).
 

Field Detail

NO_COMPRESSION

public NO_COMPRESSION
No compression.

USE_COMPRESSION

public USE_COMPRESSION
Compression enabled (default).

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Machine..Event.html000066400000000000000000000161771411157722000233600ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Machine::Event
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Machine::Event

Machine events.


Field Summary
EVENT_LOAD
          A new image has been loaded into the system.
EVENT_MODE_NTSC
          Mode has changed to NTSC.
EVENT_MODE_PAL
          Mode has changed to PAL.
EVENT_POWER_OFF
          Machine power OFF.
EVENT_POWER_ON
          Machine power ON.
EVENT_RESET_HARD
          Machine hard-reset.
EVENT_RESET_SOFT
          Machine soft-reset.
EVENT_UNLOAD
          An image has been unloaded from the system.
 

Field Detail

EVENT_LOAD

public EVENT_LOAD
A new image has been loaded into the system.

EVENT_MODE_NTSC

public EVENT_MODE_NTSC
Mode has changed to NTSC.

EVENT_MODE_PAL

public EVENT_MODE_PAL
Mode has changed to PAL.

EVENT_POWER_OFF

public EVENT_POWER_OFF
Machine power OFF.

EVENT_POWER_ON

public EVENT_POWER_ON
Machine power ON.

EVENT_RESET_HARD

public EVENT_RESET_HARD
Machine hard-reset.

EVENT_RESET_SOFT

public EVENT_RESET_SOFT
Machine soft-reset.

EVENT_UNLOAD

public EVENT_UNLOAD
An image has been unloaded from the system.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Machine..EventCallback.html000066400000000000000000000102361411157722000247630ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Machine::EventCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Machine::EventCallback

Machine event callback prototype.

Parameters:
userData - optional user data
event - the event
result - result code of event operation, in success or warning state



Details

EventCallback

public typedef void( NST_CALLBACK* EventCallback )( UserData userData, Event event, Result result );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Machine..EventCaller.html000066400000000000000000000114521411157722000244720ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Machine::EventCaller
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Machine::EventCaller

Core::UserCallback
   |
   +--Nes::Api::Machine::EventCaller


struct Nes::Api::Machine::EventCaller
extends Core::UserCallback

Machine event callback invoker. Used internally by the core.


Method Summary
 void operator()( Event event, Result result = RESULT_OK ) const
          
 

Method Detail

operator()

public void operator()( Event event, Result result = RESULT_OK ) const;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Machine..FavoredSystem.html000066400000000000000000000136341411157722000250650ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Machine::FavoredSystem
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Machine::FavoredSystem

Favored System. Used for telling what console to emulate if the core can't decide by itself.


Field Summary
FAVORED_DENDY = Core : : FAVORED_DENDY
          Dendy (clone).
FAVORED_FAMICOM = Core : : FAVORED_FAMICOM
          Famicom.
FAVORED_NES_NTSC = Core : : FAVORED_NES_NTSC
          NES NTSC.
FAVORED_NES_PAL = Core : : FAVORED_NES_PAL
          NES PAL.
 

Field Detail

FAVORED_DENDY

public FAVORED_DENDY = Core : : FAVORED_DENDY
Dendy (clone).

FAVORED_FAMICOM

public FAVORED_FAMICOM = Core : : FAVORED_FAMICOM
Famicom.

FAVORED_NES_NTSC

public FAVORED_NES_NTSC = Core : : FAVORED_NES_NTSC
NES NTSC.

FAVORED_NES_PAL

public FAVORED_NES_PAL = Core : : FAVORED_NES_PAL
NES PAL.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Machine..Mode.html000066400000000000000000000110361411157722000231500ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Machine::Mode
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Machine::Mode

NTSC/PAL mode.


Field Summary
NTSC = 0x04
          NTSC.
PAL = 0x08
          PAL.
 

Field Detail

NTSC

public NTSC = 0x04
NTSC.

PAL

public PAL = 0x08
PAL.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Machine..Patch.html000066400000000000000000000160051411157722000233240ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Machine::Patch
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Machine::Patch


struct Nes::Api::Machine::Patch

Soft-patching context object. Used as input parameter to some of the image loading methods.


Field Summary
 bool bypassChecksum
          Set to true to bypass checksum validation.
 Result result
          Will contain the result of the operation after the image has been loaded.
 std::istream& stream
          Input stream containing the patch in UPS or IPS format.
 
Constructor Summary
Patch( std::istream& s, bool b = false )
          Constructor.
 

Field Detail

bypassChecksum

public bool bypassChecksum;
Set to true to bypass checksum validation.

result

public Result result;
Will contain the result of the operation after the image has been loaded.

stream

public std::istream& stream;
Input stream containing the patch in UPS or IPS format.


Constructor Detail

Patch

public Patch( std::istream& s, bool b = false );
Constructor.
Parameters:
s - input stream
b - true to bypass checksum validation, default is false

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Machine.html000066400000000000000000000627601411157722000222210ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Machine
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Class Nes::Api::Machine

Base
   |
   +--Nes::Api::Machine


class Nes::Api::Machine
extends Base

Machine interface.


Inner Classes, Typedefs, and Enums
enum Nes::Api::Machine::AskProfile
          Image profile questioning state.
enum Nes::Api::Machine::Compression
          Internal compression on states.
enum Nes::Api::Machine::Event
          Machine events.
typedef Nes::Api::Machine::EventCallback
          Machine event callback prototype.
enum Nes::Api::Machine::FavoredSystem
          Favored System.
enum Nes::Api::Machine::Mode
          NTSC/PAL mode.
struct Nes::Api::Machine::Patch
          Soft-patching context object.
 
Field Summary
 static Nes::Api::Machine::EventCaller eventCallback
          Machine event callback manager.
 
Constructor Summary
Machine( T& instance )
          Interface constructor.
 
Method Summary
 Nes::Api::Machine::Mode GetDesiredMode() const
          Returns the mode most appropriate for the current image.
 Nes::Api::Machine::Mode GetMode() const
          Returns the current mode.
 bool Is( uint flags1, uint flags2 ) const
          Returns a machine state.
 uint Is( uint flags ) const
          Returns a machine state.
 bool IsLocked() const
          Tells if the machine is in a locked state.
 Result Load( std::istream& stream, Nes::Api::Machine::FavoredSystem system, Nes::Api::Machine::Patch& patch, Nes::Api::Machine::AskProfile askProfile = DONT_ASK_PROFILE )
          Loads any image.
 Result Load( std::istream& stream, Nes::Api::Machine::FavoredSystem system, Nes::Api::Machine::AskProfile askProfile = DONT_ASK_PROFILE )
          Loads any image.
 Result LoadCartridge( std::istream& stream, Nes::Api::Machine::FavoredSystem system, Nes::Api::Machine::Patch& patch, Nes::Api::Machine::AskProfile askProfile = DONT_ASK_PROFILE )
          Loads a cartridge image.
 Result LoadCartridge( std::istream& stream, Nes::Api::Machine::FavoredSystem system, Nes::Api::Machine::AskProfile askProfile = DONT_ASK_PROFILE )
          Loads a cartridge image.
 Result LoadDisk( std::istream& stream, Nes::Api::Machine::FavoredSystem system )
          Loads a Famicom Disk System image.
 Result LoadSound( std::istream& stream, Nes::Api::Machine::FavoredSystem system )
          Loads a sound image.
 Result LoadState( std::istream& stream )
          Loads a state.
 Result Power( bool state )
          Powers ON or OFF the machine.
 Result Reset( bool state )
          Resets the machine.
 Result SaveState( std::ostream& stream, Nes::Api::Machine::Compression compression = USE_COMPRESSION ) const
          Saves a state.
 Result SetMode( Nes::Api::Machine::Mode mode )
          Sets the mode.
 Result Unload()
          Unloads the current image.
 

Field Detail

eventCallback

public static Nes::Api::Machine::EventCaller eventCallback;
Machine event callback manager. Static object used for adding the user defined callback.


Constructor Detail

Machine

public Machine( T& instance );
Interface constructor.
Parameters:
instance - emulator instance


Method Detail

GetDesiredMode

public Nes::Api::Machine::Mode GetDesiredMode() const throw();
Returns the mode most appropriate for the current image.
Returns:
mode

GetMode

public Nes::Api::Machine::Mode GetMode() const throw();
Returns the current mode.
Returns:
mode

Is

public bool Is( uint flags1, uint flags2 ) const throw();
Returns a machine state.
Parameters:
flags1 - OR:ed flags to check
flags2 - OR:ed flags to check
Returns:
true if both parameters has at least one flag evaluated to true

Is

public uint Is( uint flags ) const throw();
Returns a machine state.
Parameters:
flags - OR:ed flags to check
Returns:
OR:ed flags evaluated to true

IsLocked

public bool IsLocked() const;
Tells if the machine is in a locked state. A locked state means that the machine can't respond to certain operations because it's doing something special, like playing a movie or rewinding.
Returns:
true if machine is in a locked state.

Load

public Result Load( std::istream& stream, Nes::Api::Machine::FavoredSystem system, Nes::Api::Machine::Patch& patch, Nes::Api::Machine::AskProfile askProfile = DONT_ASK_PROFILE ) throw();
Loads any image. Input stream can be in XML, iNES, UNIF, FDS or NSF format.
Parameters:
stream - input stream containing the image to load
system - console to emulate if the core can't do automatic detection
patch - object for performing soft-patching on the image
askProfile - to allow callback triggering if the image has multiple media profiles, default is false
Returns:
result code

Load

public Result Load( std::istream& stream, Nes::Api::Machine::FavoredSystem system, Nes::Api::Machine::AskProfile askProfile = DONT_ASK_PROFILE ) throw();
Loads any image. Input stream can be in XML, iNES, UNIF, FDS or NSF format.
Parameters:
stream - input stream containing the image to load
system - console to emulate if the core can't do automatic detection
askProfile - to allow callback triggering if the image has multiple media profiles, default is false
Returns:
result code

LoadCartridge

public Result LoadCartridge( std::istream& stream, Nes::Api::Machine::FavoredSystem system, Nes::Api::Machine::Patch& patch, Nes::Api::Machine::AskProfile askProfile = DONT_ASK_PROFILE ) throw();
Loads a cartridge image. Input stream can be in XML, iNES or UNIF format.
Parameters:
stream - input stream containing the image to load
system - console to emulate if the core can't do automatic detection
patch - object for performing soft-patching on the image
askProfile - to allow callback triggering if the image has multiple media profiles, default is false
Returns:
result code

LoadCartridge

public Result LoadCartridge( std::istream& stream, Nes::Api::Machine::FavoredSystem system, Nes::Api::Machine::AskProfile askProfile = DONT_ASK_PROFILE ) throw();
Loads a cartridge image. Input stream can be in XML, iNES or UNIF format.
Parameters:
stream - input stream containing the image to load
system - console to emulate if the core can't do automatic detection
askProfile - to allow callback triggering if the image has multiple media profiles, default is false
Returns:
result code

LoadDisk

public Result LoadDisk( std::istream& stream, Nes::Api::Machine::FavoredSystem system ) throw();
Loads a Famicom Disk System image. Input stream can be in FDS format.
Parameters:
stream - input stream containing the image to load
system - console to emulate if the core can't do automatic detection
Returns:
result code

LoadSound

public Result LoadSound( std::istream& stream, Nes::Api::Machine::FavoredSystem system ) throw();
Loads a sound image. Input stream can be in NSF format.
Parameters:
stream - input stream containing the image to load
system - console to emulate if the core can't do automatic detection
Returns:
result code

LoadState

public Result LoadState( std::istream& stream ) throw();
Loads a state.
Parameters:
stream - input stream containing the state
Returns:
result code

Power

public Result Power( bool state ) throw();
Powers ON or OFF the machine.
Parameters:
state - ON if true
Returns:
result code

Reset

public Result Reset( bool state ) throw();
Resets the machine.
Parameters:
state - hard-reset if true, soft-reset otherwise
Returns:
result code

SaveState

public Result SaveState( std::ostream& stream, Nes::Api::Machine::Compression compression = USE_COMPRESSION ) const throw();
Saves a state.
Parameters:
stream - output stream which the state will be written to
compression - to allow internal compression in the state, default is USE_COMPRESSION
Returns:
result code

SetMode

public Result SetMode( Nes::Api::Machine::Mode mode ) throw();
Sets the mode.
Parameters:
mode - new mode
Returns:
result code

Unload

public Result Unload() throw();
Unloads the current image.
Returns:
result code

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Movie..Event.html000066400000000000000000000131561411157722000230650ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Movie::Event
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Movie::Event

Movie event.


Field Summary
EVENT_PLAYING
          Movie has started playing.
EVENT_PLAYING_STOPPED
          Movie has stopped playing.
EVENT_RECORDING
          Movie has started recording.
EVENT_RECORDING_STOPPED
          Movie has stopped recording.
 

Field Detail

EVENT_PLAYING

public EVENT_PLAYING
Movie has started playing.

EVENT_PLAYING_STOPPED

public EVENT_PLAYING_STOPPED
Movie has stopped playing.

EVENT_RECORDING

public EVENT_RECORDING
Movie has started recording.

EVENT_RECORDING_STOPPED

public EVENT_RECORDING_STOPPED
Movie has stopped recording.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Movie..EventCallback.html000066400000000000000000000101611411157722000244730ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Movie::EventCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Movie::EventCallback

Movie event callback prototype.

Parameters:
userData - optional user data
event - type of event
result - result code of event



Details

EventCallback

public typedef void( NST_CALLBACK* EventCallback )( UserData userData, Event event, Result result );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Movie..EventCaller.html000066400000000000000000000114321411157722000242030ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Movie::EventCaller
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Movie::EventCaller

Core::UserCallback
   |
   +--Nes::Api::Movie::EventCaller


struct Nes::Api::Movie::EventCaller
extends Core::UserCallback

Movie event callback invoker. Used internally by the core.


Method Summary
 void operator()( Event event, Result result = RESULT_OK ) const
          
 

Method Detail

operator()

public void operator()( Event event, Result result = RESULT_OK ) const;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Movie..How.html000066400000000000000000000111641411157722000225360ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Movie::How
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Movie::How

Recording procedure.


Field Summary
APPEND
          Keep any previous content.
CLEAN
          Overwrite any previous content.
 

Field Detail

APPEND

public APPEND
Keep any previous content.

CLEAN

public CLEAN
Overwrite any previous content.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Movie.html000066400000000000000000000302761411157722000217310ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Movie
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Class Nes::Api::Movie

Base
   |
   +--Nes::Api::Movie


class Nes::Api::Movie
extends Base

Movie playing/recording interface.


Inner Classes, Typedefs, and Enums
enum Nes::Api::Movie::Event
          Movie event.
typedef Nes::Api::Movie::EventCallback
          Movie event callback prototype.
enum Nes::Api::Movie::How
          Recording procedure.
 
Field Summary
 static Nes::Api::Movie::EventCaller eventCallback
          Movie event callback manager.
 
Constructor Summary
Movie( T& instance )
          Interface constructor.
 
Method Summary
 void Eject()
          Deprecated. @deprecated
 bool IsPlaying() const
          Checks if a movie is being played.
 bool IsRecording() const
          Checks if a movie is being recorded.
 bool IsStopped() const
          Checks if a movie has stopped playing or recording.
 Result Play( std::istream& stream )
          Plays movie.
 Result Record( std::iostream& stream, Nes::Api::Movie::How how = CLEAN )
          Records movie.
 void Stop()
          Stops movie.
 

Field Detail

eventCallback

public static Nes::Api::Movie::EventCaller eventCallback;
Movie event callback manager. Static object used for adding the user defined callback.


Constructor Detail

Movie

public Movie( T& instance );
Interface constructor.
Parameters:
instance - emulator instance


Method Detail

Eject

public void Eject();
Deprecated. @deprecated

Ejects movie.


IsPlaying

public bool IsPlaying() const throw();
Checks if a movie is being played.
Returns:
true if playing

IsRecording

public bool IsRecording() const throw();
Checks if a movie is being recorded.
Returns:
true if recording

IsStopped

public bool IsStopped() const throw();
Checks if a movie has stopped playing or recording.
Returns:
true if stopped

Play

public Result Play( std::istream& stream ) throw();
Plays movie.
Parameters:
stream - input stream to movie
Returns:
result code

Record

public Result Record( std::iostream& stream, Nes::Api::Movie::How how = CLEAN ) throw();
Records movie.
Parameters:
stream - stream to record movie to
how - CLEAN to erase any previous content, APPEND to keep content, default is CLEAN
Returns:
result code

Stop

public void Stop() throw();
Stops movie.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Nsf..Event.html000066400000000000000000000121111411157722000225220ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Nsf::Event
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Nsf::Event

Event.


Field Summary
EVENT_PLAY_SONG
          
EVENT_SELECT_SONG
          A new song has been selected.
EVENT_STOP_SONG
          Song has stopped playing.
 

Field Detail

EVENT_PLAY_SONG

public EVENT_PLAY_SONG

EVENT_SELECT_SONG

public EVENT_SELECT_SONG
A new song has been selected.

EVENT_STOP_SONG

public EVENT_STOP_SONG
Song has stopped playing.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Nsf..EventCallback.html000066400000000000000000000100431411157722000241410ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Nsf::EventCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Nsf::EventCallback

Event callback prototype.

Parameters:
userData - optional user data
event - type of event



Details

EventCallback

public typedef void( NST_CALLBACK* EventCallback )( UserData userData, Event event );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Nsf..EventCaller.html000066400000000000000000000113071411157722000236530ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Nsf::EventCaller
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Nsf::EventCaller

Core::UserCallback
   |
   +--Nes::Api::Nsf::EventCaller


struct Nes::Api::Nsf::EventCaller
extends Core::UserCallback

Song event callback invoker. Used internally by the core.


Method Summary
 void operator()( Event event ) const
          
 

Method Detail

operator()

public void operator()( Event event ) const;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Nsf..TuneMode.html000066400000000000000000000120251411157722000231650ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Nsf::TuneMode
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Nsf::TuneMode

Tune mode.


Field Summary
TUNE_MODE_BOTH
          Both NTSC and PAL.
TUNE_MODE_NTSC
          NTSC only.
TUNE_MODE_PAL
          PAL only.
 

Field Detail

TUNE_MODE_BOTH

public TUNE_MODE_BOTH
Both NTSC and PAL.

TUNE_MODE_NTSC

public TUNE_MODE_NTSC
NTSC only.

TUNE_MODE_PAL

public TUNE_MODE_PAL
PAL only.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Nsf.html000066400000000000000000000452621411157722000214010ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Nsf
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Class Nes::Api::Nsf

Base
   |
   +--Nes::Api::Nsf


class Nes::Api::Nsf
extends Base

NES Sound Files interface.


Inner Classes, Typedefs, and Enums
enum Nes::Api::Nsf::Event
          Event.
typedef Nes::Api::Nsf::EventCallback
          Event callback prototype.
enum Nes::Api::Nsf::TuneMode
          Tune mode.
 
Field Summary
 static Nes::Api::Nsf::EventCaller eventCallback
          Event callback manager.
 
Constructor Summary
Nsf( T& instance )
          Interface constructor.
 
Method Summary
 const char* GetArtist() const
          Returns the name of the artists.
 uint GetChips() const
          Returns the OR:ed chips in use.
 const char* GetCopyright() const
          Returns the copyright string.
 int GetCurrentSong() const
          Returns the current song index.
 uint GetInitAddress() const
          Returns the init-address.
 uint GetLoadAddress() const
          Returns the load-address.
 Nes::Api::Nsf::TuneMode GetMode() const
          Return the tune mode.
 const char* GetName() const
          Returns the name of the NSF.
 uint GetNumSongs() const
          Returns the total number of songs.
 uint GetPlayAddress() const
          Returns the play-address.
 int GetStartingSong() const
          Returns the starting song index.
 bool IsPlaying() const
          Checks if a song is currently being played.
 Result PlaySong()
          Plays current selected song.
 Result SelectNextSong()
          Selects the next song.
 Result SelectPrevSong()
          Selects the previous song.
 Result SelectSong( uint song )
          Selects a song.
 Result StopSong()
          Stops current selected song.
 bool UsesBankSwitching() const
          Checks if the NSF uses bank-switching.
 

Field Detail

eventCallback

public static Nes::Api::Nsf::EventCaller eventCallback;
Event callback manager. Static object used for adding the user defined callback.


Constructor Detail

Nsf

public Nsf( T& instance );
Interface constructor.
Parameters:
instance - emulator instance


Method Detail

GetArtist

public const char* GetArtist() const throw();
Returns the name of the artists.
Returns:
artist names or empty string if NSF hasn't been loaded

GetChips

public uint GetChips() const throw();
Returns the OR:ed chips in use.
Returns:
OR:ed chips used

GetCopyright

public const char* GetCopyright() const throw();
Returns the copyright string.
Returns:
copyright or empty string if NSF hasn't been loaded

GetCurrentSong

public int GetCurrentSong() const throw();
Returns the current song index.
Returns:
song index or NO_SONG if NSF hasn't been loaded

GetInitAddress

public uint GetInitAddress() const throw();
Returns the init-address.
Returns:
address

GetLoadAddress

public uint GetLoadAddress() const throw();
Returns the load-address.
Returns:
address

GetMode

public Nes::Api::Nsf::TuneMode GetMode() const throw();
Return the tune mode.
Returns:
tune mode

GetName

public const char* GetName() const throw();
Returns the name of the NSF.
Returns:
name or empty string if NSF hasn't been loaded

GetNumSongs

public uint GetNumSongs() const throw();
Returns the total number of songs.
Returns:
number

GetPlayAddress

public uint GetPlayAddress() const throw();
Returns the play-address.
Returns:
address

GetStartingSong

public int GetStartingSong() const throw();
Returns the starting song index.
Returns:
song index or NO_SONG if NSF hasn't been loaded

IsPlaying

public bool IsPlaying() const throw();
Checks if a song is currently being played.
Returns:
true if playing

PlaySong

public Result PlaySong() throw();
Plays current selected song.
Returns:
result code

SelectNextSong

public Result SelectNextSong() throw();
Selects the next song.
Returns:
result code

SelectPrevSong

public Result SelectPrevSong() throw();
Selects the previous song.
Returns:
result code

SelectSong

public Result SelectSong( uint song ) throw();
Selects a song.
Parameters:
song - index
Returns:
result code

StopSong

public Result StopSong() throw();
Stops current selected song.
Returns:
result code

UsesBankSwitching

public bool UsesBankSwitching() const throw();
Checks if the NSF uses bank-switching.
Returns:
true if NSF uses bank-switching

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Rewinder..Direction.html000066400000000000000000000111261411157722000244170ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Rewinder::Direction
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Rewinder::Direction

Direction.


Field Summary
BACKWARD
          Backward.
FORWARD
          Forward.
 

Field Detail

BACKWARD

public BACKWARD
Backward.

FORWARD

public FORWARD
Forward.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Rewinder..State.html000066400000000000000000000120001411157722000235470ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Rewinder::State
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Rewinder::State

Rewinder state.


Field Summary
PREPARING
          Rewinding will soon start.
REWINDING
          Rewinding has begun.
STOPPED
          Rewinding has stopped.
 

Field Detail

PREPARING

public PREPARING
Rewinding will soon start.

REWINDING

public REWINDING
Rewinding has begun.

STOPPED

public STOPPED
Rewinding has stopped.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Rewinder..StateCallback.html000066400000000000000000000101001411157722000251630ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Rewinder::StateCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Rewinder::StateCallback

Rewinder state callback prototype.

Parameters:
userData - optional user data
state - type of state



Details

StateCallback

public typedef void( NST_CALLBACK* StateCallback )( UserData userData, State state );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Rewinder..StateCaller.html000066400000000000000000000113561411157722000247070ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Rewinder::StateCaller
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Rewinder::StateCaller

Core::UserCallback
   |
   +--Nes::Api::Rewinder::StateCaller


struct Nes::Api::Rewinder::StateCaller
extends Core::UserCallback

Rewinder state callback invoker. Used internally by the core.


Method Summary
 void operator()( State state ) const
          
 

Method Detail

operator()

public void operator()( State state ) const;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Rewinder.html000066400000000000000000000306621411157722000224300ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Rewinder
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Class Nes::Api::Rewinder

Base
   |
   +--Nes::Api::Rewinder


class Nes::Api::Rewinder
extends Base

Game rewinder interface.


Inner Classes, Typedefs, and Enums
enum Nes::Api::Rewinder::Direction
          Direction.
enum Nes::Api::Rewinder::State
          Rewinder state.
typedef Nes::Api::Rewinder::StateCallback
          Rewinder state callback prototype.
 
Field Summary
 static Nes::Api::Rewinder::StateCaller stateCallback
          Rewinder state callback manager.
 
Constructor Summary
Rewinder( T& instance )
          Interface constructor.
 
Method Summary
 Result Enable( bool state = true )
          Enables rewinder.
 void EnableSound( bool state = true )
          Enables backward sound.
 Nes::Api::Rewinder::Direction GetDirection() const
          Returns the current direction.
 bool IsEnabled() const
          Checks if rewinder is enabled.
 bool IsSoundEnabled() const
          Checks if backward sound is enabled.
 void Reset()
          Resets rewinder.
 Result SetDirection( Nes::Api::Rewinder::Direction direction )
          Sets direction.
 

Field Detail

stateCallback

public static Nes::Api::Rewinder::StateCaller stateCallback;
Rewinder state callback manager. Static object used for adding the user defined callback.


Constructor Detail

Rewinder

public Rewinder( T& instance );
Interface constructor.
Parameters:
instance - emulator instance


Method Detail

Enable

public Result Enable( bool state = true ) throw();
Enables rewinder.
Parameters:
state - true to enable
Returns:
result code

EnableSound

public void EnableSound( bool state = true ) throw();
Enables backward sound.
Parameters:
state - true to enable

GetDirection

public Nes::Api::Rewinder::Direction GetDirection() const throw();
Returns the current direction.
Returns:
current direction

IsEnabled

public bool IsEnabled() const throw();
Checks if rewinder is enabled.
Returns:
true if enabled

IsSoundEnabled

public bool IsSoundEnabled() const throw();
Checks if backward sound is enabled.
Returns:
true if enabled

Reset

public void Reset() throw();
Resets rewinder.

SetDirection

public Result SetDirection( Nes::Api::Rewinder::Direction direction ) throw();
Sets direction.
Parameters:
direction - direction, FORWARD or BACKWARD
Returns:
result code

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Sound..Channel.html000066400000000000000000000236501411157722000233650ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Sound::Channel
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Sound::Channel

Sound channel types.


Field Summary
ALL_CHANNELS = APU_CHANNELS | EXT_CHANNELS
          All channels.
APU_CHANNELS = CHANNEL_SQUARE1 | CHANNEL_SQUARE2 | CHANNEL_TRIANGLE | CHANNEL_NOISE | CHANNEL_DPCM
          All NES APU channels.
CHANNEL_DPCM = 0x010
          DPCM channel.
CHANNEL_FDS = 0x020
          FDS sound chip channel.
CHANNEL_MMC5 = 0x040
          MMC5 sound chip channel.
CHANNEL_N163 = 0x200
          Namcot 163 sound chip channel.
CHANNEL_NOISE = 0x008
          Noise channel.
CHANNEL_S5B = 0x400
          Sunsoft 5B sound chip channel.
CHANNEL_SQUARE1 = 0x001
          First square channel.
CHANNEL_SQUARE2 = 0x002
          Second square channel.
CHANNEL_TRIANGLE = 0x004
          Triangle channel.
CHANNEL_VRC6 = 0x080
          Konami VRC6 sound chip channel.
CHANNEL_VRC7 = 0x100
          Konami VRC7 sound chip channel.
EXT_CHANNELS = CHANNEL_FDS | CHANNEL_MMC5 | CHANNEL_VRC6 | CHANNEL_VRC7 | CHANNEL_N163 | CHANNEL_S5B
          All external sound chip channels.
 

Field Detail

ALL_CHANNELS

public ALL_CHANNELS = APU_CHANNELS | EXT_CHANNELS
All channels.

APU_CHANNELS

public APU_CHANNELS = CHANNEL_SQUARE1 | CHANNEL_SQUARE2 | CHANNEL_TRIANGLE | CHANNEL_NOISE | CHANNEL_DPCM
All NES APU channels.

CHANNEL_DPCM

public CHANNEL_DPCM = 0x010
DPCM channel.

CHANNEL_FDS

public CHANNEL_FDS = 0x020
FDS sound chip channel.

CHANNEL_MMC5

public CHANNEL_MMC5 = 0x040
MMC5 sound chip channel.

CHANNEL_N163

public CHANNEL_N163 = 0x200
Namcot 163 sound chip channel.

CHANNEL_NOISE

public CHANNEL_NOISE = 0x008
Noise channel.

CHANNEL_S5B

public CHANNEL_S5B = 0x400
Sunsoft 5B sound chip channel.

CHANNEL_SQUARE1

public CHANNEL_SQUARE1 = 0x001
First square channel.

CHANNEL_SQUARE2

public CHANNEL_SQUARE2 = 0x002
Second square channel.

CHANNEL_TRIANGLE

public CHANNEL_TRIANGLE = 0x004
Triangle channel.

CHANNEL_VRC6

public CHANNEL_VRC6 = 0x080
Konami VRC6 sound chip channel.

CHANNEL_VRC7

public CHANNEL_VRC7 = 0x100
Konami VRC7 sound chip channel.

EXT_CHANNELS

public EXT_CHANNELS = CHANNEL_FDS | CHANNEL_MMC5 | CHANNEL_VRC6 | CHANNEL_VRC7 | CHANNEL_N163 | CHANNEL_S5B
All external sound chip channels.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Sound..Output.html000066400000000000000000000075151411157722000233170ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Sound::Output
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Sound::Output

Sound output context.




Details

Output

public typedef Core::Sound::Output Output;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Sound..Speaker.html000066400000000000000000000112671411157722000234100ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Sound::Speaker
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Sound::Speaker

Speaker type.


Field Summary
SPEAKER_MONO
          Mono sound (default).
SPEAKER_STEREO
          Pseudo stereo sound.
 

Field Detail

SPEAKER_MONO

public SPEAKER_MONO
Mono sound (default).

SPEAKER_STEREO

public SPEAKER_STEREO
Pseudo stereo sound.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Sound.html000066400000000000000000000413351411157722000217400ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Sound
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Class Nes::Api::Sound

Base
   |
   +--Nes::Api::Sound


class Nes::Api::Sound
extends Base

Sound interface.


Inner Classes, Typedefs, and Enums
enum Nes::Api::Sound::Channel
          Sound channel types.
typedef Nes::Api::Sound::Output
          Sound output context.
enum Nes::Api::Sound::Speaker
          Speaker type.
 
Constructor Summary
Sound( T& instance )
          Interface constructor.
 
Method Summary
 void EmptyBuffer()
          Empties the internal sound buffer.
 uint GetSampleBits() const
          Returns the sample bits.
 ulong GetSampleRate() const
          Returns the sample rate.
 Nes::Api::Sound::Speaker GetSpeaker() const
          Returns the speaker type.
 uint GetSpeed() const
          Returns the current speed.
 uint GetVolume( uint channel ) const
          Returns the volume of a channel.
 bool IsAudible() const
          Checks if sound is audible at all.
 bool IsAutoTransposing() const
          Checks if automatic transposing is enabled.
 bool IsMuted() const
          Checks if sound is muted.
 void Mute( bool mute )
          Mutes all sound.
 void SetAutoTranspose( bool state )
          Enables automatic transposition.
 Result SetSampleBits( uint bits )
          Sets the sample bits.
 Result SetSampleRate( ulong rate )
          Sets the sample rate.
 void SetSpeaker( Nes::Api::Sound::Speaker speaker )
          Sets the speaker type.
 Result SetSpeed( uint speed )
          Sets the speed.
 Result SetVolume( uint channels, uint volume )
          Sets one or more channel volumes.
 

Constructor Detail

Sound

public Sound( T& instance );
Interface constructor.
Parameters:
instance - emulator instance


Method Detail

EmptyBuffer

public void EmptyBuffer() throw();
Empties the internal sound buffer.

GetSampleBits

public uint GetSampleBits() const throw();
Returns the sample bits.
Returns:
number

GetSampleRate

public ulong GetSampleRate() const throw();
Returns the sample rate.
Returns:
sample rate

GetSpeaker

public Nes::Api::Sound::Speaker GetSpeaker() const throw();
Returns the speaker type.
Returns:
speaker type

GetSpeed

public uint GetSpeed() const throw();
Returns the current speed.
Returns:
speed

GetVolume

public uint GetVolume( uint channel ) const throw();
Returns the volume of a channel.
Parameters:
channel - channel
Returns:
volume

IsAudible

public bool IsAudible() const throw();
Checks if sound is audible at all.
Returns:
true if audible

IsAutoTransposing

public bool IsAutoTransposing() const throw();
Checks if automatic transposing is enabled.
Returns:
true if enabled

IsMuted

public bool IsMuted() const throw();
Checks if sound is muted.
Returns:
true if muted

Mute

public void Mute( bool mute ) throw();
Mutes all sound.
Parameters:
mute - true to mute sound

SetAutoTranspose

public void SetAutoTranspose( bool state ) throw();
Enables automatic transposition.
Parameters:
state - true to enable

SetSampleBits

public Result SetSampleBits( uint bits ) throw();
Sets the sample bits.
Parameters:
bits - value of 8 or 16, default is 16
Returns:
result code

SetSampleRate

public Result SetSampleRate( ulong rate ) throw();
Sets the sample rate.
Parameters:
rate - value in the range 11025 to 96000, default is 44100
Returns:
result code

SetSpeaker

public void SetSpeaker( Nes::Api::Sound::Speaker speaker ) throw();
Sets the speaker type.
Parameters:
speaker - speaker type, default is SPEAKER_MONO

SetSpeed

public Result SetSpeed( uint speed ) throw();
Sets the speed.
Parameters:
speed - speed in the range 30 to 240, set to DEFAULT_SPEED for automatic adjustment
Returns:
result code

SetVolume

public Result SetVolume( uint channels, uint volume ) throw();
Sets one or more channel volumes.
Parameters:
channels - OR:ed channels
volume - volume in the range 0 to 100, default is 85
Returns:
result code

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..TapeRecorder..Event.html000066400000000000000000000121651411157722000243640ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::TapeRecorder::Event
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::TapeRecorder::Event

Tape events.


Field Summary
EVENT_PLAYING
          Tape is playing.
EVENT_RECORDING
          Tape is recording.
EVENT_STOPPED
          Tape has stopped playing or recording.
 

Field Detail

EVENT_PLAYING

public EVENT_PLAYING
Tape is playing.

EVENT_RECORDING

public EVENT_RECORDING
Tape is recording.

EVENT_STOPPED

public EVENT_STOPPED
Tape has stopped playing or recording.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..TapeRecorder..EventCallback.html000066400000000000000000000101141411157722000257710ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::TapeRecorder::EventCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::TapeRecorder::EventCallback

Tape event callback prototype.

Parameters:
userData - optional user data
event - type of event



Details

EventCallback

public typedef void( NST_CALLBACK* EventCallback )( UserData userData, Event event );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..TapeRecorder..EventCaller.html000066400000000000000000000114061411157722000255040ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::TapeRecorder::EventCaller
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::TapeRecorder::EventCaller

Core::UserCallback
   |
   +--Nes::Api::TapeRecorder::EventCaller


struct Nes::Api::TapeRecorder::EventCaller
extends Core::UserCallback

Tape event callback invoker. Used internally by the core.


Method Summary
 void operator()( Event event ) const
          
 

Method Detail

operator()

public void operator()( Event event ) const;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..TapeRecorder.html000066400000000000000000000302101411157722000232150ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::TapeRecorder
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Class Nes::Api::TapeRecorder

Base
   |
   +--Nes::Api::TapeRecorder


class Nes::Api::TapeRecorder
extends Base

Tape interface.


Inner Classes, Typedefs, and Enums
enum Nes::Api::TapeRecorder::Event
          Tape events.
typedef Nes::Api::TapeRecorder::EventCallback
          Tape event callback prototype.
 
Field Summary
 static Nes::Api::TapeRecorder::EventCaller eventCallback
          Tape event callback manager.
 
Constructor Summary
TapeRecorder( T& instance )
          Interface constructor.
 
Method Summary
 bool IsConnected() const
          Checks if a tape recorder is connected.
 bool IsPlayable() const
          Checks if tape can be played
 bool IsPlaying() const
          Checks if tape is playing.
 bool IsRecording() const
          Checks if tape is recording.
 bool IsStopped() const
          Checks if tape has stopped playing or recording.
 Result Play()
          Plays tape.
 Result Record()
          Records tape.
 Result Stop()
          Stops tape.
 

Field Detail

eventCallback

public static Nes::Api::TapeRecorder::EventCaller eventCallback;
Tape event callback manager. Static object used for adding the user defined callback.


Constructor Detail

TapeRecorder

public TapeRecorder( T& instance );
Interface constructor.
Parameters:
instance - emulator instance


Method Detail

IsConnected

public bool IsConnected() const throw();
Checks if a tape recorder is connected.
Parameters:
true - connected

IsPlayable

public bool IsPlayable() const throw();
Checks if tape can be played
Returns:
true if playable

IsPlaying

public bool IsPlaying() const throw();
Checks if tape is playing.
Returns:
true if playing

IsRecording

public bool IsRecording() const throw();
Checks if tape is recording.
Returns:
true if recording

IsStopped

public bool IsStopped() const throw();
Checks if tape has stopped playing or recording.
Returns:
true if stopped

Play

public Result Play() throw();
Plays tape.
Returns:
result code

Record

public Result Record() throw();
Records tape.
Returns:
result code

Stop

public Result Stop() throw();
Stops tape.
Returns:
result code

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..User..Answer.html000066400000000000000000000117311411157722000230770ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::User::Answer
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::User::Answer

User answer.


Field Summary
ANSWER_DEFAULT
          Default answer (default).
ANSWER_NO
          No.
ANSWER_YES
          Yes.
 

Field Detail

ANSWER_DEFAULT

public ANSWER_DEFAULT
Default answer (default).

ANSWER_NO

public ANSWER_NO
No.

ANSWER_YES

public ANSWER_YES
Yes.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..User..Event.html000066400000000000000000000123171411157722000227220ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::User::Event
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::User::Event

User events.


Field Summary
EVENT_CPU_JAM = 1
          CPU jam.
EVENT_CPU_UNOFFICIAL_OPCODE
          An unofficial CPU opcode was executed.
EVENT_DISPLAY_TIMER
          Can display an in-game timer.
 

Field Detail

EVENT_CPU_JAM

public EVENT_CPU_JAM = 1
CPU jam.

EVENT_CPU_UNOFFICIAL_OPCODE

public EVENT_CPU_UNOFFICIAL_OPCODE
An unofficial CPU opcode was executed.

EVENT_DISPLAY_TIMER

public EVENT_DISPLAY_TIMER
Can display an in-game timer.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..User..EventCallback.html000066400000000000000000000101661411157722000243370ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::User::EventCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::User::EventCallback

Logfile callback prototype.

Parameters:
userData - optional user data
event - type of event
context - context depending on event



Details

EventCallback

public typedef void( NST_CALLBACK* EventCallback )( UserData userData, Event event, const void* context );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..User..EventCaller.html000066400000000000000000000114201411157722000240370ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::User::EventCaller
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::User::EventCaller

Core::UserCallback
   |
   +--Nes::Api::User::EventCaller


struct Nes::Api::User::EventCaller
extends Core::UserCallback

User event callback invoker. Used internally by the core.


Method Summary
 void operator()( Event event, const void* data = 0 ) const
          
 

Method Detail

operator()

public void operator()( Event event, const void* data = 0 ) const;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..User..File..Action.html000066400000000000000000000273061411157722000240160ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::User::File::Action
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::User::File::Action

Action event.


Field Summary
LOAD_BATTERY = 1
          For loading battery-backed RAM into a cartridge.
LOAD_EEPROM
          For loading EEPROM into a cartridge.
LOAD_FDS
          For patching a Famicom Disk System image.
LOAD_ROM
          For loading ROM into a cartridge.
LOAD_SAMPLE
          For loading raw PCM audio samples.
LOAD_SAMPLE_AEROBICS_STUDIO
          For loading raw PCM audio samples used in Aerobics Studio.
LOAD_SAMPLE_MOERO_PRO_TENNIS
          For loading raw PCM audio samples used in Moero Pro Tennis.
LOAD_SAMPLE_MOERO_PRO_YAKYUU
          For loading raw PCM audio samples used in Moero Pro Yakyuu.
LOAD_SAMPLE_MOERO_PRO_YAKYUU_88
          For loading raw PCM audio samples used in Moero Pro Yakyuu 88.
LOAD_SAMPLE_TERAO_NO_DOSUKOI_OOZUMOU
          For loading raw PCM audio samples used in Terao No Dosukoi Oozumou.
LOAD_TAPE
          For loading cassette tape recording.
LOAD_TURBOFILE
          For loading Turbo File device data.
SAVE_BATTERY
          For saving the battery-backed RAM in a cartridge.
SAVE_EEPROM
          For saving the EEPROM in a cartridge.
SAVE_FDS
          For saving a modified Famicom Disk System image to patch or directly to image.
SAVE_TAPE
          For saving the cassette tape recording.
SAVE_TURBOFILE
          For saving Turbo File device data.
 

Field Detail

LOAD_BATTERY

public LOAD_BATTERY = 1
For loading battery-backed RAM into a cartridge.

LOAD_EEPROM

public LOAD_EEPROM
For loading EEPROM into a cartridge.

LOAD_FDS

public LOAD_FDS
For patching a Famicom Disk System image.

LOAD_ROM

public LOAD_ROM
For loading ROM into a cartridge.

LOAD_SAMPLE

public LOAD_SAMPLE
For loading raw PCM audio samples.

LOAD_SAMPLE_AEROBICS_STUDIO

public LOAD_SAMPLE_AEROBICS_STUDIO
For loading raw PCM audio samples used in Aerobics Studio.

LOAD_SAMPLE_MOERO_PRO_TENNIS

public LOAD_SAMPLE_MOERO_PRO_TENNIS
For loading raw PCM audio samples used in Moero Pro Tennis.

LOAD_SAMPLE_MOERO_PRO_YAKYUU

public LOAD_SAMPLE_MOERO_PRO_YAKYUU
For loading raw PCM audio samples used in Moero Pro Yakyuu.

LOAD_SAMPLE_MOERO_PRO_YAKYUU_88

public LOAD_SAMPLE_MOERO_PRO_YAKYUU_88
For loading raw PCM audio samples used in Moero Pro Yakyuu 88.

LOAD_SAMPLE_TERAO_NO_DOSUKOI_OOZUMOU

public LOAD_SAMPLE_TERAO_NO_DOSUKOI_OOZUMOU
For loading raw PCM audio samples used in Terao No Dosukoi Oozumou.

LOAD_TAPE

public LOAD_TAPE
For loading cassette tape recording.

LOAD_TURBOFILE

public LOAD_TURBOFILE
For loading Turbo File device data.

SAVE_BATTERY

public SAVE_BATTERY
For saving the battery-backed RAM in a cartridge.

SAVE_EEPROM

public SAVE_EEPROM
For saving the EEPROM in a cartridge.

SAVE_FDS

public SAVE_FDS
For saving a modified Famicom Disk System image to patch or directly to image.

SAVE_TAPE

public SAVE_TAPE
For saving the cassette tape recording.

SAVE_TURBOFILE

public SAVE_TURBOFILE
For saving Turbo File device data.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..User..File..Patch.html000066400000000000000000000111341411157722000236300ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::User::File::Patch
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::User::File::Patch

Supported patch formats.


Field Summary
PATCH_IPS
          IPS.
PATCH_UPS
          UPS.
 

Field Detail

PATCH_IPS

public PATCH_IPS
IPS.

PATCH_UPS

public PATCH_UPS
UPS.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..User..File.html000066400000000000000000000342301411157722000225160ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::User::File
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::User::File


struct Nes::Api::User::File

File IO interface.


Inner Classes, Typedefs, and Enums
enum Nes::Api::User::File::Action
          Action event.
enum Nes::Api::User::File::Patch
          Supported patch formats.
 
Method Summary
 virtual Nes::Api::User::File::Action GetAction() const = 0
          Returns type of action.
 virtual Result GetContent( const void*& mem, ulong& size ) const
          Returns a pointer to the content to be saved and its size.
 virtual Result GetContent( std::ostream& stream ) const
          Saves the content into an output stream.
 virtual uint GetId() const
          Returns the sound file ID to load.
 virtual ulong GetMaxSize() const
          Returns the maximum allowed size for the content to load.
 virtual const wchar_t* GetName() const
          Returns the name of the file to load.
 virtual Result GetPatchContent( Nes::Api::User::File::Patch patch, std::ostream& stream ) const
          Saves the patch content into an output stream.
 virtual Result SetContent( const void* mem, ulong size )
          Loads content into the core.
 virtual Result SetContent( std::istream& stream )
          Loads content into the core through stream.
 virtual Result SetPatchContent( std::istream& stream )
          Loads patch content into the core.
 virtual Result SetSampleContent( const void* mem, ulong length, bool stereo, uint bits, ulong rate )
          Loads audio content into the core.
 

Method Detail

GetAction

public virtual Nes::Api::User::File::Action GetAction() const throw()= 0;
Returns type of action.
Returns:
action

GetContent

public virtual Result GetContent( const void*& mem, ulong& size ) const throw();
Returns a pointer to the content to be saved and its size. Used only with the SAVE_xx action callbacks.
Parameters:
mem - pointer to content
size - size of content
result - code

GetContent

public virtual Result GetContent( std::ostream& stream ) const throw();
Saves the content into an output stream. Used only with the SAVE_xx action callbacks.
Parameters:
stream - output stream
result - code

GetId

public virtual uint GetId() const throw();
Returns the sound file ID to load. Used only with the LOAD_SAMPLE_xx action callbacks.
Returns:
sample id

GetMaxSize

public virtual ulong GetMaxSize() const throw();
Returns the maximum allowed size for the content to load. Used only with the LOAD_xx action callbacks.
Returns:
max size

GetName

public virtual const wchar_t* GetName() const throw();
Returns the name of the file to load. Used only with the LOAD_ROM and LOAD_SAMPLE action callbacks.
Returns:
filename

GetPatchContent

public virtual Result GetPatchContent( Nes::Api::User::File::Patch patch, std::ostream& stream ) const throw();
Saves the patch content into an output stream. Used only with the FDS_SAVE action callback.
Parameters:
patch - patch format to use
stream - output stream

SetContent

public virtual Result SetContent( const void* mem, ulong size ) throw();
Loads content into the core. Used only with the LOAD_xx action callbacks. This method can't be used for audio or patch content. Instead, use LoadSampleContent(..) and SetPatchContent(..) for those.
Parameters:
mem - content
size - size of content
Returns:
result code

SetContent

public virtual Result SetContent( std::istream& stream ) throw();
Loads content into the core through stream. Used only with the LOAD_xx action callbacks. This method can't be used for audio or patch content. Instead, use LoadSampleContent(..) and SetPatchContent(..) for those.
Parameters:
stream - input stream
Returns:
result code

SetPatchContent

public virtual Result SetPatchContent( std::istream& stream ) throw();
Loads patch content into the core. Used only with LOAD_FDS action callback.
Parameters:
stream - input stream to patch
Returns:
result code

SetSampleContent

public virtual Result SetSampleContent( const void* mem, ulong length, bool stereo, uint bits, ulong rate ) throw();
Loads audio content into the core. Used only with the LOAD_SAMPLE and LOAD_SAMPLE_xx action callbacks.
Parameters:
mem - sample content
length - number of samples
stereo - dual channel if true
bits - bits per sample
rate - sample rate
Returns:
result code

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..User..FileIoCallback.html000066400000000000000000000100631411157722000244210ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::User::FileIoCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::User::FileIoCallback

File IO callback prototype.

Parameters:
userData - optional user data
file - File IO interface



Details

FileIoCallback

public typedef void( NST_CALLBACK* FileIoCallback )( UserData userData, File& file );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..User..FileIoCaller.html000066400000000000000000000113171411157722000241320ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::User::FileIoCaller
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::User::FileIoCaller

Core::UserCallback
   |
   +--Nes::Api::User::FileIoCaller


struct Nes::Api::User::FileIoCaller
extends Core::UserCallback

File IO callback invoker. Used internally by the core.


Method Summary
 void operator()( File& file ) const
          
 

Method Detail

operator()

public void operator()( File& file ) const;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..User..LogCallback.html000066400000000000000000000101321411157722000237700ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::User::LogCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::User::LogCallback

Logfile callback prototype.

Parameters:
userData - optional user data
string - string content
length - string length



Details

LogCallback

public typedef void( NST_CALLBACK* LogCallback )( UserData userData, const char* string, ulong length );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..User..LogCaller.html000066400000000000000000000124221411157722000235020ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::User::LogCaller
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::User::LogCaller

Core::UserCallback
   |
   +--Nes::Api::User::LogCaller


struct Nes::Api::User::LogCaller
extends Core::UserCallback

Logfile callback invoker. Used internally by the core.


Method Summary
 void operator()( const char(& c )[ N] ) const
          
 void operator()( const char* text, ulong length ) const
          
 

Method Detail

operator()

public void operator()( const char(& c )[ N] ) const;

operator()

public void operator()( const char* text, ulong length ) const;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..User..Question.html000066400000000000000000000122271411157722000234500ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::User::Question
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::User::Question

User questions.


Field Summary
QUESTION_NST_PRG_CRC_FAIL_CONTINUE = 1
          Whether to proceed or abort if CRC validation fails when loading a save state.
QUESTION_NSV_PRG_CRC_FAIL_CONTINUE
          Whether to proceed or abort if CRC validation fails when playing a move.
 

Field Detail

QUESTION_NST_PRG_CRC_FAIL_CONTINUE

public QUESTION_NST_PRG_CRC_FAIL_CONTINUE = 1
Whether to proceed or abort if CRC validation fails when loading a save state.

QUESTION_NSV_PRG_CRC_FAIL_CONTINUE

public QUESTION_NSV_PRG_CRC_FAIL_CONTINUE
Whether to proceed or abort if CRC validation fails when playing a move.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..User..QuestionCallback.html000066400000000000000000000102001411157722000250520ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::User::QuestionCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::User::QuestionCallback

User question callback prototype.

Parameters:
userData - optional user data
question - type of question
Returns:
user answer



Details

QuestionCallback

public typedef Answer( NST_CALLBACK* QuestionCallback )( UserData userData, Question question );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..User..QuestionCaller.html000066400000000000000000000113711411157722000245720ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::User::QuestionCaller
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::User::QuestionCaller

Core::UserCallback
   |
   +--Nes::Api::User::QuestionCaller


struct Nes::Api::User::QuestionCaller
extends Core::UserCallback

User question callback invoker. Used internally by the core.


Method Summary
 Answer operator()( Question question ) const
          
 

Method Detail

operator()

public Answer operator()( Question question ) const;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..User.html000066400000000000000000000257241411157722000215720ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::User
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Class Nes::Api::User

Base
   |
   +--Nes::Api::User


class Nes::Api::User
extends Base

User IO interfaces.


Inner Classes, Typedefs, and Enums
enum Nes::Api::User::Answer
          User answer.
enum Nes::Api::User::Event
          User events.
typedef Nes::Api::User::EventCallback
          Logfile callback prototype.
struct Nes::Api::User::File
          File IO interface.
typedef Nes::Api::User::FileIoCallback
          File IO callback prototype.
typedef Nes::Api::User::LogCallback
          Logfile callback prototype.
enum Nes::Api::User::Question
          User questions.
typedef Nes::Api::User::QuestionCallback
          User question callback prototype.
 
Field Summary
 static Nes::Api::User::EventCaller eventCallback
          User event callback manager.
 static Nes::Api::User::FileIoCaller fileIoCallback
          File IO callback manager.
 static Nes::Api::User::LogCaller logCallback
          Logfile callback manager.
 static Nes::Api::User::QuestionCaller questionCallback
          User question callback manager.
 
Constructor Summary
User( T& instance )
          Interface constructor.
 

Field Detail

eventCallback

public static Nes::Api::User::EventCaller eventCallback;
User event callback manager. Static object used for adding the user defined callback.

fileIoCallback

public static Nes::Api::User::FileIoCaller fileIoCallback;
File IO callback manager. Static object used for adding the user defined callback.

logCallback

public static Nes::Api::User::LogCaller logCallback;
Logfile callback manager. Static object used for adding the user defined callback.

questionCallback

public static Nes::Api::User::QuestionCaller questionCallback;
User question callback manager. Static object used for adding the user defined callback.


Constructor Detail

User

public User( T& instance );
Interface constructor.
Parameters:
instance - emulator instance

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Video..Decoder.html000066400000000000000000000202761411157722000233410ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Video::Decoder
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Video::Decoder


struct Nes::Api::Video::Decoder

YUV decoder context.


Field Summary
 [ NUM_AXES ] axes
          
 bool boostYellow
          
 
Constructor Summary
Decoder( DecoderPreset preset = DECODER_CANONICAL )
          Constructor.
 
Method Summary
 bool operator!=( const Decoder& decoder ) const
          Tests for non-equality.
 bool operator==( const Decoder& decoder ) const
          Tests for equality.
 

Field Detail

axes

public  axes[ NUM_AXES ];

boostYellow

public bool boostYellow;


Constructor Detail

Decoder

public Decoder( DecoderPreset preset = DECODER_CANONICAL ) throw();
Constructor.
Parameters:
preset - preset, canonical by default


Method Detail

operator!=

public bool operator!=( const Decoder& decoder ) const throw();
Tests for non-equality.
Parameters:
decoder - object to compare
Returns:
true if non-equal

operator==

public bool operator==( const Decoder& decoder ) const throw();
Tests for equality.
Parameters:
decoder - object to compare
Returns:
true if equal

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Video..DecoderPreset.html000066400000000000000000000121771411157722000245250ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Video::DecoderPreset
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Video::DecoderPreset

YUV decoder presets.


Field Summary
DECODER_ALTERNATIVE
          Alternative
DECODER_CANONICAL
          Canonical (default)
DECODER_CONSUMER
          Consumer
 

Field Detail

DECODER_ALTERNATIVE

public DECODER_ALTERNATIVE
Alternative

DECODER_CANONICAL

public DECODER_CANONICAL
Canonical (default)

DECODER_CONSUMER

public DECODER_CONSUMER
Consumer

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Video..Output.html000066400000000000000000000075151411157722000232750ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Video::Output
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Video::Output

Video output context.




Details

Output

public typedef Core::Video::Output Output;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Video..Palette..Colors.html000066400000000000000000000075421411157722000247110ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Video::Palette::Colors
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Api::Video::Palette::Colors

RGB colors.




Details

Colors

public typedef const uchar ( * Colors )[ 3];

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Video..Palette..CustomType.html000066400000000000000000000114751411157722000255640ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Video::Palette::CustomType
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Video::Palette::CustomType

Custom palette types.


Field Summary
EXT_PALETTE = NUM_ENTRIES_EXT
          Extended palette.
STD_PALETTE = NUM_ENTRIES
          Standard palette.
 

Field Detail

EXT_PALETTE

public EXT_PALETTE = NUM_ENTRIES_EXT
Extended palette. 512 colors with emphasis included in it.

STD_PALETTE

public STD_PALETTE = NUM_ENTRIES
Standard palette. 64 colors.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Video..Palette..Mode.html000066400000000000000000000117021411157722000243250ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Video::Palette::Mode
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Video::Palette::Mode

Palette modes


Field Summary
MODE_CUSTOM
          Custom
MODE_RGB
          RGB
MODE_YUV
          YUV (default)
 

Field Detail

MODE_CUSTOM

public MODE_CUSTOM
Custom

MODE_RGB

public MODE_RGB
RGB

MODE_YUV

public MODE_YUV
YUV (default)

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Video..Palette.html000066400000000000000000000317161411157722000233730ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Video::Palette
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Class Nes::Api::Video::Palette


class Nes::Api::Video::Palette

Palette interface.


Inner Classes, Typedefs, and Enums
typedef Nes::Api::Video::Palette::Colors
          RGB colors.
enum Nes::Api::Video::Palette::CustomType
          Custom palette types.
enum Nes::Api::Video::Palette::Mode
          Palette modes
 
Constructor Summary
Palette( Core::Machine& instance )
          Interface constructor
 
Method Summary
 Nes::Api::Video::Palette::Colors GetColors() const
          Return the current palette colors.
 uint GetCustom( uchar ( * colors )[ 3], Nes::Api::Video::Palette::CustomType type ) const
          Returns the custom palette.
 Nes::Api::Video::Palette::CustomType GetCustomType() const
          Returns the custom palette type.
 Nes::Api::Video::Palette::Mode GetDefaultMode() const
          Returns the default palette mode.
 Nes::Api::Video::Palette::Mode GetMode() const
          Returns the current palette mode.
 void ResetCustom()
          Resets the custom palette.
 Result SetCustom( Nes::Api::Video::Palette::Colors colors, Nes::Api::Video::Palette::CustomType type = STD_PALETTE )
          Sets the custom palette.
 Result SetMode( Nes::Api::Video::Palette::Mode mode )
          Sets the palette mode.
 

Constructor Detail

Palette

public Palette( Core::Machine& instance );
Interface constructor
Parameters:
instance - emulator instance


Method Detail

GetColors

public Nes::Api::Video::Palette::Colors GetColors() const throw();
Return the current palette colors.
Returns:
palette colors

GetCustom

public uint GetCustom( uchar ( * colors )[ 3], Nes::Api::Video::Palette::CustomType type ) const throw();
Returns the custom palette.
Parameters:
colors - RGB colors to be filled
type - custom palette type
Returns:
number of colors written

GetCustomType

public Nes::Api::Video::Palette::CustomType GetCustomType() const throw();
Returns the custom palette type.
Returns:
custom palette type

GetDefaultMode

public Nes::Api::Video::Palette::Mode GetDefaultMode() const throw();
Returns the default palette mode.
Returns:
default palette mode

GetMode

public Nes::Api::Video::Palette::Mode GetMode() const throw();
Returns the current palette mode.
Returns:
current mode

ResetCustom

public void ResetCustom() throw();
Resets the custom palette.

SetCustom

public Result SetCustom( Nes::Api::Video::Palette::Colors colors, Nes::Api::Video::Palette::CustomType type = STD_PALETTE ) throw();
Sets the custom palette.
Parameters:
colors - RGB color data
type - custom palette type

SetMode

public Result SetMode( Nes::Api::Video::Palette::Mode mode ) throw();
Sets the palette mode.
Parameters:
mode - palette mode
Returns:
result code

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Video..RenderState..Bits..Mask.html000066400000000000000000000124131411157722000261340ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Video::RenderState::Bits::Mask
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Video::RenderState::Bits::Mask


struct Nes::Api::Video::RenderState::Bits::Mask

RGB bit mask.


Field Summary
 ulong b
          
 ulong g
          
 ulong r
          
 

Field Detail

b

public ulong b;

g

public ulong g;

r

public ulong r;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Video..RenderState..Bits.html000066400000000000000000000134411411157722000251660ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Video::RenderState::Bits
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Video::RenderState::Bits


struct Nes::Api::Video::RenderState::Bits

Pixel context.


Inner Classes, Typedefs, and Enums
struct Nes::Api::Video::RenderState::Bits::Mask
          RGB bit mask.
 
Field Summary
 uint count
          Bits per pixel.
 Nes::Api::Video::RenderState::Bits::Mask mask
          RGB bit mask.
 

Field Detail

count

public uint count;
Bits per pixel.

mask

public Nes::Api::Video::RenderState::Bits::Mask mask;
RGB bit mask.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Video..RenderState..Filter.html000066400000000000000000000156031411157722000255140ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Video::RenderState::Filter
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Video::RenderState::Filter

Video Filter.


Field Summary
FILTER_2XSAI
          2xSaI filter.
FILTER_HQ2X
          Hq2x filter.
FILTER_HQ3X
          Hq3x filter.
FILTER_HQ4X
          Hq4x filter.
FILTER_NONE
          No filter (default).
FILTER_NTSC
          NTSC filter.
FILTER_SCALE2X
          Scale2x filter.
FILTER_SCALE3X
          Scale3x filter.
 

Field Detail

FILTER_2XSAI

public FILTER_2XSAI
2xSaI filter.

FILTER_HQ2X

public FILTER_HQ2X
Hq2x filter.

FILTER_HQ3X

public FILTER_HQ3X
Hq3x filter.

FILTER_HQ4X

public FILTER_HQ4X
Hq4x filter.

FILTER_NONE

public FILTER_NONE
No filter (default).

FILTER_NTSC

public FILTER_NTSC
NTSC filter.

FILTER_SCALE2X

public FILTER_SCALE2X
Scale2x filter.

FILTER_SCALE3X

public FILTER_SCALE3X
Scale3x filter.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Video..RenderState..Scale.html000066400000000000000000000137701411157722000253210ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Video::RenderState::Scale
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Api::Video::RenderState::Scale

Scale factors.


Field Summary
SCALE_2XSAI = 2
          
SCALE_HQ2X = 2
          
SCALE_HQ3X = 3
          
SCALE_NONE = 1
          
SCALE_SCALE2X = 2
          
SCALE_SCALE3X = 3
          
 

Field Detail

SCALE_2XSAI

public SCALE_2XSAI = 2

SCALE_HQ2X

public SCALE_HQ2X = 2

SCALE_HQ3X

public SCALE_HQ3X = 3

SCALE_NONE

public SCALE_NONE = 1

SCALE_SCALE2X

public SCALE_SCALE2X = 2

SCALE_SCALE3X

public SCALE_SCALE3X = 3

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Video..RenderState.html000066400000000000000000000207241411157722000242120ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Video::RenderState
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Api::Video::RenderState


struct Nes::Api::Video::RenderState

Render state context.


Inner Classes, Typedefs, and Enums
struct Nes::Api::Video::RenderState::Bits
          Pixel context.
enum Nes::Api::Video::RenderState::Filter
          Video Filter.
enum Nes::Api::Video::RenderState::Scale
          Scale factors.
 
Field Summary
 Nes::Api::Video::RenderState::Bits bits
          Pixel context.
 Nes::Api::Video::RenderState::Filter filter
          Filter.
 ushort height
          Screen height.
 ushort width
          Screen width.
 
Constructor Summary
RenderState()
          
 

Field Detail

bits

public Nes::Api::Video::RenderState::Bits bits;
Pixel context.

filter

public Nes::Api::Video::RenderState::Filter filter;
Filter.

height

public ushort height;
Screen height.

width

public ushort width;
Screen width.


Constructor Detail

RenderState

public RenderState() throw();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api..Video.html000066400000000000000000000663241411157722000217230ustar00rootroot00000000000000 Nestopia Core API: Nes::Api::Video
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Class Nes::Api::Video

Base
   |
   +--Nes::Api::Video


class Nes::Api::Video
extends Base

Video interface.


Inner Classes, Typedefs, and Enums
struct Nes::Api::Video::Decoder
          YUV decoder context.
enum Nes::Api::Video::DecoderPreset
          YUV decoder presets.
typedef Nes::Api::Video::Output
          Video output context.
class Nes::Api::Video::Palette
          Palette interface.
struct Nes::Api::Video::RenderState
          Render state context.
 
Constructor Summary
Video( T& instance )
          Interface constructor.
 
Method Summary
 bool AreUnlimSpritesEnabled() const
          Checks if the PPU sprite software extension is enabled.
 Result Blit( Nes::Api::Video::Output& output )
          Performs a manual blit to the video output object.
 void EnableFieldMerging( bool state )
          Enables field merging for the NTSC filter.
 Result EnableUnlimSprites( bool state )
          Allows the PPU to render more than eight sprites per line.
 int GetBrightness() const
          Returns the current brightness.
 int GetColorArtifacts() const
          Returns the current color artifacts for the NTSC filter.
 int GetColorBleed() const
          Returns the current color bleed for the NTSC filter.
 int GetColorFringing() const
          Returns the current color fringing for the NTSC filter.
 int GetColorResolution() const
          Returns the current color resolution for the NTSC filter.
 int GetContrast() const
          Returns the current contrast.
 const Nes::Api::Video::Decoder& GetDecoder() const
          Returns the current YUV decoder.
 int GetHue() const
          Returns the current hue.
 Nes::Api::Video::Palette GetPalette()
          Returns the palette interface.
 Result GetRenderState( Nes::Api::Video::RenderState& state ) const
          Returns the current render state.
 int GetSaturation() const
          Returns the current saturation.
 int GetSharpness() const
          Returns the current sharpness for the NTSC filter.
 bool IsFieldMergingEnabled() const
          Checks if NTSC filter field merging is enabled.
 Result SetBrightness( int value )
          Sets the brightness.
 Result SetColorArtifacts( int value )
          Sets the color artifacts for the NTSC filter.
 Result SetColorBleed( int value )
          Sets the color bleed for the NTSC filter.
 Result SetColorFringing( int value )
          Sets the color fringing for the NTSC filter.
 Result SetColorResolution( int value )
          Sets the color resolution for the NTSC filter.
 Result SetContrast( int value )
          Sets the contrast.
 Result SetDecoder( const Nes::Api::Video::Decoder& decoder )
          Sets the YUV decoder.
 Result SetHue( int value )
          Sets the hue.
 Result SetRenderState( const Nes::Api::Video::RenderState& state )
          Sets the render state.
 Result SetSaturation( int value )
          Sets the saturation.
 Result SetSharpness( int value )
          Sets the sharpness for the NTSC filter.
 

Constructor Detail

Video

public Video( T& instance );
Interface constructor.
Parameters:
instance - emulator instance


Method Detail

AreUnlimSpritesEnabled

public bool AreUnlimSpritesEnabled() const throw();
Checks if the PPU sprite software extension is enabled.
Returns:
true if enabled

Blit

public Result Blit( Nes::Api::Video::Output& output ) throw();
Performs a manual blit to the video output object. The core calls this method internally for each frame.
Parameters:
output - video output object to blit to
Returns:
result code

EnableFieldMerging

public void EnableFieldMerging( bool state ) throw();
Enables field merging for the NTSC filter.
Parameters:
state - true to enable

EnableUnlimSprites

public Result EnableUnlimSprites( bool state ) throw();
Allows the PPU to render more than eight sprites per line.
Parameters:
state - true to allow it, default is false
Returns:
result code

GetBrightness

public int GetBrightness() const throw();
Returns the current brightness.
Returns:
brightness value in the range -100 to 100

GetColorArtifacts

public int GetColorArtifacts() const throw();
Returns the current color artifacts for the NTSC filter.
Returns:
color artifacts value in the range -100 to 100

GetColorBleed

public int GetColorBleed() const throw();
Returns the current color bleed for the NTSC filter.
Returns:
color bleed value in the range -100 to 100

GetColorFringing

public int GetColorFringing() const throw();
Returns the current color fringing for the NTSC filter.
Returns:
color fringing value in the range -100 to 100

GetColorResolution

public int GetColorResolution() const throw();
Returns the current color resolution for the NTSC filter.
Returns:
color resolution value in the range -100 to 100

GetContrast

public int GetContrast() const throw();
Returns the current contrast.
Returns:
contrast value in the range -100 to 100

GetDecoder

public const Nes::Api::Video::Decoder& GetDecoder() const throw();
Returns the current YUV decoder.
Returns:
current decoder

GetHue

public int GetHue() const throw();
Returns the current hue.
Returns:
hue value in the range -45 to 45

GetPalette

public Nes::Api::Video::Palette GetPalette();
Returns the palette interface.
Returns:
palette interface

GetRenderState

public Result GetRenderState( Nes::Api::Video::RenderState& state ) const throw();
Returns the current render state.
Parameters:
state - object to be filled
Returns:
result code

GetSaturation

public int GetSaturation() const throw();
Returns the current saturation.
Returns:
saturation value in the range -100 to 100

GetSharpness

public int GetSharpness() const throw();
Returns the current sharpness for the NTSC filter.
Returns:
sharpness value in the range -100 to 100

IsFieldMergingEnabled

public bool IsFieldMergingEnabled() const throw();
Checks if NTSC filter field merging is enabled.
Returns:
true if enabled

SetBrightness

public Result SetBrightness( int value ) throw();
Sets the brightness.
Parameters:
value - brightness in the range -100 to 100, default is 0
Returns:
result code

SetColorArtifacts

public Result SetColorArtifacts( int value ) throw();
Sets the color artifacts for the NTSC filter.
Parameters:
value - color artifacts in the range -100 to 100, default is 0
Returns:
result code

SetColorBleed

public Result SetColorBleed( int value ) throw();
Sets the color bleed for the NTSC filter.
Parameters:
value - color bleed in the range -100 to 100, default is 0
Returns:
result code

SetColorFringing

public Result SetColorFringing( int value ) throw();
Sets the color fringing for the NTSC filter.
Parameters:
value - fringing in the range -100 to 100, default is 0
Returns:
result code

SetColorResolution

public Result SetColorResolution( int value ) throw();
Sets the color resolution for the NTSC filter.
Parameters:
value - color resolution in the range -100 to 100, default is 0
Returns:
result code

SetContrast

public Result SetContrast( int value ) throw();
Sets the contrast.
Parameters:
value - contrast in the range -100 to 100, default is 0
Returns:
result code

SetDecoder

public Result SetDecoder( const Nes::Api::Video::Decoder& decoder ) throw();
Sets the YUV decoder.
Parameters:
decoder - decoder
Returns:
result code

SetHue

public Result SetHue( int value ) throw();
Sets the hue.
Parameters:
value - hue in the range -45 to 45, default is 0
Returns:
result code

SetRenderState

public Result SetRenderState( const Nes::Api::Video::RenderState& state ) throw();
Sets the render state.
Parameters:
state - render state to be set
Returns:
result code

SetSaturation

public Result SetSaturation( int value ) throw();
Sets the saturation.
Parameters:
value - saturation in the range -100 to 100, default is 0
Returns:
result code

SetSharpness

public Result SetSharpness( int value ) throw();
Sets the sharpness for the NTSC filter.
Parameters:
value - sharpness in the range -100 to 100, default is 0
Returns:
result code

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Api.html000066400000000000000000000313171411157722000205720ustar00rootroot00000000000000 Nestopia Core API: Nes::Api
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Namespace Nes::Api


namespace Nes::Api


Inner Classes, Typedefs, and Enums
class Nes::Api::BarcodeReader
          Bar code reader interface.
class Nes::Api::Cartridge
          Cartridge interface.
struct Nes::Api::Cartridge::ChooseProfileCaller
          Cartridge profile chooser callback invoker.
class Nes::Api::Cheats
          Cheats interface.
class Nes::Api::DipSwitches
          DIP switches interface.
class Nes::Api::Emulator
          Emulator object instance.
class Nes::Api::Fds
          Famicom Disk System interface.
struct Nes::Api::Fds::DiskCaller
          Disk event callback invoker.
struct Nes::Api::Fds::DriveCaller
          Drive event callback invoker.
class Nes::Api::Input
          Controller input interface.
struct Nes::Api::Input::AdapterCaller
          Adapter event callback invoker.
struct Nes::Api::Input::ControllerCaller
          Controller event callback invoker.
class Nes::Api::Machine
          Machine interface.
struct Nes::Api::Machine::EventCaller
          Machine event callback invoker.
class Nes::Api::Movie
          Movie playing/recording interface.
struct Nes::Api::Movie::EventCaller
          Movie event callback invoker.
class Nes::Api::Nsf
          NES Sound Files interface.
struct Nes::Api::Nsf::EventCaller
          Song event callback invoker.
class Nes::Api::Rewinder
          Game rewinder interface.
struct Nes::Api::Rewinder::StateCaller
          Rewinder state callback invoker.
class Nes::Api::Sound
          Sound interface.
class Nes::Api::TapeRecorder
          Tape interface.
struct Nes::Api::TapeRecorder::EventCaller
          Tape event callback invoker.
class Nes::Api::User
          User IO interfaces.
struct Nes::Api::User::EventCaller
          User event callback invoker.
struct Nes::Api::User::FileIoCaller
          File IO callback invoker.
struct Nes::Api::User::LogCaller
          Logfile callback invoker.
struct Nes::Api::User::QuestionCaller
          User question callback invoker.
class Nes::Api::Video
          Video interface.
 
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..BandaiHyperShot..PollCallback.html000066400000000000000000000077701411157722000322170ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::BandaiHyperShot::PollCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Input::Controllers::BandaiHyperShot::PollCallback




Details

PollCallback

public typedef bool( NST_CALLBACK* PollCallback )( void*, BandaiHyperShot& );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..BandaiHyperShot.html000066400000000000000000000176411411157722000276150ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::BandaiHyperShot
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::BandaiHyperShot


struct Nes::Core::Input::Controllers::BandaiHyperShot

Bandai Hyper Shot


Inner Classes, Typedefs, and Enums
typedef Nes::Core::Input::Controllers::BandaiHyperShot::PollCallback
          
 
Field Summary
 static PollCaller1< BandaiHyperShot > callback
          
 uint fire
          
 uint move
          
 uint x
          
 uint y
          
 
Constructor Summary
BandaiHyperShot()
          
 

Field Detail

callback

public static PollCaller1< BandaiHyperShot > callback;

fire

public uint fire;

move

public uint move;

x

public uint x;

y

public uint y;


Constructor Detail

BandaiHyperShot

public BandaiHyperShot();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..CrazyClimber..PollCallback.html000066400000000000000000000077511411157722000315600ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::CrazyClimber::PollCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Input::Controllers::CrazyClimber::PollCallback




Details

PollCallback

public typedef bool( NST_CALLBACK* PollCallback )( void*, CrazyClimber& );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..CrazyClimber.html000066400000000000000000000161551411157722000271560ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::CrazyClimber
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::CrazyClimber


struct Nes::Core::Input::Controllers::CrazyClimber

Crazy Climber.


Inner Classes, Typedefs, and Enums
typedef Nes::Core::Input::Controllers::CrazyClimber::PollCallback
          
 
Field Summary
 static PollCaller1< CrazyClimber > callback
          
 uint left
          
 uint right
          
 
Constructor Summary
CrazyClimber()
          
 

Field Detail

callback

public static PollCaller1< CrazyClimber > callback;

left

public uint left;

right

public uint right;


Constructor Detail

CrazyClimber

public CrazyClimber();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..DoremikkoKeyboard..PollCallback.html000066400000000000000000000100161411157722000325630ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::DoremikkoKeyboard::PollCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Input::Controllers::DoremikkoKeyboard::PollCallback




Details

PollCallback

public typedef bool( NST_CALLBACK* PollCallback )( void*, DoremikkoKeyboard&, uint, uint );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..DoremikkoKeyboard.html000066400000000000000000000154401411157722000301710ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::DoremikkoKeyboard
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::DoremikkoKeyboard


struct Nes::Core::Input::Controllers::DoremikkoKeyboard

Doremikko Keyboard.


Inner Classes, Typedefs, and Enums
typedef Nes::Core::Input::Controllers::DoremikkoKeyboard::PollCallback
          
 
Field Summary
 static PollCaller3< DoremikkoKeyboard > callback
          
 uint keys
          
 
Constructor Summary
DoremikkoKeyboard()
          
 

Field Detail

callback

public static PollCaller3< DoremikkoKeyboard > callback;

keys

public uint keys;


Constructor Detail

DoremikkoKeyboard

public DoremikkoKeyboard();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..ExcitingBoxing..PollCallback.html000066400000000000000000000077711411157722000321150ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::ExcitingBoxing::PollCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Input::Controllers::ExcitingBoxing::PollCallback




Details

PollCallback

public typedef bool( NST_CALLBACK* PollCallback )( void*, ExcitingBoxing&, uint );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..ExcitingBoxing.html000066400000000000000000000154111411157722000275030ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::ExcitingBoxing
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::ExcitingBoxing


struct Nes::Core::Input::Controllers::ExcitingBoxing

Konami Exciting Boxing.


Inner Classes, Typedefs, and Enums
typedef Nes::Core::Input::Controllers::ExcitingBoxing::PollCallback
          
 
Field Summary
 uint buttons
          
 static PollCaller2< ExcitingBoxing > callback
          
 
Constructor Summary
ExcitingBoxing()
          
 

Field Detail

buttons

public uint buttons;

callback

public static PollCaller2< ExcitingBoxing > callback;


Constructor Detail

ExcitingBoxing

public ExcitingBoxing();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..FamilyKeyboard..PollCallback.html000066400000000000000000000077771411157722000321040ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::FamilyKeyboard::PollCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Input::Controllers::FamilyKeyboard::PollCallback




Details

PollCallback

public typedef bool( NST_CALLBACK* PollCallback )( void*, FamilyKeyboard&, uint, uint );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..FamilyKeyboard.html000066400000000000000000000154421411157722000274700ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::FamilyKeyboard
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::FamilyKeyboard


struct Nes::Core::Input::Controllers::FamilyKeyboard

Family Keyboard.


Inner Classes, Typedefs, and Enums
typedef Nes::Core::Input::Controllers::FamilyKeyboard::PollCallback
          
 
Field Summary
 static PollCaller3< FamilyKeyboard > callback
          
 uchar[ NUM_PARTS + 3 ] parts
          
 
Constructor Summary
FamilyKeyboard()
          
 

Field Detail

callback

public static PollCaller3< FamilyKeyboard > callback;

parts

public uchar parts[ NUM_PARTS + 3 ];


Constructor Detail

FamilyKeyboard

public FamilyKeyboard() throw();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..FamilyTrainer..PollCallback.html000066400000000000000000000077561411157722000317450ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::FamilyTrainer::PollCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Input::Controllers::FamilyTrainer::PollCallback




Details

PollCallback

public typedef bool( NST_CALLBACK* PollCallback )( void*, FamilyTrainer& );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..FamilyTrainer.html000066400000000000000000000163431411157722000273350ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::FamilyTrainer
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::FamilyTrainer


struct Nes::Core::Input::Controllers::FamilyTrainer

Family Trainer.


Inner Classes, Typedefs, and Enums
typedef Nes::Core::Input::Controllers::FamilyTrainer::PollCallback
          
 
Field Summary
 static PollCaller1< FamilyTrainer > callback
          
 bool[ NUM_SIDE_A_BUTTONS ] sideA
          
 bool[ NUM_SIDE_B_BUTTONS ] sideB
          
 
Constructor Summary
FamilyTrainer()
          
 

Field Detail

callback

public static PollCaller1< FamilyTrainer > callback;

sideA

public bool sideA[ NUM_SIDE_A_BUTTONS ];

sideB

public bool sideB[ NUM_SIDE_B_BUTTONS ];


Constructor Detail

FamilyTrainer

public FamilyTrainer() throw();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..HoriTrack..PollCallback.html000066400000000000000000000077321411157722000310570ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::HoriTrack::PollCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Input::Controllers::HoriTrack::PollCallback




Details

PollCallback

public typedef bool( NST_CALLBACK* PollCallback )( void*, HoriTrack& );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..HoriTrack.html000066400000000000000000000175231411157722000264560ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::HoriTrack
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::HoriTrack


struct Nes::Core::Input::Controllers::HoriTrack

Hori Track.


Inner Classes, Typedefs, and Enums
typedef Nes::Core::Input::Controllers::HoriTrack::PollCallback
          
 
Field Summary
 uint buttons
          
 static PollCaller1< HoriTrack > callback
          
 uint mode
          
 uint x
          
 uint y
          
 
Constructor Summary
HoriTrack()
          
 

Field Detail

buttons

public uint buttons;

callback

public static PollCaller1< HoriTrack > callback;

mode

public uint mode;

x

public uint x;

y

public uint y;


Constructor Detail

HoriTrack

public HoriTrack();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..KaraokeStudio..PollCallback.html000066400000000000000000000077561411157722000317440ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::KaraokeStudio::PollCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Input::Controllers::KaraokeStudio::PollCallback




Details

PollCallback

public typedef bool( NST_CALLBACK* PollCallback )( void*, KaraokeStudio& );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..KaraokeStudio.html000066400000000000000000000153711411157722000273340ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::KaraokeStudio
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::KaraokeStudio


struct Nes::Core::Input::Controllers::KaraokeStudio

Bandai Karaoke Studio.


Inner Classes, Typedefs, and Enums
typedef Nes::Core::Input::Controllers::KaraokeStudio::PollCallback
          
 
Field Summary
 uint buttons
          
 static PollCaller1< KaraokeStudio > callback
          
 
Constructor Summary
KaraokeStudio()
          
 

Field Detail

buttons

public uint buttons;

callback

public static PollCaller1< KaraokeStudio > callback;


Constructor Detail

KaraokeStudio

public KaraokeStudio();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..KonamiHyperShot..PollCallback.html000066400000000000000000000077701411157722000322570ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::KonamiHyperShot::PollCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Input::Controllers::KonamiHyperShot::PollCallback




Details

PollCallback

public typedef bool( NST_CALLBACK* PollCallback )( void*, KonamiHyperShot& );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..KonamiHyperShot.html000066400000000000000000000154231411157722000276510ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::KonamiHyperShot
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::KonamiHyperShot


struct Nes::Core::Input::Controllers::KonamiHyperShot

Konami Hyper Shot.


Inner Classes, Typedefs, and Enums
typedef Nes::Core::Input::Controllers::KonamiHyperShot::PollCallback
          
 
Field Summary
 uint buttons
          
 static PollCaller1< KonamiHyperShot > callback
          
 
Constructor Summary
KonamiHyperShot()
          
 

Field Detail

buttons

public uint buttons;

callback

public static PollCaller1< KonamiHyperShot > callback;


Constructor Detail

KonamiHyperShot

public KonamiHyperShot();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..Mahjong..PollCallback.html000066400000000000000000000077261411157722000305570ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::Mahjong::PollCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Input::Controllers::Mahjong::PollCallback




Details

PollCallback

public typedef bool( NST_CALLBACK* PollCallback )( void*, Mahjong&, uint );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..Mahjong.html000066400000000000000000000152211411157722000261440ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::Mahjong
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::Mahjong


struct Nes::Core::Input::Controllers::Mahjong

Mahjong.


Inner Classes, Typedefs, and Enums
typedef Nes::Core::Input::Controllers::Mahjong::PollCallback
          
 
Field Summary
 uint buttons
          
 static PollCaller2< Mahjong > callback
          
 
Constructor Summary
Mahjong()
          
 

Field Detail

buttons

public uint buttons;

callback

public static PollCaller2< Mahjong > callback;


Constructor Detail

Mahjong

public Mahjong();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..Mouse..PollCallback.html000066400000000000000000000077061411157722000302620ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::Mouse::PollCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Input::Controllers::Mouse::PollCallback




Details

PollCallback

public typedef bool( NST_CALLBACK* PollCallback )( void*, Mouse& );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..Mouse.html000066400000000000000000000165651411157722000256650ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::Mouse
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::Mouse


struct Nes::Core::Input::Controllers::Mouse

Mouse.


Inner Classes, Typedefs, and Enums
typedef Nes::Core::Input::Controllers::Mouse::PollCallback
          
 
Field Summary
 uint button
          
 static PollCaller1< Mouse > callback
          
 uint x
          
 uint y
          
 
Constructor Summary
Mouse()
          
 

Field Detail

button

public uint button;

callback

public static PollCaller1< Mouse > callback;

x

public uint x;

y

public uint y;


Constructor Detail

Mouse

public Mouse();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..OekaKidsTablet..PollCallback.html000066400000000000000000000077631411157722000320230ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::OekaKidsTablet::PollCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Input::Controllers::OekaKidsTablet::PollCallback




Details

PollCallback

public typedef bool( NST_CALLBACK* PollCallback )( void*, OekaKidsTablet& );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..OekaKidsTablet.html000066400000000000000000000170071411157722000274130ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::OekaKidsTablet
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::OekaKidsTablet


struct Nes::Core::Input::Controllers::OekaKidsTablet

Oeka Kids Tablet.


Inner Classes, Typedefs, and Enums
typedef Nes::Core::Input::Controllers::OekaKidsTablet::PollCallback
          
 
Field Summary
 uint button
          
 static PollCaller1< OekaKidsTablet > callback
          
 uint x
          
 uint y
          
 
Constructor Summary
OekaKidsTablet()
          
 

Field Detail

button

public uint button;

callback

public static PollCaller1< OekaKidsTablet > callback;

x

public uint x;

y

public uint y;


Constructor Detail

OekaKidsTablet

public OekaKidsTablet();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..Pachinko..PollCallback.html000066400000000000000000000077251411157722000307270ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::Pachinko::PollCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Input::Controllers::Pachinko::PollCallback




Details

PollCallback

public typedef bool( NST_CALLBACK* PollCallback )( void*, Pachinko& );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..Pachinko.html000066400000000000000000000161161411157722000263210ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::Pachinko
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::Pachinko


struct Nes::Core::Input::Controllers::Pachinko

Pachinko.


Inner Classes, Typedefs, and Enums
typedef Nes::Core::Input::Controllers::Pachinko::PollCallback
          
 
Field Summary
 uint buttons
          
 static PollCaller1< Pachinko > callback
          
 int throttle
          
 
Constructor Summary
Pachinko()
          
 

Field Detail

buttons

public uint buttons;

callback

public static PollCaller1< Pachinko > callback;

throttle

public int throttle;


Constructor Detail

Pachinko

public Pachinko();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..Pad..PollCallback.html000066400000000000000000000077021411157722000276720ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::Pad::PollCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Input::Controllers::Pad::PollCallback




Details

PollCallback

public typedef bool( NST_CALLBACK* PollCallback )( void*, Pad&, uint );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..Pad.html000066400000000000000000000167021411157722000252720ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::Pad
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::Pad


struct Nes::Core::Input::Controllers::Pad

Standard NES pad.


Inner Classes, Typedefs, and Enums
typedef Nes::Core::Input::Controllers::Pad::PollCallback
          
 
Field Summary
 uint allowSimulAxes
          
 uint buttons
          
 static PollCaller2< Pad > callback
          
 uint mic
          
 
Constructor Summary
Pad()
          
 

Field Detail

allowSimulAxes

public uint allowSimulAxes;

buttons

public uint buttons;

callback

public static PollCaller2< Pad > callback;

mic

public uint mic;


Constructor Detail

Pad

public Pad();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..Paddle..PollCallback.html000066400000000000000000000077131411157722000303610ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::Paddle::PollCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Input::Controllers::Paddle::PollCallback




Details

PollCallback

public typedef bool( NST_CALLBACK* PollCallback )( void*, Paddle& );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..Paddle.html000066400000000000000000000160151411157722000257540ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::Paddle
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::Paddle


struct Nes::Core::Input::Controllers::Paddle

Arkanoid controller.


Inner Classes, Typedefs, and Enums
typedef Nes::Core::Input::Controllers::Paddle::PollCallback
          
 
Field Summary
 uint button
          
 static PollCaller1< Paddle > callback
          
 uint x
          
 
Constructor Summary
Paddle()
          
 

Field Detail

button

public uint button;

callback

public static PollCaller1< Paddle > callback;

x

public uint x;


Constructor Detail

Paddle

public Paddle();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..PartyTap..PollCallback.html000066400000000000000000000077251411157722000307370ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::PartyTap::PollCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Input::Controllers::PartyTap::PollCallback




Details

PollCallback

public typedef bool( NST_CALLBACK* PollCallback )( void*, PartyTap& );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..PartyTap.html000066400000000000000000000152261411157722000263320ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::PartyTap
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::PartyTap


struct Nes::Core::Input::Controllers::PartyTap

Party Tap.


Inner Classes, Typedefs, and Enums
typedef Nes::Core::Input::Controllers::PartyTap::PollCallback
          
 
Field Summary
 static PollCaller1< PartyTap > callback
          
 uint units
          
 
Constructor Summary
PartyTap()
          
 

Field Detail

callback

public static PollCaller1< PartyTap > callback;

units

public uint units;


Constructor Detail

PartyTap

public PartyTap();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..PokkunMoguraa..PollCallback.html000066400000000000000000000077641411157722000317610ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::PokkunMoguraa::PollCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Input::Controllers::PokkunMoguraa::PollCallback




Details

PollCallback

public typedef bool( NST_CALLBACK* PollCallback )( void*, PokkunMoguraa&, uint );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..PokkunMoguraa.html000066400000000000000000000153621411157722000273520ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::PokkunMoguraa
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::PokkunMoguraa


struct Nes::Core::Input::Controllers::PokkunMoguraa

Pokkun Moguraa.


Inner Classes, Typedefs, and Enums
typedef Nes::Core::Input::Controllers::PokkunMoguraa::PollCallback
          
 
Field Summary
 uint buttons
          
 static PollCaller2< PokkunMoguraa > callback
          
 
Constructor Summary
PokkunMoguraa()
          
 

Field Detail

buttons

public uint buttons;

callback

public static PollCaller2< PokkunMoguraa > callback;


Constructor Detail

PokkunMoguraa

public PokkunMoguraa();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..PollCaller1.html000066400000000000000000000113631411157722000266760ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::PollCaller1
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::PollCaller1

UserCallback
   |
   +--Nes::Core::Input::Controllers::PollCaller1


template < typename T > struct Nes::Core::Input::Controllers::PollCaller1
extends UserCallback


Method Summary
 bool operator()( T& t ) const
          
 

Method Detail

operator()

public bool operator()( T& t ) const;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..PollCaller2.html000066400000000000000000000114151411157722000266750ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::PollCaller2
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::PollCaller2

UserCallback
   |
   +--Nes::Core::Input::Controllers::PollCaller2


template < typename T > struct Nes::Core::Input::Controllers::PollCaller2
extends UserCallback


Method Summary
 bool operator()( T& t, uint a ) const
          
 

Method Detail

operator()

public bool operator()( T& t, uint a ) const;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..PollCaller3.html000066400000000000000000000114471411157722000267030ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::PollCaller3
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::PollCaller3

UserCallback
   |
   +--Nes::Core::Input::Controllers::PollCaller3


template < typename T > struct Nes::Core::Input::Controllers::PollCaller3
extends UserCallback


Method Summary
 bool operator()( T& t, uint a, uint b ) const
          
 

Method Detail

operator()

public bool operator()( T& t, uint a, uint b ) const;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..PowerGlove..Gesture.html000066400000000000000000000120751411157722000303510ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::PowerGlove::Gesture
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Enum Nes::Core::Input::Controllers::PowerGlove::Gesture


Field Summary
GESTURE_FINGER = 0x0F
          
GESTURE_FIST = 0xFF
          
GESTURE_OPEN = 0x00
          
 

Field Detail

GESTURE_FINGER

public GESTURE_FINGER = 0x0F

GESTURE_FIST

public GESTURE_FIST = 0xFF

GESTURE_OPEN

public GESTURE_OPEN = 0x00

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..PowerGlove..PollCallback.html000066400000000000000000000077371411157722000312670ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::PowerGlove::PollCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Input::Controllers::PowerGlove::PollCallback




Details

PollCallback

public typedef bool( NST_CALLBACK* PollCallback )( void*, PowerGlove& );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..PowerGlove.html000066400000000000000000000224431411157722000266560ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::PowerGlove
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::PowerGlove


struct Nes::Core::Input::Controllers::PowerGlove

Power Glove.


Inner Classes, Typedefs, and Enums
enum Nes::Core::Input::Controllers::PowerGlove::Gesture
          
typedef Nes::Core::Input::Controllers::PowerGlove::PollCallback
          
 
Field Summary
 uint buttons
          
 static PollCaller1< PowerGlove > callback
          
 schar distance
          
 Nes::Core::Input::Controllers::PowerGlove::Gesture gesture
          
 schar wrist
          
 uchar x
          
 uchar y
          
 
Constructor Summary
PowerGlove()
          
 

Field Detail

buttons

public uint buttons;

callback

public static PollCaller1< PowerGlove > callback;

distance

public schar distance;

gesture

public Nes::Core::Input::Controllers::PowerGlove::Gesture gesture;

wrist

public schar wrist;

x

public uchar x;

y

public uchar y;


Constructor Detail

PowerGlove

public PowerGlove() throw();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..PowerPad..PollCallback.html000066400000000000000000000077251411157722000307140ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::PowerPad::PollCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Input::Controllers::PowerPad::PollCallback




Details

PollCallback

public typedef bool( NST_CALLBACK* PollCallback )( void*, PowerPad& );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..PowerPad.html000066400000000000000000000162511411157722000263060ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::PowerPad
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::PowerPad


struct Nes::Core::Input::Controllers::PowerPad

Power Pad / Family Fun Fittness.


Inner Classes, Typedefs, and Enums
typedef Nes::Core::Input::Controllers::PowerPad::PollCallback
          
 
Field Summary
 static PollCaller1< PowerPad > callback
          
 bool[ NUM_SIDE_A_BUTTONS ] sideA
          
 bool[ NUM_SIDE_B_BUTTONS ] sideB
          
 
Constructor Summary
PowerPad()
          
 

Field Detail

callback

public static PollCaller1< PowerPad > callback;

sideA

public bool sideA[ NUM_SIDE_A_BUTTONS ];

sideB

public bool sideB[ NUM_SIDE_B_BUTTONS ];


Constructor Detail

PowerPad

public PowerPad() throw();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..SuborKeyboard..PollCallback.html000066400000000000000000000077721411157722000317500ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::SuborKeyboard::PollCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Input::Controllers::SuborKeyboard::PollCallback




Details

PollCallback

public typedef bool( NST_CALLBACK* PollCallback )( void*, SuborKeyboard&, uint, uint );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..SuborKeyboard.html000066400000000000000000000154221411157722000273370ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::SuborKeyboard
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::SuborKeyboard


struct Nes::Core::Input::Controllers::SuborKeyboard

Subor Keyboard.


Inner Classes, Typedefs, and Enums
typedef Nes::Core::Input::Controllers::SuborKeyboard::PollCallback
          
 
Field Summary
 static PollCaller3< SuborKeyboard > callback
          
 uchar[ NUM_PARTS + 2 ] parts
          
 
Constructor Summary
SuborKeyboard()
          
 

Field Detail

callback

public static PollCaller3< SuborKeyboard > callback;

parts

public uchar parts[ NUM_PARTS + 2 ];


Constructor Detail

SuborKeyboard

public SuborKeyboard() throw();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..TopRider..PollCallback.html000066400000000000000000000077251411157722000307230ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::TopRider::PollCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Input::Controllers::TopRider::PollCallback




Details

PollCallback

public typedef bool( NST_CALLBACK* PollCallback )( void*, TopRider& );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..TopRider.html000066400000000000000000000152471411157722000263210ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::TopRider
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::TopRider


struct Nes::Core::Input::Controllers::TopRider

Top Rider bike.


Inner Classes, Typedefs, and Enums
typedef Nes::Core::Input::Controllers::TopRider::PollCallback
          
 
Field Summary
 uint buttons
          
 static PollCaller1< TopRider > callback
          
 
Constructor Summary
TopRider()
          
 

Field Detail

buttons

public uint buttons;

callback

public static PollCaller1< TopRider > callback;


Constructor Detail

TopRider

public TopRider();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..VsSystem..PollCallback.html000066400000000000000000000077251411157722000307700ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::VsSystem::PollCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Input::Controllers::VsSystem::PollCallback




Details

PollCallback

public typedef bool( NST_CALLBACK* PollCallback )( void*, VsSystem& );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..VsSystem.html000066400000000000000000000152721411157722000263640ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::VsSystem
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::VsSystem


struct Nes::Core::Input::Controllers::VsSystem

VS System input.


Inner Classes, Typedefs, and Enums
typedef Nes::Core::Input::Controllers::VsSystem::PollCallback
          
 
Field Summary
 static PollCaller1< VsSystem > callback
          
 uint insertCoin
          
 
Constructor Summary
VsSystem()
          
 

Field Detail

callback

public static PollCaller1< VsSystem > callback;

insertCoin

public uint insertCoin;


Constructor Detail

VsSystem

public VsSystem();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..Zapper..PollCallback.html000066400000000000000000000077131411157722000304310ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::Zapper::PollCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Input::Controllers::Zapper::PollCallback




Details

PollCallback

public typedef bool( NST_CALLBACK* PollCallback )( void*, Zapper& );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers..Zapper.html000066400000000000000000000166051411157722000260310ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers::Zapper
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Input::Controllers::Zapper


struct Nes::Core::Input::Controllers::Zapper

Standard light gun.


Inner Classes, Typedefs, and Enums
typedef Nes::Core::Input::Controllers::Zapper::PollCallback
          
 
Field Summary
 static PollCaller1< Zapper > callback
          
 uint fire
          
 uint x
          
 uint y
          
 
Constructor Summary
Zapper()
          
 

Field Detail

callback

public static PollCaller1< Zapper > callback;

fire

public uint fire;

x

public uint x;

y

public uint y;


Constructor Detail

Zapper

public Zapper();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input..Controllers.html000066400000000000000000000717311411157722000245140ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input::Controllers
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Class Nes::Core::Input::Controllers


class Nes::Core::Input::Controllers


Inner Classes, Typedefs, and Enums
struct Nes::Core::Input::Controllers::BandaiHyperShot
          Bandai Hyper Shot
struct Nes::Core::Input::Controllers::CrazyClimber
          Crazy Climber.
struct Nes::Core::Input::Controllers::DoremikkoKeyboard
          Doremikko Keyboard.
struct Nes::Core::Input::Controllers::ExcitingBoxing
          Konami Exciting Boxing.
struct Nes::Core::Input::Controllers::FamilyKeyboard
          Family Keyboard.
struct Nes::Core::Input::Controllers::FamilyTrainer
          Family Trainer.
struct Nes::Core::Input::Controllers::HoriTrack
          Hori Track.
struct Nes::Core::Input::Controllers::KaraokeStudio
          Bandai Karaoke Studio.
struct Nes::Core::Input::Controllers::KonamiHyperShot
          Konami Hyper Shot.
struct Nes::Core::Input::Controllers::Mahjong
          Mahjong.
struct Nes::Core::Input::Controllers::Mouse
          Mouse.
struct Nes::Core::Input::Controllers::OekaKidsTablet
          Oeka Kids Tablet.
struct Nes::Core::Input::Controllers::Pachinko
          Pachinko.
struct Nes::Core::Input::Controllers::Pad
          Standard NES pad.
struct Nes::Core::Input::Controllers::Paddle
          Arkanoid controller.
struct Nes::Core::Input::Controllers::PartyTap
          Party Tap.
struct Nes::Core::Input::Controllers::PokkunMoguraa
          Pokkun Moguraa.
struct Nes::Core::Input::Controllers::PollCaller1
          
struct Nes::Core::Input::Controllers::PollCaller2
          
struct Nes::Core::Input::Controllers::PollCaller3
          
struct Nes::Core::Input::Controllers::PowerGlove
          Power Glove.
struct Nes::Core::Input::Controllers::PowerPad
          Power Pad / Family Fun Fittness.
struct Nes::Core::Input::Controllers::SuborKeyboard
          Subor Keyboard.
struct Nes::Core::Input::Controllers::TopRider
          Top Rider bike.
struct Nes::Core::Input::Controllers::VsSystem
          VS System input.
struct Nes::Core::Input::Controllers::Zapper
          Standard light gun.
 
Field Summary
 Nes::Core::Input::Controllers::BandaiHyperShot bandaiHyperShot
          
 Nes::Core::Input::Controllers::CrazyClimber crazyClimber
          
 Nes::Core::Input::Controllers::DoremikkoKeyboard doremikkoKeyboard
          
 Nes::Core::Input::Controllers::ExcitingBoxing excitingBoxing
          
 Nes::Core::Input::Controllers::FamilyKeyboard familyKeyboard
          
 Nes::Core::Input::Controllers::FamilyTrainer familyTrainer
          
 Nes::Core::Input::Controllers::HoriTrack horiTrack
          
 Nes::Core::Input::Controllers::KaraokeStudio karaokeStudio
          
 Nes::Core::Input::Controllers::KonamiHyperShot konamiHyperShot
          
 Nes::Core::Input::Controllers::Mahjong mahjong
          
 Nes::Core::Input::Controllers::Mouse mouse
          
 Nes::Core::Input::Controllers::OekaKidsTablet oekaKidsTablet
          
 Nes::Core::Input::Controllers::Pachinko pachinko
          
 Nes::Core::Input::Controllers::Pad[ NUM_PADS ] pad
          
 Nes::Core::Input::Controllers::Paddle paddle
          
 Nes::Core::Input::Controllers::PartyTap partyTap
          
 Nes::Core::Input::Controllers::PokkunMoguraa pokkunMoguraa
          
 Nes::Core::Input::Controllers::PowerGlove powerGlove
          
 Nes::Core::Input::Controllers::PowerPad powerPad
          
 Nes::Core::Input::Controllers::SuborKeyboard suborKeyboard
          
 Nes::Core::Input::Controllers::TopRider topRider
          
 Nes::Core::Input::Controllers::VsSystem vsSystem
          
 Nes::Core::Input::Controllers::Zapper zapper
          
 
Constructor Summary
Controllers()
          
 

Field Detail

bandaiHyperShot

public Nes::Core::Input::Controllers::BandaiHyperShot bandaiHyperShot;

crazyClimber

public Nes::Core::Input::Controllers::CrazyClimber crazyClimber;

doremikkoKeyboard

public Nes::Core::Input::Controllers::DoremikkoKeyboard doremikkoKeyboard;

excitingBoxing

public Nes::Core::Input::Controllers::ExcitingBoxing excitingBoxing;

familyKeyboard

public Nes::Core::Input::Controllers::FamilyKeyboard familyKeyboard;

familyTrainer

public Nes::Core::Input::Controllers::FamilyTrainer familyTrainer;

horiTrack

public Nes::Core::Input::Controllers::HoriTrack horiTrack;

karaokeStudio

public Nes::Core::Input::Controllers::KaraokeStudio karaokeStudio;

konamiHyperShot

public Nes::Core::Input::Controllers::KonamiHyperShot konamiHyperShot;

mahjong

public Nes::Core::Input::Controllers::Mahjong mahjong;

mouse

public Nes::Core::Input::Controllers::Mouse mouse;

oekaKidsTablet

public Nes::Core::Input::Controllers::OekaKidsTablet oekaKidsTablet;

pachinko

public Nes::Core::Input::Controllers::Pachinko pachinko;

pad

public Nes::Core::Input::Controllers::Pad pad[ NUM_PADS ];

paddle

public Nes::Core::Input::Controllers::Paddle paddle;

partyTap

public Nes::Core::Input::Controllers::PartyTap partyTap;

pokkunMoguraa

public Nes::Core::Input::Controllers::PokkunMoguraa pokkunMoguraa;

powerGlove

public Nes::Core::Input::Controllers::PowerGlove powerGlove;

powerPad

public Nes::Core::Input::Controllers::PowerPad powerPad;

suborKeyboard

public Nes::Core::Input::Controllers::SuborKeyboard suborKeyboard;

topRider

public Nes::Core::Input::Controllers::TopRider topRider;

vsSystem

public Nes::Core::Input::Controllers::VsSystem vsSystem;

zapper

public Nes::Core::Input::Controllers::Zapper zapper;


Constructor Detail

Controllers

public Controllers() throw();

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Input.html000066400000000000000000000076771411157722000221410ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Input
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Namespace Nes::Core::Input


namespace Nes::Core::Input


Inner Classes, Typedefs, and Enums
class Nes::Core::Input::Controllers
          
 
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Sound..Output..LockCallback.html000066400000000000000000000104601411157722000260510ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Sound::Output::LockCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Sound::Output::LockCallback

Sound lock callback prototype. Called right before the core is about to render sound for one frame. Non-written samples will be saved for the next frame.

Parameters:
userData - optional user data
output - object to this class
Returns:
true if output memory is valid and samples can be written to it



Details

LockCallback

public typedef bool( NST_CALLBACK* LockCallback )( void* userData, Output& output );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Sound..Output..Locker.html000066400000000000000000000113641411157722000247670ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Sound::Output::Locker
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Sound::Output::Locker

UserCallback
   |
   +--Nes::Core::Sound::Output::Locker


struct Nes::Core::Sound::Output::Locker
extends UserCallback

Sound lock callback invoker. Used internally by the core.


Method Summary
 bool operator()( Output& output ) const
          
 

Method Detail

operator()

public bool operator()( Output& output ) const;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Sound..Output..UnlockCallback.html000066400000000000000000000103071411157722000264140ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Sound::Output::UnlockCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Sound::Output::UnlockCallback

Sound unlock callback prototype. Called when the core has finished rendering sound for one frame and a previously lock was made.

Parameters:
userData - optional user data
output - object to this class



Details

UnlockCallback

public typedef void( NST_CALLBACK* UnlockCallback )( void* userData, Output& output );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Sound..Output..Unlocker.html000066400000000000000000000114021411157722000253230ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Sound::Output::Unlocker
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Sound::Output::Unlocker

UserCallback
   |
   +--Nes::Core::Sound::Output::Unlocker


struct Nes::Core::Sound::Output::Unlocker
extends UserCallback

Sound unlock callback invoker. Used internally by the core.


Method Summary
 void operator()( Output& output ) const
          
 

Method Detail

operator()

public void operator()( Output& output ) const;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Sound..Output.html000066400000000000000000000223061411157722000234710ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Sound::Output
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Class Nes::Core::Sound::Output


class Nes::Core::Sound::Output

Sound output context.


Inner Classes, Typedefs, and Enums
typedef Nes::Core::Sound::Output::LockCallback
          Sound lock callback prototype.
typedef Nes::Core::Sound::Output::UnlockCallback
          Sound unlock callback prototype.
 
Field Summary
 uint[ 2 ] length
          Length in number of samples for one frame.
 static Nes::Core::Sound::Output::Locker lockCallback
          Sound lock callback manager.
 void*[ 2 ] samples
          Pointer to sound memory to be written to.
 static Nes::Core::Sound::Output::Unlocker unlockCallback
          Sound unlock callback manager.
 
Constructor Summary
Output( void* s0 = 0, uint l0 = 0, void* s1 = 0, uint l1 = 0 )
          
 

Field Detail

length

public uint length[ 2 ];
Length in number of samples for one frame. Assign 0 to length[1] if circular buffers aren't needed. Length doesn't neccesarily need to be the same value for every frame as long as they eventually add up in relation to the emulation speed. The requested number of samples will always be written even if the length is greater than what the sound engine normally produces. Non-written samples for one frame will be carried over to the next through an internal buffer.

lockCallback

public static Nes::Core::Sound::Output::Locker lockCallback;
Sound lock callback manager. Static object used for adding the user defined callback.

samples

public void* samples[ 2 ];
Pointer to sound memory to be written to. Assign NULL to samples[1] if circular buffers aren't needed.

unlockCallback

public static Nes::Core::Sound::Output::Unlocker unlockCallback;
Sound unlock callback manager. Static object used for adding the user defined callback.


Constructor Detail

Output

public Output( void* s0 = 0, uint l0 = 0, void* s1 = 0, uint l1 = 0 );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Sound.html000066400000000000000000000111741411157722000221150ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Sound
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Namespace Nes::Core::Sound


namespace Nes::Core::Sound


Inner Classes, Typedefs, and Enums
class Nes::Core::Sound::Output
          Sound output context.
struct Nes::Core::Sound::Output::Locker
          Sound lock callback invoker.
struct Nes::Core::Sound::Output::Unlocker
          Sound unlock callback invoker.
 
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Video..Output..LockCallback.html000066400000000000000000000103451411157722000260310ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Video::Output::LockCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Video::Output::LockCallback

Surface lock callback prototype. Called right before the core is about to render to the surface.

Parameters:
userData - optional user data
output - object to this class
Returns:
true if surface is valid and can be written to



Details

LockCallback

public typedef bool( NST_CALLBACK* LockCallback )( void* userData, Output& output );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Video..Output..Locker.html000066400000000000000000000113661411157722000247470ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Video::Output::Locker
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Video::Output::Locker

UserCallback
   |
   +--Nes::Core::Video::Output::Locker


struct Nes::Core::Video::Output::Locker
extends UserCallback

Surface lock callback invoker. Used internally by the core.


Method Summary
 bool operator()( Output& output ) const
          
 

Method Detail

operator()

public bool operator()( Output& output ) const;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Video..Output..UnlockCallback.html000066400000000000000000000103041411157722000263670ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Video::Output::UnlockCallback
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Typedef Nes::Core::Video::Output::UnlockCallback

Surface unlock callback prototype. Called when the core has finished rendering to the surface and a previous locked was made.

Parameters:
userData - optional user data
output - object to this class



Details

UnlockCallback

public typedef void( NST_CALLBACK* UnlockCallback )( void* userData, Output& output );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Video..Output..Unlocker.html000066400000000000000000000114041411157722000253030ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Video::Output::Unlocker
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Struct Nes::Core::Video::Output::Unlocker

UserCallback
   |
   +--Nes::Core::Video::Output::Unlocker


struct Nes::Core::Video::Output::Unlocker
extends UserCallback

Surface unlock callback invoker. Used internally by the core.


Method Summary
 void operator()( Output& output ) const
          
 

Method Detail

operator()

public void operator()( Output& output ) const;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Video..Output.html000066400000000000000000000215051411157722000234470ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Video::Output
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Class Nes::Core::Video::Output


class Nes::Core::Video::Output

Video output context.


Inner Classes, Typedefs, and Enums
typedef Nes::Core::Video::Output::LockCallback
          Surface lock callback prototype.
typedef Nes::Core::Video::Output::UnlockCallback
          Surface unlock callback prototype.
 
Field Summary
 static Nes::Core::Video::Output::Locker lockCallback
          Surface lock callback manager.
 long pitch
          Distance in bytes for each line in the surface memory.
 void* pixels
          Pointer to surface memory to be written to.
 static Nes::Core::Video::Output::Unlocker unlockCallback
          Surface unlock callback manager.
 
Constructor Summary
Output( void* v = 0, long p = 0 )
          
 

Field Detail

lockCallback

public static Nes::Core::Video::Output::Locker lockCallback;
Surface lock callback manager. Static object used for adding the user defined callback.

pitch

public long pitch;
Distance in bytes for each line in the surface memory. Must be equal to or greater than the actual NES screen width. Value is allowed to be negative.

pixels

public void* pixels;
Pointer to surface memory to be written to. Size must be equal to or greater than bitsPerPixel/8 * NES screen width * NES screen height.

unlockCallback

public static Nes::Core::Video::Output::Unlocker unlockCallback;
Surface unlock callback manager. Static object used for adding the user defined callback.


Constructor Detail

Output

public Output( void* v = 0, long p = 0 );

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core..Video.html000066400000000000000000000112001411157722000220610ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Video
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Namespace Nes::Core::Video


namespace Nes::Core::Video


Inner Classes, Typedefs, and Enums
class Nes::Core::Video::Output
          Video output context.
struct Nes::Core::Video::Output::Locker
          Surface lock callback invoker.
struct Nes::Core::Video::Output::Unlocker
          Surface unlock callback invoker.
 
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes..Core.html000066400000000000000000000106721411157722000207520ustar00rootroot00000000000000 Nestopia Core API: Nes::Core
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Namespace Nes::Core


namespace Nes::Core


Inner Classes, Typedefs, and Enums
namespace Nes::Core::Input
          
namespace Nes::Core::Sound
          
namespace Nes::Core::Video
          
 
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/Nes.html000066400000000000000000000101031411157722000177720ustar00rootroot00000000000000 Nestopia Core API: Nes
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

api
Namespace Nes


namespace Nes


Inner Classes, Typedefs, and Enums
namespace Nes::Api
          
namespace Nes::Core
          
 
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/api/project-frame.html000066400000000000000000000004771411157722000220200ustar00rootroot00000000000000 api api

Nes
nestopia-1.51.1/doc/details/api/project-summary.html000066400000000000000000000057331411157722000224230ustar00rootroot00000000000000 api
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES


Project api

Class Summary
 

Namespace Summary
Nes  
 


 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
nestopia-1.51.1/doc/details/api/project-tree.html000066400000000000000000000156651411157722000216720ustar00rootroot00000000000000 Hierarchy for Project api
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES

Hierarchy for Project api

Project Hierarchies:
All Projects

Class Hierarchy



 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
nestopia-1.51.1/doc/details/core/000077500000000000000000000000001411157722000165435ustar00rootroot00000000000000nestopia-1.51.1/doc/details/core/Nes..Core..CpuModel.html000066400000000000000000000115441411157722000227150ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::CpuModel
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

core
Enum Nes::Core::CpuModel


Field Summary
CPU_DENDY
          
CPU_RP2A03
          
CPU_RP2A07
          
 

Field Detail

CPU_DENDY

public CPU_DENDY

CPU_RP2A03

public CPU_RP2A03

CPU_RP2A07

public CPU_RP2A07

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/core/Nes..Core..FavoredSystem.html000066400000000000000000000124751411157722000240040ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::FavoredSystem
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

core
Enum Nes::Core::FavoredSystem


Field Summary
FAVORED_DENDY
          
FAVORED_FAMICOM
          
FAVORED_NES_NTSC
          
FAVORED_NES_PAL
          
 

Field Detail

FAVORED_DENDY

public FAVORED_DENDY

FAVORED_FAMICOM

public FAVORED_FAMICOM

FAVORED_NES_NTSC

public FAVORED_NES_NTSC

FAVORED_NES_PAL

public FAVORED_NES_PAL

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/core/Nes..Core..ImplicitBool..Type.html000066400000000000000000000075121411157722000245710ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::ImplicitBool::Type
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

core
Typedef Nes::Core::ImplicitBool::Type




Details

Type

public typedef int ImplicitBool< void >::* Type;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/core/Nes..Core..ImplicitBool.html000066400000000000000000000141771411157722000236000ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::ImplicitBool
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

core
Class Nes::Core::ImplicitBool


template < > class Nes::Core::ImplicitBool


Inner Classes, Typedefs, and Enums
typedef Nes::Core::ImplicitBool::Type
          
 
Field Summary
 int type
          
 
Method Summary
 operator ImplicitBool< void >:: Type() const
          
 

Field Detail

type

public int type;


Method Detail

Type

public operator ImplicitBool< void >::Type() const;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/core/Nes..Core..PpuModel.html000066400000000000000000000224671411157722000227400ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::PpuModel
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

core
Enum Nes::Core::PpuModel


Field Summary
PPU_DENDY
          
PPU_RC2C03B
          
PPU_RC2C03C
          
PPU_RC2C05_01
          
PPU_RC2C05_02
          
PPU_RC2C05_03
          
PPU_RC2C05_04
          
PPU_RC2C05_05
          
PPU_RP2C02
          
PPU_RP2C03B
          
PPU_RP2C03G
          
PPU_RP2C04_0001
          
PPU_RP2C04_0002
          
PPU_RP2C04_0003
          
PPU_RP2C04_0004
          
PPU_RP2C07
          
 

Field Detail

PPU_DENDY

public PPU_DENDY

PPU_RC2C03B

public PPU_RC2C03B

PPU_RC2C03C

public PPU_RC2C03C

PPU_RC2C05_01

public PPU_RC2C05_01

PPU_RC2C05_02

public PPU_RC2C05_02

PPU_RC2C05_03

public PPU_RC2C05_03

PPU_RC2C05_04

public PPU_RC2C05_04

PPU_RC2C05_05

public PPU_RC2C05_05

PPU_RP2C02

public PPU_RP2C02

PPU_RP2C03B

public PPU_RP2C03B

PPU_RP2C03G

public PPU_RP2C03G

PPU_RP2C04_0001

public PPU_RP2C04_0001

PPU_RP2C04_0002

public PPU_RP2C04_0002

PPU_RP2C04_0003

public PPU_RP2C04_0003

PPU_RP2C04_0004

public PPU_RP2C04_0004

PPU_RP2C07

public PPU_RP2C07

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/core/Nes..Core..Region.html000066400000000000000000000110331411157722000224210ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::Region
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

core
Enum Nes::Core::Region


Field Summary
REGION_NTSC
          
REGION_PAL
          
 

Field Detail

REGION_NTSC

public REGION_NTSC

REGION_PAL

public REGION_PAL

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/core/Nes..Core..System.html000066400000000000000000000162001411157722000224630ustar00rootroot00000000000000 Nestopia Core API: Nes::Core::System
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

core
Enum Nes::Core::System


Field Summary
SYSTEM_DENDY
          
SYSTEM_FAMICOM
          
SYSTEM_NES_NTSC
          
SYSTEM_NES_PAL
          
SYSTEM_NES_PAL_A
          
SYSTEM_NES_PAL_B
          
SYSTEM_PLAYCHOICE_10
          
SYSTEM_VS_DUALSYSTEM
          
SYSTEM_VS_UNISYSTEM
          
 

Field Detail

SYSTEM_DENDY

public SYSTEM_DENDY

SYSTEM_FAMICOM

public SYSTEM_FAMICOM

SYSTEM_NES_NTSC

public SYSTEM_NES_NTSC

SYSTEM_NES_PAL

public SYSTEM_NES_PAL

SYSTEM_NES_PAL_A

public SYSTEM_NES_PAL_A

SYSTEM_NES_PAL_B

public SYSTEM_NES_PAL_B

SYSTEM_PLAYCHOICE_10

public SYSTEM_PLAYCHOICE_10

SYSTEM_VS_DUALSYSTEM

public SYSTEM_VS_DUALSYSTEM

SYSTEM_VS_UNISYSTEM

public SYSTEM_VS_UNISYSTEM

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/core/Nes..Core.html000066400000000000000000000147561411157722000211400ustar00rootroot00000000000000 Nestopia Core API: Nes::Core
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

core
Namespace Nes::Core


namespace Nes::Core


Inner Classes, Typedefs, and Enums
enum Nes::Core::CpuModel
          
enum Nes::Core::FavoredSystem
          
class Nes::Core::ImplicitBool
          
enum Nes::Core::PpuModel
          
enum Nes::Core::Region
          
enum Nes::Core::System
          
 
Field Summary
 < typename T > class Nes::Core::ImplicitBool
          
 

Field Detail

ImplicitBool

public < typename T > class Nes::Core::ImplicitBool;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/core/Nes..Result.html000066400000000000000000000330371411157722000215170ustar00rootroot00000000000000 Nestopia Core API: Nes::Result
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

core
Enum Nes::Result

General result codes.


Field Summary
RESULT_ERR_CORRUPT_FILE = -6
          Corrupt file.
RESULT_ERR_GENERIC = -1
          Generic error.
RESULT_ERR_INVALID_CRC = -7
          Invalid CRC checksum.
RESULT_ERR_INVALID_FILE = -5
          Invalid file.
RESULT_ERR_INVALID_PARAM = -4
          Invalid parameter(s).
RESULT_ERR_MISSING_BIOS = -12
          Missing FDS BIOS.
RESULT_ERR_NOT_READY = -3
          System not ready.
RESULT_ERR_OUT_OF_MEMORY = -2
          Out of memory.
RESULT_ERR_UNSUPPORTED = -8
          Unsupported operation.
RESULT_ERR_UNSUPPORTED_FILE_VERSION = -9
          File format version is no longer supported.
RESULT_ERR_UNSUPPORTED_MAPPER = -11
          Unsupported or malformed mapper.
RESULT_ERR_UNSUPPORTED_VSSYSTEM = -10
          Vs DualSystem is unsupported.
RESULT_ERR_WRONG_MODE = -13
          NTSC/PAL region mismatch.
RESULT_NOP = 1
          Success but operation had no effect.
RESULT_OK = 0
          Success.
RESULT_WARN_BAD_CROM = 4
          Success but CHR-ROM may be bad.
RESULT_WARN_BAD_DUMP = 2
          Success but image dump may be bad.
RESULT_WARN_BAD_FILE_HEADER = 5
          Success but file header may have incorrect data.
RESULT_WARN_BAD_PROM = 3
          Success but PRG-ROM may be bad.
RESULT_WARN_DATA_REPLACED = 8
          Success but data may have been replaced.
RESULT_WARN_SAVEDATA_LOST = 6
          Success but save data has been lost.
 

Field Detail

RESULT_ERR_CORRUPT_FILE

public RESULT_ERR_CORRUPT_FILE = -6
Corrupt file.

RESULT_ERR_GENERIC

public RESULT_ERR_GENERIC = -1
Generic error.

RESULT_ERR_INVALID_CRC

public RESULT_ERR_INVALID_CRC = -7
Invalid CRC checksum.

RESULT_ERR_INVALID_FILE

public RESULT_ERR_INVALID_FILE = -5
Invalid file.

RESULT_ERR_INVALID_PARAM

public RESULT_ERR_INVALID_PARAM = -4
Invalid parameter(s).

RESULT_ERR_MISSING_BIOS

public RESULT_ERR_MISSING_BIOS = -12
Missing FDS BIOS.

RESULT_ERR_NOT_READY

public RESULT_ERR_NOT_READY = -3
System not ready.

RESULT_ERR_OUT_OF_MEMORY

public RESULT_ERR_OUT_OF_MEMORY = -2
Out of memory.

RESULT_ERR_UNSUPPORTED

public RESULT_ERR_UNSUPPORTED = -8
Unsupported operation.

RESULT_ERR_UNSUPPORTED_FILE_VERSION

public RESULT_ERR_UNSUPPORTED_FILE_VERSION = -9
File format version is no longer supported.

RESULT_ERR_UNSUPPORTED_MAPPER

public RESULT_ERR_UNSUPPORTED_MAPPER = -11
Unsupported or malformed mapper.

RESULT_ERR_UNSUPPORTED_VSSYSTEM

public RESULT_ERR_UNSUPPORTED_VSSYSTEM = -10
Vs DualSystem is unsupported.

RESULT_ERR_WRONG_MODE

public RESULT_ERR_WRONG_MODE = -13
NTSC/PAL region mismatch.

RESULT_NOP

public RESULT_NOP = 1
Success but operation had no effect.

RESULT_OK

public RESULT_OK = 0
Success.

RESULT_WARN_BAD_CROM

public RESULT_WARN_BAD_CROM = 4
Success but CHR-ROM may be bad.

RESULT_WARN_BAD_DUMP

public RESULT_WARN_BAD_DUMP = 2
Success but image dump may be bad.

RESULT_WARN_BAD_FILE_HEADER

public RESULT_WARN_BAD_FILE_HEADER = 5
Success but file header may have incorrect data.

RESULT_WARN_BAD_PROM

public RESULT_WARN_BAD_PROM = 3
Success but PRG-ROM may be bad.

RESULT_WARN_DATA_REPLACED

public RESULT_WARN_DATA_REPLACED = 8
Success but data may have been replaced.

RESULT_WARN_SAVEDATA_LOST

public RESULT_WARN_SAVEDATA_LOST = 6
Success but save data has been lost.

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/core/Nes..byte.html000066400000000000000000000073541411157722000212070ustar00rootroot00000000000000 Nestopia Core API: Nes::byte
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

core
Typedef Nes::byte




Details

byte

public typedef unsigned char byte;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/core/Nes..dword.html000066400000000000000000000073641411157722000213640ustar00rootroot00000000000000 Nestopia Core API: Nes::dword
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

core
Typedef Nes::dword




Details

dword

public typedef unsigned char dword;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/core/Nes..schar.html000066400000000000000000000073621411157722000213430ustar00rootroot00000000000000 Nestopia Core API: Nes::schar
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

core
Typedef Nes::schar




Details

schar

public typedef signed char schar;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/core/Nes..uchar.html000066400000000000000000000073641411157722000213470ustar00rootroot00000000000000 Nestopia Core API: Nes::uchar
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

core
Typedef Nes::uchar




Details

uchar

public typedef unsigned char uchar;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/core/Nes..uint.html000066400000000000000000000073531411157722000212220ustar00rootroot00000000000000 Nestopia Core API: Nes::uint
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

core
Typedef Nes::uint




Details

uint

public typedef unsigned int uint;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/core/Nes..ulong.html000066400000000000000000000073641411157722000213710ustar00rootroot00000000000000 Nestopia Core API: Nes::ulong
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

core
Typedef Nes::ulong




Details

ulong

public typedef unsigned long ulong;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/core/Nes..ushort.html000066400000000000000000000073751411157722000215730ustar00rootroot00000000000000 Nestopia Core API: Nes::ushort
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

core
Typedef Nes::ushort




Details

ushort

public typedef unsigned short ushort;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/core/Nes..word.html000066400000000000000000000073541411157722000212170ustar00rootroot00000000000000 Nestopia Core API: Nes::word
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

core
Typedef Nes::word




Details

word

public typedef unsigned char word;

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/core/Nes.html000066400000000000000000000143321411157722000201610ustar00rootroot00000000000000 Nestopia Core API: Nes
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

core
Namespace Nes


namespace Nes


Inner Classes, Typedefs, and Enums
typedef Nes::byte
          
namespace Nes::Core
          
typedef Nes::dword
          
enum Nes::Result
          General result codes.
typedef Nes::schar
          
typedef Nes::uchar
          
typedef Nes::uint
          
typedef Nes::ulong
          
typedef Nes::ushort
          
typedef Nes::word
          
 
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
SUMMARY:  INNER | FIELD | CONSTR | METHOD

nestopia-1.51.1/doc/details/core/project-frame.html000066400000000000000000000005021411157722000221640ustar00rootroot00000000000000 core core

Nes
nestopia-1.51.1/doc/details/core/project-summary.html000066400000000000000000000057361411157722000226050ustar00rootroot00000000000000 core
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES


Project core

Class Summary
 

Namespace Summary
Nes  
 


 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
nestopia-1.51.1/doc/details/core/project-tree.html000066400000000000000000000100771411157722000220410ustar00rootroot00000000000000 Hierarchy for Project core
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES

Hierarchy for Project core

Project Hierarchies:
All Projects

Class Hierarchy



 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
nestopia-1.51.1/doc/index-all.html000066400000000000000000007374471411157722000167570ustar00rootroot00000000000000 Nestopia Core API
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z _

A

adapter - member variable in struct Nes::Api::Cartridge::Profile::Game
Utilized controller adapter.
ADAPTER_FAMICOM - field in enum Nes::Api::Input::Adapter
Famicom adapter.
ADAPTER_NES - field in enum Nes::Api::Input::Adapter
NES adapter.
AdapterCallback - member variable in typedef Nes::Api::Input::AdapterCallback
adapterCallback - static variable in class Nes::Api::Input
Adapter event callback manager.
address - member variable in struct Nes::Api::Cheats::Code
Address.
address - member variable in struct Nes::Api::Fds::DiskData::File
File address.
ALL_CHANNELS - field in enum Nes::Api::Sound::Channel
All channels.
allowSimulAxes - member variable in struct Nes::Core::Input::Controllers::Pad
altTitle - member variable in struct Nes::Api::Cartridge::Profile::Game
Alternative game title.
ANSWER_DEFAULT - field in enum Nes::Api::User::Answer
Default answer (default).
ANSWER_NO - field in enum Nes::Api::User::Answer
No.
ANSWER_YES - field in enum Nes::Api::User::Answer
Yes.
APPEND - field in enum Nes::Api::Movie::How
Keep any previous content.
APU_CHANNELS - field in enum Nes::Api::Sound::Channel
All NES APU channels.
AreUnlimSpritesEnabled() - member function in class Nes::Api::Video
Checks if the PPU sprite software extension is enabled.
ASK_PROFILE - field in enum Nes::Api::Machine::AskProfile
Trigger callback.
Assign(const char*,const char*) - member function in class Nes::Api::Cartridge::Profile::Hash
Assigns new checksum from null-terminated strings.
Assign(const dword*,dword) - member function in class Nes::Api::Cartridge::Profile::Hash
Assigns new checksum from input values.
Assign(const wchar_t*,const wchar_t*) - member function in class Nes::Api::Cartridge::Profile::Hash
Assigns new checksum from null-terminated wide-strings.
AutoSelectAdapter() - member function in class Nes::Api::Input
Connects the most suited adapter for a game.
AutoSelectController(uint) - member function in class Nes::Api::Input
Connects the most suited controller for a game into a port.
AutoSelectControllers() - member function in class Nes::Api::Input
Connects the most suited controllers for a game into all ports.
axes - member variable in struct Nes::Api::Video::Decoder

B

b - member variable in struct Nes::Api::Video::RenderState::Bits::Mask
BACKWARD - field in enum Nes::Api::Rewinder::Direction
Backward.
BAD - field in enum Nes::Api::Cartridge::Profile::Dump::State
Bad dump.
bandaiHyperShot - member variable in class Nes::Core::Input::Controllers
BANDAIHYPERSHOT - field in enum Nes::Api::Input::Type
Bandai hypershot.
BandaiHyperShot() - constructor in struct Nes::Core::Input::Controllers::BandaiHyperShot
BarcodeReader(T&) - constructor in class Nes::Api::BarcodeReader
Interface constructor.
BARCODEWORLD - field in enum Nes::Api::Input::Type
Barcode World.
battery - member variable in struct Nes::Api::Cartridge::Profile::Board::Ram
Battery connected to RAM chip.
battery - member variable in struct Nes::Api::Cartridge::Profile::Board::Chip
battery connected to custom chip.
bits - member variable in struct Nes::Api::Video::RenderState
Pixel context.
Blit(Output&) - member function in class Nes::Api::Video
Performs a manual blit to the video output object.
board - member variable in struct Nes::Api::Cartridge::Profile
Board context.
Board() - constructor in class Nes::Api::Cartridge::Profile::Board
~Board() - constructor in class Nes::Api::Cartridge::Profile::Board
boostYellow - member variable in struct Nes::Api::Video::Decoder
button - member variable in struct Nes::Core::Input::Controllers::Mouse
button - member variable in struct Nes::Core::Input::Controllers::OekaKidsTablet
button - member variable in struct Nes::Core::Input::Controllers::Paddle
buttons - member variable in struct Nes::Core::Input::Controllers::KonamiHyperShot
buttons - member variable in struct Nes::Core::Input::Controllers::PokkunMoguraa
buttons - member variable in struct Nes::Core::Input::Controllers::Pachinko
buttons - member variable in struct Nes::Core::Input::Controllers::PowerGlove
buttons - member variable in struct Nes::Core::Input::Controllers::Pad
buttons - member variable in struct Nes::Core::Input::Controllers::HoriTrack
buttons - member variable in struct Nes::Core::Input::Controllers::TopRider
buttons - member variable in struct Nes::Core::Input::Controllers::KaraokeStudio
buttons - member variable in struct Nes::Core::Input::Controllers::Mahjong
buttons - member variable in struct Nes::Core::Input::Controllers::ExcitingBoxing
by - member variable in struct Nes::Api::Cartridge::Profile::Dump
Dumped by.
bypassChecksum - member variable in struct Nes::Api::Machine::Patch
Set to true to bypass checksum validation.
byte - member variable in typedef Nes::byte

C

callback - static variable in struct Nes::Core::Input::Controllers::VsSystem
callback - static variable in struct Nes::Core::Input::Controllers::KaraokeStudio
callback - static variable in struct Nes::Core::Input::Controllers::TopRider
callback - static variable in struct Nes::Core::Input::Controllers::ExcitingBoxing
callback - static variable in struct Nes::Core::Input::Controllers::Mouse
callback - static variable in struct Nes::Core::Input::Controllers::BandaiHyperShot
callback - static variable in struct Nes::Core::Input::Controllers::Mahjong
callback - static variable in struct Nes::Core::Input::Controllers::Paddle
callback - static variable in struct Nes::Core::Input::Controllers::OekaKidsTablet
callback - static variable in struct Nes::Core::Input::Controllers::Zapper
callback - static variable in struct Nes::Core::Input::Controllers::CrazyClimber
callback - static variable in struct Nes::Core::Input::Controllers::DoremikkoKeyboard
callback - static variable in struct Nes::Core::Input::Controllers::PartyTap
callback - static variable in struct Nes::Core::Input::Controllers::KonamiHyperShot
callback - static variable in struct Nes::Core::Input::Controllers::PokkunMoguraa
callback - static variable in struct Nes::Core::Input::Controllers::PowerGlove
callback - static variable in struct Nes::Core::Input::Controllers::Pachinko
callback - static variable in struct Nes::Core::Input::Controllers::FamilyKeyboard
callback - static variable in struct Nes::Core::Input::Controllers::FamilyTrainer
callback - static variable in struct Nes::Core::Input::Controllers::PowerPad
callback - static variable in struct Nes::Core::Input::Controllers::Pad
callback - static variable in struct Nes::Core::Input::Controllers::HoriTrack
callback - static variable in struct Nes::Core::Input::Controllers::SuborKeyboard
CanChangeDiskSide() - member function in class Nes::Api::Fds
Checks if the current disk can change side.
CanModify() - member function in class Nes::Api::DipSwitches
Checks if the DIP switches can be changed at this time.
CanTransfer() - member function in class Nes::Api::BarcodeReader
Checks if the reader is ready to scan.
Cartridge(T&) - constructor in class Nes::Api::Cartridge
Interface constructor.
catalog - member variable in struct Nes::Api::Cartridge::Profile::Game
Catalog.
ChangeSide() - member function in class Nes::Api::Fds
Changes disk side.
CHANNEL_DPCM - field in enum Nes::Api::Sound::Channel
DPCM channel.
CHANNEL_FDS - field in enum Nes::Api::Sound::Channel
FDS sound chip channel.
CHANNEL_MMC5 - field in enum Nes::Api::Sound::Channel
MMC5 sound chip channel.
CHANNEL_N163 - field in enum Nes::Api::Sound::Channel
Namcot 163 sound chip channel.
CHANNEL_NOISE - field in enum Nes::Api::Sound::Channel
Noise channel.
CHANNEL_S5B - field in enum Nes::Api::Sound::Channel
Sunsoft 5B sound chip channel.
CHANNEL_SQUARE1 - field in enum Nes::Api::Sound::Channel
First square channel.
CHANNEL_SQUARE2 - field in enum Nes::Api::Sound::Channel
Second square channel.
CHANNEL_TRIANGLE - field in enum Nes::Api::Sound::Channel
Triangle channel.
CHANNEL_VRC6 - field in enum Nes::Api::Sound::Channel
Konami VRC6 sound chip channel.
CHANNEL_VRC7 - field in enum Nes::Api::Sound::Channel
Konami VRC7 sound chip channel.
Cheats(T&) - constructor in class Nes::Api::Cheats
Interface constructor.
Chip() - constructor in struct Nes::Api::Cartridge::Profile::Board::Chip
Chips - member variable in typedef Nes::Api::Cartridge::Profile::Board::Chips
chips - member variable in class Nes::Api::Cartridge::Profile::Board
Custom chips.
ChooseProfileCallback - member variable in typedef Nes::Api::Cartridge::ChooseProfileCallback
chooseProfileCallback - static variable in class Nes::Api::Cartridge
Cartridge profile chooser callback manager.
Chr - member variable in typedef Nes::Api::Cartridge::Profile::Board::Chr
chr - member variable in class Nes::Api::Cartridge::Profile::Board
CHR-ROM.
chrNvRam - member variable in struct Nes::Api::Cartridge::NesHeader
Non-volatile CHR-RAM (aka V-RAM) size.
chrRam - member variable in struct Nes::Api::Cartridge::NesHeader
volatile CHR-RAM (aka V-RAM) size.
chrRom - member variable in struct Nes::Api::Cartridge::NesHeader
CHR-ROM size.
cic - member variable in class Nes::Api::Cartridge::Profile::Board
CIC type.
CLEAN - field in enum Nes::Api::Movie::How
Overwrite any previous content.
Clear() - member function in struct Nes::Api::Cartridge::NesHeader
Clears settings.
Clear() - member function in class Nes::Api::Cartridge::Profile::Hash
Clears the current checksum.
ClearCodes() - member function in class Nes::Api::Cheats
Removes all existing codes.
clss - member variable in struct Nes::Api::Cartridge::Profile::Game
Class.
Code(ushort,uchar,uchar,bool) - constructor in struct Nes::Api::Cheats::Code
Constructor.
Colors - member variable in typedef Nes::Api::Video::Palette::Colors
compare - member variable in struct Nes::Api::Cheats::Code
Compare-value.
Compute(const void*,ulong) - member function in class Nes::Api::Cartridge::Profile::Hash
Computes and updates checksum from input.
ConnectAdapter(Adapter) - member function in class Nes::Api::Input
Connects an adapter.
ConnectController(uint,Type) - member function in class Nes::Api::Input
Connects a controller to a port.
controllerCallback - static variable in class Nes::Api::Input
Controller event callback manager.
ControllerCallback - member variable in typedef Nes::Api::Input::ControllerCallback
Controllers - member variable in typedef Nes::Api::Input::Controllers
controllers - member variable in struct Nes::Api::Cartridge::Profile::Game
Utilized controllers.
Controllers() - constructor in class Nes::Core::Input::Controllers
count - member variable in struct Nes::Api::Video::RenderState::Bits
Bits per pixel.
cpu - member variable in struct Nes::Api::Cartridge::Profile::System
CPU type.
CPU_DENDY - field in enum Nes::Api::Cartridge::Profile::System::Cpu
Dendy CPU (clone).
CPU_DENDY - field in enum Nes::Core::CpuModel
CPU_RP2A03 - field in enum Nes::Api::Cartridge::Profile::System::Cpu
RP2A03 NTSC CPU.
CPU_RP2A03 - field in enum Nes::Core::CpuModel
CPU_RP2A07 - field in enum Nes::Core::CpuModel
CPU_RP2A07 - field in enum Nes::Api::Cartridge::Profile::System::Cpu
RP2A07 PAL CPU.
CRAZYCLIMBER - field in enum Nes::Api::Input::Type
Crazy Climber.
crazyClimber - member variable in class Nes::Core::Input::Controllers
CrazyClimber() - constructor in struct Nes::Core::Input::Controllers::CrazyClimber

D

Data - member variable in typedef Nes::Api::Fds::DiskData::Data
data - member variable in struct Nes::Api::Fds::DiskData::File
File content.
Database(Core::Machine&) - constructor in class Nes::Api::Cartridge::Database
Interface constructor.
date - member variable in struct Nes::Api::Cartridge::Profile::Dump
Dump date.
Decoder(DecoderPreset) - constructor in struct Nes::Api::Video::Decoder
Constructor.
DECODER_ALTERNATIVE - field in enum Nes::Api::Video::DecoderPreset
Alternative
DECODER_CANONICAL - field in enum Nes::Api::Video::DecoderPreset
Canonical (default)
DECODER_CONSUMER - field in enum Nes::Api::Video::DecoderPreset
Consumer
DeleteCode(ulong) - member function in class Nes::Api::Cheats
Removes an existing code.
DENDY - field in enum Nes::Api::Cartridge::Profile::System::Type
Dendy console (clone).
developer - member variable in struct Nes::Api::Cartridge::Profile::Game
Developer.
DipSwitches(T&) - constructor in class Nes::Api::DipSwitches
Interface constructor.
DISK_EJECT - field in enum Nes::Api::Fds::Event
Disk has been ejected.
DISK_INSERT - field in enum Nes::Api::Fds::Event
Disk has been inserted.
DISK_NONSTANDARD - field in enum Nes::Api::Fds::Event
Disk is in a non-standard format.
DiskCallback - member variable in typedef Nes::Api::Fds::DiskCallback
diskCallback - static variable in class Nes::Api::Fds
Disk event callback manager.
DiskData() - constructor in struct Nes::Api::Fds::DiskData
~DiskData() - constructor in struct Nes::Api::Fds::DiskData
distance - member variable in struct Nes::Core::Input::Controllers::PowerGlove
DONT_ASK_PROFILE - field in enum Nes::Api::Machine::AskProfile
Don't trigger callback (default).
doremikkoKeyboard - member variable in class Nes::Core::Input::Controllers
DOREMIKKOKEYBOARD - field in enum Nes::Api::Input::Type
Doremikko keyboard.
DoremikkoKeyboard() - constructor in struct Nes::Core::Input::Controllers::DoremikkoKeyboard
DriveCallback - member variable in typedef Nes::Api::Fds::DriveCallback
driveCallback - static variable in class Nes::Api::Fds
Drive event callback manager.
dump - member variable in struct Nes::Api::Cartridge::Profile
Dump context.
Dump() - constructor in struct Nes::Api::Cartridge::Profile::Dump
dword - member variable in typedef Nes::dword

E

Eject() - member function in class Nes::Api::Movie
Deprecated. @deprecated
EjectDisk() - member function in class Nes::Api::Fds
Ejects disk.
EmptyBuffer() - member function in class Nes::Api::Sound
Empties the internal sound buffer.
Emulator() - constructor in class Nes::Api::Emulator
~Emulator() - constructor in class Nes::Api::Emulator
Enable(bool) - member function in class Nes::Api::Rewinder
Enables rewinder.
Enable(bool) - member function in class Nes::Api::Cartridge::Database
Enables image corrections.
EnableFieldMerging(bool) - member function in class Nes::Api::Video
Enables field merging for the NTSC filter.
EnableSound(bool) - member function in class Nes::Api::Rewinder
Enables backward sound.
EnableUnlimSprites(bool) - member function in class Nes::Api::Video
Allows the PPU to render more than eight sprites per line.
Entry() - constructor in class Nes::Api::Cartridge::Database::Entry
Default constructor.
EVENT_CPU_JAM - field in enum Nes::Api::User::Event
CPU jam.
EVENT_CPU_UNOFFICIAL_OPCODE - field in enum Nes::Api::User::Event
An unofficial CPU opcode was executed.
EVENT_DISPLAY_TIMER - field in enum Nes::Api::User::Event
Can display an in-game timer.
EVENT_LOAD - field in enum Nes::Api::Machine::Event
A new image has been loaded into the system.
EVENT_MODE_NTSC - field in enum Nes::Api::Machine::Event
Mode has changed to NTSC.
EVENT_MODE_PAL - field in enum Nes::Api::Machine::Event
Mode has changed to PAL.
EVENT_PLAY_SONG - field in enum Nes::Api::Nsf::Event
EVENT_PLAYING - field in enum Nes::Api::TapeRecorder::Event
Tape is playing.
EVENT_PLAYING - field in enum Nes::Api::Movie::Event
Movie has started playing.
EVENT_PLAYING_STOPPED - field in enum Nes::Api::Movie::Event
Movie has stopped playing.
EVENT_POWER_OFF - field in enum Nes::Api::Machine::Event
Machine power OFF.
EVENT_POWER_ON - field in enum Nes::Api::Machine::Event
Machine power ON.
EVENT_RECORDING - field in enum Nes::Api::Movie::Event
Movie has started recording.
EVENT_RECORDING - field in enum Nes::Api::TapeRecorder::Event
Tape is recording.
EVENT_RECORDING_STOPPED - field in enum Nes::Api::Movie::Event
Movie has stopped recording.
EVENT_RESET_HARD - field in enum Nes::Api::Machine::Event
Machine hard-reset.
EVENT_RESET_SOFT - field in enum Nes::Api::Machine::Event
Machine soft-reset.
EVENT_SELECT_SONG - field in enum Nes::Api::Nsf::Event
A new song has been selected.
EVENT_STOP_SONG - field in enum Nes::Api::Nsf::Event
Song has stopped playing.
EVENT_STOPPED - field in enum Nes::Api::TapeRecorder::Event
Tape has stopped playing or recording.
EVENT_UNLOAD - field in enum Nes::Api::Machine::Event
An image has been unloaded from the system.
eventCallback - static variable in class Nes::Api::Nsf
Event callback manager.
EventCallback - member variable in typedef Nes::Api::Machine::EventCallback
EventCallback - member variable in typedef Nes::Api::Movie::EventCallback
EventCallback - member variable in typedef Nes::Api::User::EventCallback
eventCallback - static variable in class Nes::Api::TapeRecorder
Tape event callback manager.
eventCallback - static variable in class Nes::Api::Movie
Movie event callback manager.
EventCallback - member variable in typedef Nes::Api::TapeRecorder::EventCallback
eventCallback - static variable in class Nes::Api::User
User event callback manager.
EventCallback - member variable in typedef Nes::Api::Nsf::EventCallback
eventCallback - static variable in class Nes::Api::Machine
Machine event callback manager.
excitingBoxing - member variable in class Nes::Core::Input::Controllers
EXCITINGBOXING - field in enum Nes::Api::Input::Type
Exciting Boxing.
ExcitingBoxing() - constructor in struct Nes::Core::Input::Controllers::ExcitingBoxing
Execute(Core::Video::Output*,Core::Sound::Output*,Core::Input::Controllers*) - member function in class Nes::Api::Emulator
Executes one frame.
Export(void*,ulong) - member function in struct Nes::Api::Cartridge::NesHeader
Exports settings to iNES file header in memory.
EXT_CHANNELS - field in enum Nes::Api::Sound::Channel
All external sound chip channels.
EXT_PALETTE - field in enum Nes::Api::Video::Palette::CustomType
Extended palette.

F

FAMICOM - field in enum Nes::Api::Cartridge::Profile::System::Type
Famicom console.
familyKeyboard - member variable in class Nes::Core::Input::Controllers
FAMILYKEYBOARD - field in enum Nes::Api::Input::Type
Family keyboard.
FamilyKeyboard() - constructor in struct Nes::Core::Input::Controllers::FamilyKeyboard
familyTrainer - member variable in class Nes::Core::Input::Controllers
FAMILYTRAINER - field in enum Nes::Api::Input::Type
Family Trainer.
FamilyTrainer() - constructor in struct Nes::Core::Input::Controllers::FamilyTrainer
FAVORED_DENDY - field in enum Nes::Api::Machine::FavoredSystem
Dendy (clone).
FAVORED_DENDY - field in enum Nes::Core::FavoredSystem
FAVORED_FAMICOM - field in enum Nes::Core::FavoredSystem
FAVORED_FAMICOM - field in enum Nes::Api::Machine::FavoredSystem
Famicom.
FAVORED_NES_NTSC - field in enum Nes::Core::FavoredSystem
FAVORED_NES_NTSC - field in enum Nes::Api::Machine::FavoredSystem
NES NTSC.
FAVORED_NES_PAL - field in enum Nes::Core::FavoredSystem
FAVORED_NES_PAL - field in enum Nes::Api::Machine::FavoredSystem
NES PAL.
Fds(T&) - constructor in class Nes::Api::Fds
Interface constructor.
file - member variable in struct Nes::Api::Cartridge::Profile::Board::Chip
File pointing to custom chip.
file - member variable in struct Nes::Api::Cartridge::Profile::Board::Ram
File pointing to RAM chip.
file - member variable in struct Nes::Api::Cartridge::Profile::Board::Rom
File pointing to ROM chip.
file - member variable in struct Nes::Api::Cartridge::Profile::Board::Sample
Sound sample file.
File() - constructor in struct Nes::Api::Fds::DiskData::File
FileIoCallback - member variable in typedef Nes::Api::User::FileIoCallback
fileIoCallback - static variable in class Nes::Api::User
File IO callback manager.
Files - member variable in typedef Nes::Api::Fds::DiskData::Files
files - member variable in struct Nes::Api::Fds::DiskData
Files.
filter - member variable in struct Nes::Api::Video::RenderState
Filter.
FILTER_2XSAI - field in enum Nes::Api::Video::RenderState::Filter
2xSaI filter.
FILTER_HQ2X - field in enum Nes::Api::Video::RenderState::Filter
Hq2x filter.
FILTER_HQ3X - field in enum Nes::Api::Video::RenderState::Filter
Hq3x filter.
FILTER_HQ4X - field in enum Nes::Api::Video::RenderState::Filter
Hq4x filter.
FILTER_NONE - field in enum Nes::Api::Video::RenderState::Filter
No filter (default).
FILTER_NTSC - field in enum Nes::Api::Video::RenderState::Filter
NTSC filter.
FILTER_SCALE2X - field in enum Nes::Api::Video::RenderState::Filter
Scale2x filter.
FILTER_SCALE3X - field in enum Nes::Api::Video::RenderState::Filter
Scale3x filter.
FindEntry(const Profile::Hash&,Machine::FavoredSystem) - member function in class Nes::Api::Cartridge::Database
Attempts to locate and return an entry from one of the databases.
FindEntry(const void*,ulong,Machine::FavoredSystem) - member function in class Nes::Api::Cartridge::Database
Attempts to locate and return an entry from one of the databases.
fire - member variable in struct Nes::Core::Input::Controllers::BandaiHyperShot
fire - member variable in struct Nes::Core::Input::Controllers::Zapper
FORWARD - field in enum Nes::Api::Rewinder::Direction
Forward.
Frame() - member function in class Nes::Api::Emulator
Returns the number of executed frames relative to the last machine power/reset.
function - member variable in struct Nes::Api::Cartridge::Profile::Board::Pin
Pin function.

G

g - member variable in struct Nes::Api::Video::RenderState::Bits::Mask
game - member variable in struct Nes::Api::Cartridge::Profile
Game context.
Game() - constructor in struct Nes::Api::Cartridge::Profile::Game
GameGenieDecode(const char*,Code&) - static function in class Nes::Api::Cheats
Decodes a Game Genie code.
GameGenieEncode(const Code&,char(&[ 9]) - static function in class Nes::Api::Cheats
Encodes into a Game Genie code.
gesture - member variable in struct Nes::Core::Input::Controllers::PowerGlove
GESTURE_FINGER - field in enum Nes::Core::Input::Controllers::PowerGlove::Gesture
GESTURE_FIST - field in enum Nes::Core::Input::Controllers::PowerGlove::Gesture
GESTURE_OPEN - field in enum Nes::Core::Input::Controllers::PowerGlove::Gesture
Get(char*,char*) - member function in class Nes::Api::Cartridge::Profile::Hash
Returns the current checksum.
GetAction() - member function in struct Nes::Api::User::File
Returns type of action.
GetArtist() - member function in class Nes::Api::Nsf
Returns the name of the artists.
GetBIOS(std::ostream&) - member function in class Nes::Api::Fds
Stores the current BIOS in an output stream.
GetBrightness() - member function in class Nes::Api::Video
Returns the current brightness.
GetChips() - member function in class Nes::Api::Nsf
Returns the OR:ed chips in use.
GetChr() - member function in class Nes::Api::Cartridge::Profile::Board
Returns total size of CHR-ROM.
GetChrRom() - member function in class Nes::Api::Cartridge::Database::Entry
Returns total size of CHR-ROM.
GetCode(ulong,Code&) - member function in class Nes::Api::Cheats
Returns an existing code.
GetCode(ulong,ushort*,uchar*,uchar*,bool*) - member function in class Nes::Api::Cheats
Returns attributes of an existing code.
GetColorArtifacts() - member function in class Nes::Api::Video
Returns the current color artifacts for the NTSC filter.
GetColorBleed() - member function in class Nes::Api::Video
Returns the current color bleed for the NTSC filter.
GetColorFringing() - member function in class Nes::Api::Video
Returns the current color fringing for the NTSC filter.
GetColorResolution() - member function in class Nes::Api::Video
Returns the current color resolution for the NTSC filter.
GetColors() - member function in class Nes::Api::Video::Palette
Return the current palette colors.
GetConnectedAdapter() - member function in class Nes::Api::Input
Returns the current connected adapter.
GetConnectedController(uint) - member function in class Nes::Api::Input
Returns the current connected controller.
GetContent(const void*&,ulong&) - member function in struct Nes::Api::User::File
Returns a pointer to the content to be saved and its size.
GetContent(std::ostream&) - member function in struct Nes::Api::User::File
Saves the content into an output stream.
GetContrast() - member function in class Nes::Api::Video
Returns the current contrast.
GetCopyright() - member function in class Nes::Api::Nsf
Returns the copyright string.
GetCrc32() - member function in class Nes::Api::Cartridge::Profile::Hash
Returns the current CRC-32 value.
GetCurrentDisk() - member function in class Nes::Api::Fds
Returns the current disk inserted.
GetCurrentDiskSide() - member function in class Nes::Api::Fds
Returns the current disk side.
GetCurrentSong() - member function in class Nes::Api::Nsf
Returns the current song index.
GetCustom(uchar ( *[ 3],CustomType) - member function in class Nes::Api::Video::Palette
Returns the custom palette.
GetCustomType() - member function in class Nes::Api::Video::Palette
Returns the custom palette type.
GetDatabase() - member function in class Nes::Api::Cartridge
Returns the database interface.
GetDecoder() - member function in class Nes::Api::Video
Returns the current YUV decoder.
GetDefaultMode() - member function in class Nes::Api::Video::Palette
Returns the default palette mode.
GetDesiredMode() - member function in class Nes::Api::Machine
Returns the mode most appropriate for the current image.
GetDipName(uint) - member function in class Nes::Api::DipSwitches
Returns the name of a DIP switch.
GetDirection() - member function in class Nes::Api::Rewinder
Returns the current direction.
GetDiskData(uint,DiskData&) - member function in class Nes::Api::Fds
Returns disk information.
GetDumpState() - member function in class Nes::Api::Cartridge::Database::Entry
Returns the dump state.
GetHash() - member function in class Nes::Api::Cartridge::Database::Entry
Returns hash code of ROM chips combined.
GetHue() - member function in class Nes::Api::Video
Returns the current hue.
GetId() - member function in struct Nes::Api::User::File
Returns the sound file ID to load.
GetInitAddress() - member function in class Nes::Api::Nsf
Returns the init-address.
GetLoadAddress() - member function in class Nes::Api::Nsf
Returns the load-address.
GetMapper() - member function in class Nes::Api::Cartridge::Database::Entry
Returns mapper ID.
GetMaxSize() - member function in struct Nes::Api::User::File
Returns the maximum allowed size for the content to load.
GetMode() - member function in class Nes::Api::Video::Palette
Returns the current palette mode.
GetMode() - member function in class Nes::Api::Nsf
Return the tune mode.
GetMode() - member function in class Nes::Api::Machine
Returns the current mode.
GetName() - member function in class Nes::Api::Nsf
Returns the name of the NSF.
GetName() - member function in struct Nes::Api::User::File
Returns the name of the file to load.
GetNumDisks() - member function in class Nes::Api::Fds
Returns the total number of disks.
GetNumSides() - member function in class Nes::Api::Fds
Returns the total number of disks and their sides.
GetNumSongs() - member function in class Nes::Api::Nsf
Returns the total number of songs.
GetPalette() - member function in class Nes::Api::Video
Returns the palette interface.
GetPatchContent(Patch,std::ostream&) - member function in struct Nes::Api::User::File
Saves the patch content into an output stream.
GetPlayAddress() - member function in class Nes::Api::Nsf
Returns the play-address.
GetPrg() - member function in class Nes::Api::Cartridge::Profile::Board
Returns total size of PRG-ROM.
GetPrgRom() - member function in class Nes::Api::Cartridge::Database::Entry
Returns total size of PRG-ROM.
GetProfile() - member function in class Nes::Api::Cartridge
Returns the current cartridge profile.
GetProfile(Profile&) - member function in class Nes::Api::Cartridge::Database::Entry
Returns the profile of this entry.
GetRam() - member function in class Nes::Api::Cheats
Returns read-only content of CPU RAM.
GetRegion() - member function in class Nes::Api::Cartridge::Database::Entry
Returns the target region.
GetRenderState(RenderState&) - member function in class Nes::Api::Video
Returns the current render state.
GetSampleBits() - member function in class Nes::Api::Sound
Returns the sample bits.
GetSampleRate() - member function in class Nes::Api::Sound
Returns the sample rate.
GetSaturation() - member function in class Nes::Api::Video
Returns the current saturation.
GetSha1() - member function in class Nes::Api::Cartridge::Profile::Hash
Returns the current SHA-1 values.
GetSharpness() - member function in class Nes::Api::Video
Returns the current sharpness for the NTSC filter.
GetSpeaker() - member function in class Nes::Api::Sound
Returns the speaker type.
GetSpeed() - member function in class Nes::Api::Sound
Returns the current speed.
GetStartingSong() - member function in class Nes::Api::Nsf
Returns the starting song index.
GetSystem() - member function in class Nes::Api::Cartridge::Database::Entry
Returns the target system.
GetTitle() - member function in class Nes::Api::Cartridge::Database::Entry
Returns the game title.
GetValue(uint) - member function in class Nes::Api::DipSwitches
Returns the current DIP switch value.
GetValueName(uint,uint) - member function in class Nes::Api::DipSwitches
Returns the name of a DIP switch value.
GetVolume(uint) - member function in class Nes::Api::Sound
Returns the volume of a channel.
GetVram() - member function in class Nes::Api::Cartridge::Database::Entry
Returns total size of V-RAM.
GetVram() - member function in class Nes::Api::Cartridge::Profile::Board
Returns total size of V-RAM.
GetWram() - member function in class Nes::Api::Cartridge::Profile::Board
Returns total size of W-RAM.
GetWram() - member function in class Nes::Api::Cartridge::Database::Entry
Returns total size of W-RAM.

H

HasBattery() - member function in class Nes::Api::Cartridge::Profile::Board
Returns battery status.
HasBattery() - member function in class Nes::Api::Cartridge::Database::Entry
Returns battery status.
HasBIOS() - member function in class Nes::Api::Fds
Checks if a BIOS has been loaded.
hash - member variable in struct Nes::Api::Cartridge::Profile::Board::Rom
ROM chip checksum.
hash - member variable in struct Nes::Api::Cartridge::Profile
Hash of ROM chips combined.
Hash() - constructor in class Nes::Api::Cartridge::Profile::Hash
Default constructor.
Hash(const char*,const char*) - constructor in class Nes::Api::Cartridge::Profile::Hash
Constructs new checksum from null-terminated strings.
Hash(const dword*,dword) - constructor in class Nes::Api::Cartridge::Profile::Hash
Constructs new checksum from input values.
Hash(const wchar_t*,const wchar_t*) - constructor in class Nes::Api::Cartridge::Profile::Hash
Constructs new checksum from null-terminated wide-strings.
HasHeader() - member function in class Nes::Api::Fds
Checks if the current loaded image comes with a file header.
HasMmcBattery() - member function in class Nes::Api::Cartridge::Profile::Board
Returns custom chip battery status.
HasWramBattery() - member function in class Nes::Api::Cartridge::Profile::Board
Returns W-RAM battery status.
height - member variable in struct Nes::Api::Video::RenderState
Screen height.
HORITRACK - field in enum Nes::Api::Input::Type
Horitrack.
horiTrack - member variable in class Nes::Core::Input::Controllers
HoriTrack() - constructor in struct Nes::Core::Input::Controllers::HoriTrack

I

id - member variable in struct Nes::Api::Cartridge::Profile::Board::Ram
RAM chip ID.
id - member variable in struct Nes::Api::Fds::DiskData::File
File ID.
id - member variable in struct Nes::Api::Cartridge::Profile::Board::Rom
ROM chip ID.
id - member variable in struct Nes::Api::Cartridge::Profile::Board::Sample
Sound sample id.
ImplicitBool - member variable in namespace Nes::Core
Import(const void*,ulong) - member function in struct Nes::Api::Cartridge::NesHeader
Imports settings from iNES file header in memory.
index - member variable in struct Nes::Api::Fds::DiskData::File
File index.
Input(T&) - constructor in class Nes::Api::Input
Interface constructor.
insertCoin - member variable in struct Nes::Core::Input::Controllers::VsSystem
InsertDisk(uint,uint) - member function in class Nes::Api::Fds
Inserts a disk.
Is(uint) - member function in class Nes::Api::Machine
Returns a machine state.
Is(uint,uint) - member function in class Nes::Api::Machine
Returns a machine state.
IsAnyDiskInserted() - member function in class Nes::Api::Fds
Checks if a disk is inserted.
IsAudible() - member function in class Nes::Api::Sound
Checks if sound is audible at all.
IsAutoTransposing() - member function in class Nes::Api::Sound
Checks if automatic transposing is enabled.
IsConnected() - member function in class Nes::Api::BarcodeReader
Checks if a reader is connected.
IsConnected() - member function in class Nes::Api::TapeRecorder
Checks if a tape recorder is connected.
IsControllerConnected(Type) - member function in class Nes::Api::Input
Checks if a specific controller is connected.
IsDigitsSupported(uint) - member function in class Nes::Api::BarcodeReader
Checks if the number of bar code digits is supported.
IsEnabled() - member function in class Nes::Api::Cartridge::Database
Checks if image corrections are enabled.
IsEnabled() - member function in class Nes::Api::Rewinder
Checks if rewinder is enabled.
IsFieldMergingEnabled() - member function in class Nes::Api::Video
Checks if NTSC filter field merging is enabled.
IsLoaded() - member function in class Nes::Api::Cartridge::Database
Checks if any database has been loaded into the system.
IsLocked() - member function in class Nes::Api::Machine
Tells if the machine is in a locked state.
IsMultiRegion() - member function in class Nes::Api::Cartridge::Database::Entry
Checks if the game targets multiple regions.
IsMuted() - member function in class Nes::Api::Sound
Checks if sound is muted.
IsPlayable() - member function in class Nes::Api::TapeRecorder
Checks if tape can be played
IsPlaying() - member function in class Nes::Api::Nsf
Checks if a song is currently being played.
IsPlaying() - member function in class Nes::Api::Movie
Checks if a movie is being played.
IsPlaying() - member function in class Nes::Api::TapeRecorder
Checks if tape is playing.
IsRecording() - member function in class Nes::Api::TapeRecorder
Checks if tape is recording.
IsRecording() - member function in class Nes::Api::Movie
Checks if a movie is being recorded.
IsSoundEnabled() - member function in class Nes::Api::Rewinder
Checks if backward sound is enabled.
IsStopped() - member function in class Nes::Api::Movie
Checks if a movie has stopped playing or recording.
IsStopped() - member function in class Nes::Api::TapeRecorder
Checks if tape has stopped playing or recording.

K

karaokeStudio - member variable in class Nes::Core::Input::Controllers
KaraokeStudio() - constructor in struct Nes::Core::Input::Controllers::KaraokeStudio
keys - member variable in struct Nes::Core::Input::Controllers::DoremikkoKeyboard
konamiHyperShot - member variable in class Nes::Core::Input::Controllers
KONAMIHYPERSHOT - field in enum Nes::Api::Input::Type
Konami hypershot.
KonamiHyperShot() - constructor in struct Nes::Core::Input::Controllers::KonamiHyperShot

L

left - member variable in struct Nes::Core::Input::Controllers::CrazyClimber
length - member variable in class Nes::Core::Sound::Output
Length in number of samples for one frame.
Load(std::istream&) - member function in class Nes::Api::Cartridge::Database
Resets and loads internal XML database.
Load(std::istream&,FavoredSystem,AskProfile) - member function in class Nes::Api::Machine
Loads any image.
Load(std::istream&,FavoredSystem,Patch&,AskProfile) - member function in class Nes::Api::Machine
Loads any image.
Load(std::istream&,std::istream&) - member function in class Nes::Api::Cartridge::Database
Resets and loads internal and external XML databases.
LOAD_BATTERY - field in enum Nes::Api::User::File::Action
For loading battery-backed RAM into a cartridge.
LOAD_EEPROM - field in enum Nes::Api::User::File::Action
For loading EEPROM into a cartridge.
LOAD_FDS - field in enum Nes::Api::User::File::Action
For patching a Famicom Disk System image.
LOAD_ROM - field in enum Nes::Api::User::File::Action
For loading ROM into a cartridge.
LOAD_SAMPLE - field in enum Nes::Api::User::File::Action
For loading raw PCM audio samples.
LOAD_SAMPLE_AEROBICS_STUDIO - field in enum Nes::Api::User::File::Action
For loading raw PCM audio samples used in Aerobics Studio.
LOAD_SAMPLE_MOERO_PRO_TENNIS - field in enum Nes::Api::User::File::Action
For loading raw PCM audio samples used in Moero Pro Tennis.
LOAD_SAMPLE_MOERO_PRO_YAKYUU - field in enum Nes::Api::User::File::Action
For loading raw PCM audio samples used in Moero Pro Yakyuu.
LOAD_SAMPLE_MOERO_PRO_YAKYUU_88 - field in enum Nes::Api::User::File::Action
For loading raw PCM audio samples used in Moero Pro Yakyuu 88.
LOAD_SAMPLE_TERAO_NO_DOSUKOI_OOZUMOU - field in enum Nes::Api::User::File::Action
For loading raw PCM audio samples used in Terao No Dosukoi Oozumou.
LOAD_TAPE - field in enum Nes::Api::User::File::Action
For loading cassette tape recording.
LOAD_TURBOFILE - field in enum Nes::Api::User::File::Action
For loading Turbo File device data.
LoadCartridge(std::istream&,FavoredSystem,AskProfile) - member function in class Nes::Api::Machine
Loads a cartridge image.
LoadCartridge(std::istream&,FavoredSystem,Patch&,AskProfile) - member function in class Nes::Api::Machine
Loads a cartridge image.
LoadDisk(std::istream&,FavoredSystem) - member function in class Nes::Api::Machine
Loads a Famicom Disk System image.
LoadSound(std::istream&,FavoredSystem) - member function in class Nes::Api::Machine
Loads a sound image.
LoadState(std::istream&) - member function in class Nes::Api::Machine
Loads a state.
lockCallback - static variable in class Nes::Core::Video::Output
Surface lock callback manager.
lockCallback - static variable in class Nes::Core::Sound::Output
Sound lock callback manager.
LockCallback - member variable in typedef Nes::Core::Sound::Output::LockCallback
LockCallback - member variable in typedef Nes::Core::Video::Output::LockCallback
logCallback - static variable in class Nes::Api::User
Logfile callback manager.
LogCallback - member variable in typedef Nes::Api::User::LogCallback

M

Machine&() - member function in Nes::Api::Emulator::Core
Machine(T&) - constructor in class Nes::Api::Machine
Interface constructor.
MAHJONG - field in enum Nes::Api::Input::Type
Mahjong.
mahjong - member variable in class Nes::Core::Input::Controllers
Mahjong() - constructor in struct Nes::Core::Input::Controllers::Mahjong
mapper - member variable in struct Nes::Api::Cartridge::NesHeader
Mapper ID.
mapper - member variable in class Nes::Api::Cartridge::Profile::Board
Mapper ID.
mask - member variable in struct Nes::Api::Video::RenderState::Bits
RGB bit mask.
mic - member variable in struct Nes::Core::Input::Controllers::Pad
mirroring - member variable in struct Nes::Api::Cartridge::NesHeader
Name-table mirroring.
MIRRORING_CONTROLLED - field in enum Nes::Api::Cartridge::NesHeader::Mirroring
Software-controlled mirroring.
MIRRORING_FOURSCREEN - field in enum Nes::Api::Cartridge::NesHeader::Mirroring
Four-screen mirroring.
MIRRORING_HORIZONTAL - field in enum Nes::Api::Cartridge::NesHeader::Mirroring
Horizontal mirroring.
MIRRORING_SINGLESCREEN - field in enum Nes::Api::Cartridge::NesHeader::Mirroring
Single-screen mirroring.
MIRRORING_VERTICAL - field in enum Nes::Api::Cartridge::NesHeader::Mirroring
Vertical mirroring.
mode - member variable in struct Nes::Core::Input::Controllers::HoriTrack
MODE_CUSTOM - field in enum Nes::Api::Video::Palette::Mode
Custom
MODE_RGB - field in enum Nes::Api::Video::Palette::Mode
RGB
MODE_YUV - field in enum Nes::Api::Video::Palette::Mode
YUV (default)
MOTOR_OFF - field in enum Nes::Api::Fds::Motor
Drive motor is OFF.
MOTOR_READ - field in enum Nes::Api::Fds::Motor
Drive motor is ON reading.
MOTOR_WRITE - field in enum Nes::Api::Fds::Motor
Drive motor is ON writing.
MOUSE - field in enum Nes::Api::Input::Type
Mouse.
mouse - member variable in class Nes::Core::Input::Controllers
Mouse() - constructor in struct Nes::Core::Input::Controllers::Mouse
move - member variable in struct Nes::Core::Input::Controllers::BandaiHyperShot
Movie(T&) - constructor in class Nes::Api::Movie
Interface constructor.
multiRegion - member variable in struct Nes::Api::Cartridge::Profile
Multi-region game.
Mute(bool) - member function in class Nes::Api::Sound
Mutes all sound.

N

name - member variable in struct Nes::Api::Cartridge::Profile::Property
Name.
name - member variable in struct Nes::Api::Cartridge::Profile::Board::Rom
ROM chip name.
name - member variable in struct Nes::Api::Fds::DiskData::File
File name.
Nes - namespace in api
Nes - namespace in core
Nes::Api - namespace in api
Nes::Api::BarcodeReader - class in api
Bar code reader interface.
Nes::Api::Cartridge - class in api
Cartridge interface.
Nes::Api::Cartridge::ChooseProfileCallback - typedef in api
Cartridge profile chooser callback prototype.
Nes::Api::Cartridge::ChooseProfileCaller - struct in api
Cartridge profile chooser callback invoker.
Nes::Api::Cartridge::Database - class in api
Database interface
Nes::Api::Cartridge::Database::Entry - class in api
Database entry.
Nes::Api::Cartridge::NesHeader - struct in api
iNES header format context.
Nes::Api::Cartridge::NesHeader::Mirroring - enum in api
Name-table mirroring type.
Nes::Api::Cartridge::NesHeader::Ppu - enum in api
PPU type.
Nes::Api::Cartridge::NesHeader::Region - enum in api
Region type.
Nes::Api::Cartridge::NesHeader::System - enum in api
System type.
Nes::Api::Cartridge::Profile - struct in api
Cartridge profile context.
Nes::Api::Cartridge::Profile::Board - class in api
Board context.
Nes::Api::Cartridge::Profile::Board::Chip - struct in api
Custom chip.
Nes::Api::Cartridge::Profile::Board::Chips - typedef in api
Custom chips.
Nes::Api::Cartridge::Profile::Board::Chr - typedef in api
CHR-ROM chips.
Nes::Api::Cartridge::Profile::Board::Pin - struct in api
Pin context.
Nes::Api::Cartridge::Profile::Board::Pins - typedef in api
Pins.
Nes::Api::Cartridge::Profile::Board::Prg - typedef in api
PRG-ROM chips.
Nes::Api::Cartridge::Profile::Board::Ram - struct in api
RAM chip.
Nes::Api::Cartridge::Profile::Board::Rams - typedef in api
RAM chips.
Nes::Api::Cartridge::Profile::Board::Rom - struct in api
ROM chip.
Nes::Api::Cartridge::Profile::Board::Roms - typedef in api
ROM chips.
Nes::Api::Cartridge::Profile::Board::Sample - struct in api
Analogue sound sample context.
Nes::Api::Cartridge::Profile::Board::Samples - typedef in api
Analogue sound samples.
Nes::Api::Cartridge::Profile::Board::Vram - typedef in api
V-RAM chips.
Nes::Api::Cartridge::Profile::Board::Wram - typedef in api
W-RAM chips.
Nes::Api::Cartridge::Profile::Dump - struct in api
Dump context.
Nes::Api::Cartridge::Profile::Dump::State - enum in api
Dump state type.
Nes::Api::Cartridge::Profile::Game - struct in api
Game context.
Nes::Api::Cartridge::Profile::Hash - class in api
Hash checksum.
Nes::Api::Cartridge::Profile::Properties - typedef in api
Cartridge properties.
Nes::Api::Cartridge::Profile::Property - struct in api
Cartridge property.
Nes::Api::Cartridge::Profile::System - struct in api
System context.
Nes::Api::Cartridge::Profile::System::Cpu - enum in api
CPU type.
Nes::Api::Cartridge::Profile::System::Ppu - enum in api
PPU type.
Nes::Api::Cartridge::Profile::System::Type - enum in api
System Type.
Nes::Api::Cheats - class in api
Cheats interface.
Nes::Api::Cheats::Code - struct in api
Cheat code.
Nes::Api::Cheats::RAM_SIZE - typedef in api
CPU RAM pointer reference.
Nes::Api::DipSwitches - class in api
DIP switches interface.
Nes::Api::Emulator - class in api
Emulator object instance.
Nes::Api::Emulator::Core - in api
Nes::Api::Fds - class in api
Famicom Disk System interface.
Nes::Api::Fds::DiskCallback - typedef in api
Disk event callback prototype.
Nes::Api::Fds::DiskCaller - struct in api
Disk event callback invoker.
Nes::Api::Fds::DiskData - struct in api
Disk data context.
Nes::Api::Fds::DiskData::Data - typedef in api
Data content.
Nes::Api::Fds::DiskData::File - struct in api
File on disk.
Nes::Api::Fds::DiskData::File::Type - enum in api
File type.
Nes::Api::Fds::DiskData::Files - typedef in api
Files.
Nes::Api::Fds::DriveCallback - typedef in api
Drive event callback prototype.
Nes::Api::Fds::DriveCaller - struct in api
Drive event callback invoker.
Nes::Api::Fds::Event - enum in api
Disk event.
Nes::Api::Fds::Motor - enum in api
Drive event.
Nes::Api::Input - class in api
Controller input interface.
Nes::Api::Input::Adapter - enum in api
Adapter type.
Nes::Api::Input::AdapterCallback - typedef in api
Adapter event callback prototype.
Nes::Api::Input::AdapterCaller - struct in api
Adapter event callback invoker.
Nes::Api::Input::ControllerCallback - typedef in api
Controller event callback prototype.
Nes::Api::Input::ControllerCaller - struct in api
Controller event callback invoker.
Nes::Api::Input::Controllers - typedef in api
Controllers context.
Nes::Api::Input::Type - enum in api
Controller type.
Nes::Api::Machine - class in api
Machine interface.
Nes::Api::Machine::AskProfile - enum in api
Image profile questioning state.
Nes::Api::Machine::Compression - enum in api
Internal compression on states.
Nes::Api::Machine::Event - enum in api
Machine events.
Nes::Api::Machine::EventCallback - typedef in api
Machine event callback prototype.
Nes::Api::Machine::EventCaller - struct in api
Machine event callback invoker.
Nes::Api::Machine::FavoredSystem - enum in api
Favored System.
Nes::Api::Machine::Mode - enum in api
NTSC/PAL mode.
Nes::Api::Machine::Patch - struct in api
Soft-patching context object.
Nes::Api::Movie - class in api
Movie playing/recording interface.
Nes::Api::Movie::Event - enum in api
Movie event.
Nes::Api::Movie::EventCallback - typedef in api
Movie event callback prototype.
Nes::Api::Movie::EventCaller - struct in api
Movie event callback invoker.
Nes::Api::Movie::How - enum in api
Recording procedure.
Nes::Api::Nsf - class in api
NES Sound Files interface.
Nes::Api::Nsf::Event - enum in api
Event.
Nes::Api::Nsf::EventCallback - typedef in api
Event callback prototype.
Nes::Api::Nsf::EventCaller - struct in api
Song event callback invoker.
Nes::Api::Nsf::TuneMode - enum in api
Tune mode.
Nes::Api::Rewinder - class in api
Game rewinder interface.
Nes::Api::Rewinder::Direction - enum in api
Direction.
Nes::Api::Rewinder::State - enum in api
Rewinder state.
Nes::Api::Rewinder::StateCallback - typedef in api
Rewinder state callback prototype.
Nes::Api::Rewinder::StateCaller - struct in api
Rewinder state callback invoker.
Nes::Api::Sound - class in api
Sound interface.
Nes::Api::Sound::Channel - enum in api
Sound channel types.
Nes::Api::Sound::Output - typedef in api
Sound output context.
Nes::Api::Sound::Speaker - enum in api
Speaker type.
Nes::Api::TapeRecorder - class in api
Tape interface.
Nes::Api::TapeRecorder::Event - enum in api
Tape events.
Nes::Api::TapeRecorder::EventCallback - typedef in api
Tape event callback prototype.
Nes::Api::TapeRecorder::EventCaller - struct in api
Tape event callback invoker.
Nes::Api::User - class in api
User IO interfaces.
Nes::Api::User::Answer - enum in api
User answer.
Nes::Api::User::Event - enum in api
User events.
Nes::Api::User::EventCallback - typedef in api
Logfile callback prototype.
Nes::Api::User::EventCaller - struct in api
User event callback invoker.
Nes::Api::User::File - struct in api
File IO interface.
Nes::Api::User::File::Action - enum in api
Action event.
Nes::Api::User::File::Patch - enum in api
Supported patch formats.
Nes::Api::User::FileIoCallback - typedef in api
File IO callback prototype.
Nes::Api::User::FileIoCaller - struct in api
File IO callback invoker.
Nes::Api::User::LogCallback - typedef in api
Logfile callback prototype.
Nes::Api::User::LogCaller - struct in api
Logfile callback invoker.
Nes::Api::User::Question - enum in api
User questions.
Nes::Api::User::QuestionCallback - typedef in api
User question callback prototype.
Nes::Api::User::QuestionCaller - struct in api
User question callback invoker.
Nes::Api::Video - class in api
Video interface.
Nes::Api::Video::Decoder - struct in api
YUV decoder context.
Nes::Api::Video::DecoderPreset - enum in api
YUV decoder presets.
Nes::Api::Video::Output - typedef in api
Video output context.
Nes::Api::Video::Palette - class in api
Palette interface.
Nes::Api::Video::Palette::Colors - typedef in api
RGB colors.
Nes::Api::Video::Palette::CustomType - enum in api
Custom palette types.
Nes::Api::Video::Palette::Mode - enum in api
Palette modes
Nes::Api::Video::RenderState - struct in api
Render state context.
Nes::Api::Video::RenderState::Bits - struct in api
Pixel context.
Nes::Api::Video::RenderState::Bits::Mask - struct in api
RGB bit mask.
Nes::Api::Video::RenderState::Filter - enum in api
Video Filter.
Nes::Api::Video::RenderState::Scale - enum in api
Scale factors.
Nes::byte - typedef in core
Nes::Core - namespace in core
Nes::Core - namespace in api
Nes::Core::CpuModel - enum in core
Nes::Core::FavoredSystem - enum in core
Nes::Core::ImplicitBool - class in core
Nes::Core::ImplicitBool::Type - typedef in core
Nes::Core::Input - namespace in api
Nes::Core::Input::Controllers - class in api
Nes::Core::Input::Controllers::BandaiHyperShot - struct in api
Bandai Hyper Shot
Nes::Core::Input::Controllers::BandaiHyperShot::PollCallback - typedef in api
Nes::Core::Input::Controllers::CrazyClimber - struct in api
Crazy Climber.
Nes::Core::Input::Controllers::CrazyClimber::PollCallback - typedef in api
Nes::Core::Input::Controllers::DoremikkoKeyboard - struct in api
Doremikko Keyboard.
Nes::Core::Input::Controllers::DoremikkoKeyboard::PollCallback - typedef in api
Nes::Core::Input::Controllers::ExcitingBoxing - struct in api
Konami Exciting Boxing.
Nes::Core::Input::Controllers::ExcitingBoxing::PollCallback - typedef in api
Nes::Core::Input::Controllers::FamilyKeyboard - struct in api
Family Keyboard.
Nes::Core::Input::Controllers::FamilyKeyboard::PollCallback - typedef in api
Nes::Core::Input::Controllers::FamilyTrainer - struct in api
Family Trainer.
Nes::Core::Input::Controllers::FamilyTrainer::PollCallback - typedef in api
Nes::Core::Input::Controllers::HoriTrack - struct in api
Hori Track.
Nes::Core::Input::Controllers::HoriTrack::PollCallback - typedef in api
Nes::Core::Input::Controllers::KaraokeStudio - struct in api
Bandai Karaoke Studio.
Nes::Core::Input::Controllers::KaraokeStudio::PollCallback - typedef in api
Nes::Core::Input::Controllers::KonamiHyperShot - struct in api
Konami Hyper Shot.
Nes::Core::Input::Controllers::KonamiHyperShot::PollCallback - typedef in api
Nes::Core::Input::Controllers::Mahjong - struct in api
Mahjong.
Nes::Core::Input::Controllers::Mahjong::PollCallback - typedef in api
Nes::Core::Input::Controllers::Mouse - struct in api
Mouse.
Nes::Core::Input::Controllers::Mouse::PollCallback - typedef in api
Nes::Core::Input::Controllers::OekaKidsTablet - struct in api
Oeka Kids Tablet.
Nes::Core::Input::Controllers::OekaKidsTablet::PollCallback - typedef in api
Nes::Core::Input::Controllers::Pachinko - struct in api
Pachinko.
Nes::Core::Input::Controllers::Pachinko::PollCallback - typedef in api
Nes::Core::Input::Controllers::Pad - struct in api
Standard NES pad.
Nes::Core::Input::Controllers::Pad::PollCallback - typedef in api
Nes::Core::Input::Controllers::Paddle - struct in api
Arkanoid controller.
Nes::Core::Input::Controllers::Paddle::PollCallback - typedef in api
Nes::Core::Input::Controllers::PartyTap - struct in api
Party Tap.
Nes::Core::Input::Controllers::PartyTap::PollCallback - typedef in api
Nes::Core::Input::Controllers::PokkunMoguraa - struct in api
Pokkun Moguraa.
Nes::Core::Input::Controllers::PokkunMoguraa::PollCallback - typedef in api
Nes::Core::Input::Controllers::PollCaller1 - struct in api
Nes::Core::Input::Controllers::PollCaller2 - struct in api
Nes::Core::Input::Controllers::PollCaller3 - struct in api
Nes::Core::Input::Controllers::PowerGlove - struct in api
Power Glove.
Nes::Core::Input::Controllers::PowerGlove::Gesture - enum in api
Nes::Core::Input::Controllers::PowerGlove::PollCallback - typedef in api
Nes::Core::Input::Controllers::PowerPad - struct in api
Power Pad / Family Fun Fittness.
Nes::Core::Input::Controllers::PowerPad::PollCallback - typedef in api
Nes::Core::Input::Controllers::SuborKeyboard - struct in api
Subor Keyboard.
Nes::Core::Input::Controllers::SuborKeyboard::PollCallback - typedef in api
Nes::Core::Input::Controllers::TopRider - struct in api
Top Rider bike.
Nes::Core::Input::Controllers::TopRider::PollCallback - typedef in api
Nes::Core::Input::Controllers::VsSystem - struct in api
VS System input.
Nes::Core::Input::Controllers::VsSystem::PollCallback - typedef in api
Nes::Core::Input::Controllers::Zapper - struct in api
Standard light gun.
Nes::Core::Input::Controllers::Zapper::PollCallback - typedef in api
Nes::Core::PpuModel - enum in core
Nes::Core::Region - enum in core
Nes::Core::Sound - namespace in api
Nes::Core::Sound::Output - class in api
Sound output context.
Nes::Core::Sound::Output::LockCallback - typedef in api
Sound lock callback prototype.
Nes::Core::Sound::Output::Locker - struct in api
Sound lock callback invoker.
Nes::Core::Sound::Output::UnlockCallback - typedef in api
Sound unlock callback prototype.
Nes::Core::Sound::Output::Unlocker - struct in api
Sound unlock callback invoker.
Nes::Core::System - enum in core
Nes::Core::Video - namespace in api
Nes::Core::Video::Output - class in api
Video output context.
Nes::Core::Video::Output::LockCallback - typedef in api
Surface lock callback prototype.
Nes::Core::Video::Output::Locker - struct in api
Surface lock callback invoker.
Nes::Core::Video::Output::UnlockCallback - typedef in api
Surface unlock callback prototype.
Nes::Core::Video::Output::Unlocker - struct in api
Surface unlock callback invoker.
Nes::dword - typedef in core
Nes::Result - enum in core
General result codes.
Nes::schar - typedef in core
Nes::uchar - typedef in core
Nes::uint - typedef in core
Nes::ulong - typedef in core
Nes::ushort - typedef in core
Nes::word - typedef in core
NES_NTSC - field in enum Nes::Api::Cartridge::Profile::System::Type
NES NTSC console.
NES_PAL - field in enum Nes::Api::Cartridge::Profile::System::Type
NES PAL console.
NES_PAL_A - field in enum Nes::Api::Cartridge::Profile::System::Type
NES PAL-A console.
NES_PAL_B - field in enum Nes::Api::Cartridge::Profile::System::Type
NES PAL-B console.
NesHeader() - constructor in struct Nes::Api::Cartridge::NesHeader
NO_COMPRESSION - field in enum Nes::Api::Machine::Compression
No compression.
Nsf(T&) - constructor in class Nes::Api::Nsf
Interface constructor.
NTSC - field in enum Nes::Api::Machine::Mode
NTSC.
number - member variable in struct Nes::Api::Cartridge::Profile::Board::Pin
Pin number.
NumCodes() - member function in class Nes::Api::Cheats
Returns current number of codes.
NumDips() - member function in class Nes::Api::DipSwitches
Returns the number of available DIP switches.
NumValues(uint) - member function in class Nes::Api::DipSwitches
Returns the number of values that can be chosen for a DIP switch.

O

oekaKidsTablet - member variable in class Nes::Core::Input::Controllers
OEKAKIDSTABLET - field in enum Nes::Api::Input::Type
Oeka Kids tablet.
OekaKidsTablet() - constructor in struct Nes::Core::Input::Controllers::OekaKidsTablet
OK - field in enum Nes::Api::Cartridge::Profile::Dump::State
Good dump.
operator!() - member function in class Nes::Api::Cartridge::Database::Entry
Checks if entry is invalid.
operator!() - member function in class Nes::Api::Cartridge::Profile::Hash
Checks if checksum is cleared.
operator!=(const Decoder&) - member function in struct Nes::Api::Video::Decoder
Tests for non-equality.
operator<(const Hash&) - member function in class Nes::Api::Cartridge::Profile::Hash
Tests for less-than.
operator()(Adapter) - member function in struct Nes::Api::Input::AdapterCaller
operator()(const char(&[ N]) - member function in struct Nes::Api::User::LogCaller
operator()(const char*,ulong) - member function in struct Nes::Api::User::LogCaller
operator()(const Profile*,const std::wstring*,uint) - member function in struct Nes::Api::Cartridge::ChooseProfileCaller
operator()(Event) - member function in struct Nes::Api::Nsf::EventCaller
operator()(Event) - member function in struct Nes::Api::TapeRecorder::EventCaller
operator()(Event,const void*) - member function in struct Nes::Api::User::EventCaller
operator()(Event,Result) - member function in struct Nes::Api::Movie::EventCaller
operator()(Event,Result) - member function in struct Nes::Api::Machine::EventCaller
operator()(Event,uint,uint) - member function in struct Nes::Api::Fds::DiskCaller
operator()(File&) - member function in struct Nes::Api::User::FileIoCaller
operator()(Motor) - member function in struct Nes::Api::Fds::DriveCaller
operator()(Output&) - member function in struct Nes::Core::Sound::Output::Locker
operator()(Output&) - member function in struct Nes::Core::Video::Output::Locker
operator()(Output&) - member function in struct Nes::Core::Sound::Output::Unlocker
operator()(Output&) - member function in struct Nes::Core::Video::Output::Unlocker
operator()(Question) - member function in struct Nes::Api::User::QuestionCaller
operator()(State) - member function in struct Nes::Api::Rewinder::StateCaller
operator()(T&) - member function in struct Nes::Core::Input::Controllers::PollCaller1
operator()(T&,uint) - member function in struct Nes::Core::Input::Controllers::PollCaller2
operator()(T&,uint,uint) - member function in struct Nes::Core::Input::Controllers::PollCaller3
operator()(uint,Type) - member function in struct Nes::Api::Input::ControllerCaller
operator==(const Decoder&) - member function in struct Nes::Api::Video::Decoder
Tests for equality.
operator==(const Hash&) - member function in class Nes::Api::Cartridge::Profile::Hash
Tests for equality.
Output - member variable in typedef Nes::Api::Video::Output
Output - member variable in typedef Nes::Api::Sound::Output
Output(void*,long) - constructor in class Nes::Core::Video::Output
Output(void*,uint,void*,uint) - constructor in class Nes::Core::Sound::Output

P

pachinko - member variable in class Nes::Core::Input::Controllers
PACHINKO - field in enum Nes::Api::Input::Type
Pachinko.
Pachinko() - constructor in struct Nes::Core::Input::Controllers::Pachinko
package - member variable in struct Nes::Api::Cartridge::Profile::Board::Ram
RAM chip package method.
package - member variable in struct Nes::Api::Cartridge::Profile::Board::Chip
Custom chip package type.
package - member variable in struct Nes::Api::Cartridge::Profile::Board::Rom
ROM chip package method.
pad - member variable in class Nes::Core::Input::Controllers
Pad() - constructor in struct Nes::Core::Input::Controllers::Pad
PAD1 - field in enum Nes::Api::Input::Type
Standard pad #1
PAD2 - field in enum Nes::Api::Input::Type
Standard pad #2
PAD3 - field in enum Nes::Api::Input::Type
Standard pad #3
PAD4 - field in enum Nes::Api::Input::Type
Standard pad #4
paddle - member variable in class Nes::Core::Input::Controllers
PADDLE - field in enum Nes::Api::Input::Type
Arkanoid paddle.
Paddle() - constructor in struct Nes::Core::Input::Controllers::Paddle
PAL - field in enum Nes::Api::Machine::Mode
PAL.
Palette(Core::Machine&) - constructor in class Nes::Api::Video::Palette
Interface constructor
parts - member variable in struct Nes::Core::Input::Controllers::SuborKeyboard
parts - member variable in struct Nes::Core::Input::Controllers::FamilyKeyboard
PARTYTAP - field in enum Nes::Api::Input::Type
Party Tap.
partyTap - member variable in class Nes::Core::Input::Controllers
PartyTap() - constructor in struct Nes::Core::Input::Controllers::PartyTap
Patch(std::istream&,bool) - constructor in struct Nes::Api::Machine::Patch
Constructor.
PATCH_IPS - field in enum Nes::Api::User::File::Patch
IPS.
PATCH_UPS - field in enum Nes::Api::User::File::Patch
UPS.
patched - member variable in struct Nes::Api::Cartridge::Profile
Soft-patching state.
pcb - member variable in class Nes::Api::Cartridge::Profile::Board
Board PCB name.
Pin() - constructor in struct Nes::Api::Cartridge::Profile::Board::Pin
pins - member variable in struct Nes::Api::Cartridge::Profile::Board::Rom
ROM chip pins.
pins - member variable in struct Nes::Api::Cartridge::Profile::Board::Chip
Custom chip pins.
pins - member variable in struct Nes::Api::Cartridge::Profile::Board::Ram
RAM chip pins.
Pins - member variable in typedef Nes::Api::Cartridge::Profile::Board::Pins
pitch - member variable in class Nes::Core::Video::Output
Distance in bytes for each line in the surface memory.
pixels - member variable in class Nes::Core::Video::Output
Pointer to surface memory to be written to.
Play() - member function in class Nes::Api::TapeRecorder
Plays tape.
Play(std::istream&) - member function in class Nes::Api::Movie
Plays movie.
PLAYCHOICE_10 - field in enum Nes::Api::Cartridge::Profile::System::Type
PlayChoice-10 arcade.
players - member variable in struct Nes::Api::Cartridge::Profile::Game
Number of players.
PlaySong() - member function in class Nes::Api::Nsf
Plays current selected song.
POKKUNMOGURAA - field in enum Nes::Api::Input::Type
Pokkun Moguraa.
pokkunMoguraa - member variable in class Nes::Core::Input::Controllers
PokkunMoguraa() - constructor in struct Nes::Core::Input::Controllers::PokkunMoguraa
PollCallback - member variable in typedef Nes::Core::Input::Controllers::ExcitingBoxing::PollCallback
PollCallback - member variable in typedef Nes::Core::Input::Controllers::HoriTrack::PollCallback
PollCallback - member variable in typedef Nes::Core::Input::Controllers::CrazyClimber::PollCallback
PollCallback - member variable in typedef Nes::Core::Input::Controllers::DoremikkoKeyboard::PollCallback
PollCallback - member variable in typedef Nes::Core::Input::Controllers::FamilyKeyboard::PollCallback
PollCallback - member variable in typedef Nes::Core::Input::Controllers::Zapper::PollCallback
PollCallback - member variable in typedef Nes::Core::Input::Controllers::VsSystem::PollCallback
PollCallback - member variable in typedef Nes::Core::Input::Controllers::TopRider::PollCallback
PollCallback - member variable in typedef Nes::Core::Input::Controllers::SuborKeyboard::PollCallback
PollCallback - member variable in typedef Nes::Core::Input::Controllers::PowerPad::PollCallback
PollCallback - member variable in typedef Nes::Core::Input::Controllers::FamilyTrainer::PollCallback
PollCallback - member variable in typedef Nes::Core::Input::Controllers::PowerGlove::PollCallback
PollCallback - member variable in typedef Nes::Core::Input::Controllers::KaraokeStudio::PollCallback
PollCallback - member variable in typedef Nes::Core::Input::Controllers::PokkunMoguraa::PollCallback
PollCallback - member variable in typedef Nes::Core::Input::Controllers::PartyTap::PollCallback
PollCallback - member variable in typedef Nes::Core::Input::Controllers::BandaiHyperShot::PollCallback
PollCallback - member variable in typedef Nes::Core::Input::Controllers::Paddle::PollCallback
PollCallback - member variable in typedef Nes::Core::Input::Controllers::Pad::PollCallback
PollCallback - member variable in typedef Nes::Core::Input::Controllers::Pachinko::PollCallback
PollCallback - member variable in typedef Nes::Core::Input::Controllers::OekaKidsTablet::PollCallback
PollCallback - member variable in typedef Nes::Core::Input::Controllers::Mouse::PollCallback
PollCallback - member variable in typedef Nes::Core::Input::Controllers::Mahjong::PollCallback
PollCallback - member variable in typedef Nes::Core::Input::Controllers::KonamiHyperShot::PollCallback
portDeveloper - member variable in struct Nes::Api::Cartridge::Profile::Game
Port Developer.
Power(bool) - member function in class Nes::Api::Machine
Powers ON or OFF the machine.
powerGlove - member variable in class Nes::Core::Input::Controllers
POWERGLOVE - field in enum Nes::Api::Input::Type
Powerglove.
PowerGlove() - constructor in struct Nes::Core::Input::Controllers::PowerGlove
powerPad - member variable in class Nes::Core::Input::Controllers
POWERPAD - field in enum Nes::Api::Input::Type
Powerpad.
PowerPad() - constructor in struct Nes::Core::Input::Controllers::PowerPad
ppu - member variable in struct Nes::Api::Cartridge::Profile::System
PPU type.
ppu - member variable in struct Nes::Api::Cartridge::NesHeader
PPU.
PPU_DENDY - field in enum Nes::Core::PpuModel
PPU_DENDY - field in enum Nes::Api::Cartridge::Profile::System::Ppu
Dendy PPU (clone).
PPU_RC2C03B - field in enum Nes::Api::Cartridge::NesHeader::Ppu
RC2C03B RGB PPU.
PPU_RC2C03B - field in enum Nes::Core::PpuModel
PPU_RC2C03B - field in enum Nes::Api::Cartridge::Profile::System::Ppu
RC2C03B RGB PPU.
PPU_RC2C03C - field in enum Nes::Core::PpuModel
PPU_RC2C03C - field in enum Nes::Api::Cartridge::Profile::System::Ppu
RC2C03C RGB PPU.
PPU_RC2C03C - field in enum Nes::Api::Cartridge::NesHeader::Ppu
RC2C03C RGB PPU.
PPU_RC2C05_01 - field in enum Nes::Core::PpuModel
PPU_RC2C05_01 - field in enum Nes::Api::Cartridge::NesHeader::Ppu
RC2C05-01 RGB PPU.
PPU_RC2C05_01 - field in enum Nes::Api::Cartridge::Profile::System::Ppu
RC2C05-01 RGB PPU.
PPU_RC2C05_02 - field in enum Nes::Api::Cartridge::Profile::System::Ppu
RC2C05-02 RGB PPU.
PPU_RC2C05_02 - field in enum Nes::Core::PpuModel
PPU_RC2C05_02 - field in enum Nes::Api::Cartridge::NesHeader::Ppu
RC2C05-02 RGB PPU.
PPU_RC2C05_03 - field in enum Nes::Core::PpuModel
PPU_RC2C05_03 - field in enum Nes::Api::Cartridge::Profile::System::Ppu
RC2C05-03 RGB PPU.
PPU_RC2C05_03 - field in enum Nes::Api::Cartridge::NesHeader::Ppu
RC2C05-03 RGB PPU.
PPU_RC2C05_04 - field in enum Nes::Api::Cartridge::NesHeader::Ppu
RC2C05-04 RGB PPU.
PPU_RC2C05_04 - field in enum Nes::Api::Cartridge::Profile::System::Ppu
RC2C05-04 RGB PPU.
PPU_RC2C05_04 - field in enum Nes::Core::PpuModel
PPU_RC2C05_05 - field in enum Nes::Api::Cartridge::Profile::System::Ppu
RC2C05-05 RGB PPU.
PPU_RC2C05_05 - field in enum Nes::Api::Cartridge::NesHeader::Ppu
RC2C05-05 RGB PPU.
PPU_RC2C05_05 - field in enum Nes::Core::PpuModel
PPU_RP2C02 - field in enum Nes::Api::Cartridge::NesHeader::Ppu
RP2C02 NTSC PPU.
PPU_RP2C02 - field in enum Nes::Core::PpuModel
PPU_RP2C02 - field in enum Nes::Api::Cartridge::Profile::System::Ppu
RP2C02 NTSC PPU.
PPU_RP2C03B - field in enum Nes::Api::Cartridge::NesHeader::Ppu
RP2C03B RGB PPU.
PPU_RP2C03B - field in enum Nes::Api::Cartridge::Profile::System::Ppu
RP2C03B RGB PPU.
PPU_RP2C03B - field in enum Nes::Core::PpuModel
PPU_RP2C03G - field in enum Nes::Api::Cartridge::Profile::System::Ppu
RP2C03G RGB PPU.
PPU_RP2C03G - field in enum Nes::Api::Cartridge::NesHeader::Ppu
RP2C03G RGB PPU.
PPU_RP2C03G - field in enum Nes::Core::PpuModel
PPU_RP2C04_0001 - field in enum Nes::Api::Cartridge::NesHeader::Ppu
RP2C04-0001 RGB PPU.
PPU_RP2C04_0001 - field in enum Nes::Api::Cartridge::Profile::System::Ppu
RP2C04-0001 RGB PPU.
PPU_RP2C04_0001 - field in enum Nes::Core::PpuModel
PPU_RP2C04_0002 - field in enum Nes::Api::Cartridge::Profile::System::Ppu
RP2C04-0002 RGB PPU.
PPU_RP2C04_0002 - field in enum Nes::Api::Cartridge::NesHeader::Ppu
RP2C04-0002 RGB PPU.
PPU_RP2C04_0002 - field in enum Nes::Core::PpuModel
PPU_RP2C04_0003 - field in enum Nes::Api::Cartridge::NesHeader::Ppu
RP2C04-0003 RGB PPU.
PPU_RP2C04_0003 - field in enum Nes::Api::Cartridge::Profile::System::Ppu
RP2C04-0003 RGB PPU.
PPU_RP2C04_0003 - field in enum Nes::Core::PpuModel
PPU_RP2C04_0004 - field in enum Nes::Api::Cartridge::Profile::System::Ppu
RP2C04-0004 RGB PPU.
PPU_RP2C04_0004 - field in enum Nes::Api::Cartridge::NesHeader::Ppu
RP2C04-0004 RGB PPU.
PPU_RP2C04_0004 - field in enum Nes::Core::PpuModel
PPU_RP2C07 - field in enum Nes::Api::Cartridge::Profile::System::Ppu
RP2C07 PAL PPU.
PPU_RP2C07 - field in enum Nes::Core::PpuModel
PPU_RP2C07 - field in enum Nes::Api::Cartridge::NesHeader::Ppu
RP2C07 PAL PPU.
PREPARING - field in enum Nes::Api::Rewinder::State
Rewinding will soon start.
Prg - member variable in typedef Nes::Api::Cartridge::Profile::Board::Prg
prg - member variable in class Nes::Api::Cartridge::Profile::Board
PRG-ROM.
prgNvRam - member variable in struct Nes::Api::Cartridge::NesHeader
Non-volatile PRG-RAM (aka W-RAM) size.
prgRam - member variable in struct Nes::Api::Cartridge::NesHeader
volatile PRG-RAM (aka W-RAM) size.
prgRom - member variable in struct Nes::Api::Cartridge::NesHeader
PRG-ROM size.
ProActionRockyDecode(const char*,Code&) - static function in class Nes::Api::Cheats
Decodes a Pro-Action Rocky code.
ProActionRockyEncode(const Code&,char(&[ 9]) - static function in class Nes::Api::Cheats
Encodes into a Pro-Action Rocky code.
Profile() - constructor in struct Nes::Api::Cartridge::Profile
~Profile() - constructor in struct Nes::Api::Cartridge::Profile
properties - member variable in struct Nes::Api::Cartridge::Profile
Properties.
Properties - member variable in typedef Nes::Api::Cartridge::Profile::Properties
publisher - member variable in struct Nes::Api::Cartridge::Profile::Game
Publisher.

Q

QUESTION_NST_PRG_CRC_FAIL_CONTINUE - field in enum Nes::Api::User::Question
Whether to proceed or abort if CRC validation fails when loading a save state.
QUESTION_NSV_PRG_CRC_FAIL_CONTINUE - field in enum Nes::Api::User::Question
Whether to proceed or abort if CRC validation fails when playing a move.
QuestionCallback - member variable in typedef Nes::Api::User::QuestionCallback
questionCallback - static variable in class Nes::Api::User
User question callback manager.

R

r - member variable in struct Nes::Api::Video::RenderState::Bits::Mask
Ram() - constructor in struct Nes::Api::Cartridge::Profile::Board::Ram
RAM_SIZE - member variable in typedef Nes::Api::Cheats::RAM_SIZE
Rams - member variable in typedef Nes::Api::Cartridge::Profile::Board::Rams
Randomize(char(&[ MAX_DIGITS+ 1]) - member function in class Nes::Api::BarcodeReader
Generates a randomized bar code.
raw - member variable in struct Nes::Api::Fds::DiskData
Raw binary content.
ReadInes(std::istream&,Machine::FavoredSystem,Profile&) - static function in class Nes::Api::Cartridge
Creates a profile of an iNES file.
ReadRomset(std::istream&,Machine::FavoredSystem,bool,Profile&) - static function in class Nes::Api::Cartridge
Creates a profile of an XML ROM set file.
ReadUnif(std::istream&,Machine::FavoredSystem,Profile&) - static function in class Nes::Api::Cartridge
Creates a profile of a UNIF file.
Record() - member function in class Nes::Api::TapeRecorder
Records tape.
Record(std::iostream&,How) - member function in class Nes::Api::Movie
Records movie.
region - member variable in struct Nes::Api::Cartridge::Profile::Game
Region.
region - member variable in struct Nes::Api::Cartridge::NesHeader
Region.
REGION_BOTH - field in enum Nes::Api::Cartridge::NesHeader::Region
Both PAL and NTSC.
REGION_NTSC - field in enum Nes::Api::Cartridge::NesHeader::Region
NTSC only.
REGION_NTSC - field in enum Nes::Core::Region
REGION_PAL - field in enum Nes::Api::Cartridge::NesHeader::Region
PAL only.
REGION_PAL - field in enum Nes::Core::Region
RenderState() - constructor in struct Nes::Api::Video::RenderState
Reset() - member function in class Nes::Api::Rewinder
Resets rewinder.
Reset(bool) - member function in class Nes::Api::Machine
Resets the machine.
ResetCustom() - member function in class Nes::Api::Video::Palette
Resets the custom palette.
result - member variable in struct Nes::Api::Machine::Patch
Will contain the result of the operation after the image has been loaded.
RESULT_ERR_CORRUPT_FILE - field in enum Nes::Result
Corrupt file.
RESULT_ERR_GENERIC - field in enum Nes::Result
Generic error.
RESULT_ERR_INVALID_CRC - field in enum Nes::Result
Invalid CRC checksum.
RESULT_ERR_INVALID_FILE - field in enum Nes::Result
Invalid file.
RESULT_ERR_INVALID_PARAM - field in enum Nes::Result
Invalid parameter(s).
RESULT_ERR_MISSING_BIOS - field in enum Nes::Result
Missing FDS BIOS.
RESULT_ERR_NOT_READY - field in enum Nes::Result
System not ready.
RESULT_ERR_OUT_OF_MEMORY - field in enum Nes::Result
Out of memory.
RESULT_ERR_UNSUPPORTED - field in enum Nes::Result
Unsupported operation.
RESULT_ERR_UNSUPPORTED_FILE_VERSION - field in enum Nes::Result
File format version is no longer supported.
RESULT_ERR_UNSUPPORTED_MAPPER - field in enum Nes::Result
Unsupported or malformed mapper.
RESULT_ERR_UNSUPPORTED_VSSYSTEM - field in enum Nes::Result
Vs DualSystem is unsupported.
RESULT_ERR_WRONG_MODE - field in enum Nes::Result
NTSC/PAL region mismatch.
RESULT_NOP - field in enum Nes::Result
Success but operation had no effect.
RESULT_OK - field in enum Nes::Result
Success.
RESULT_WARN_BAD_CROM - field in enum Nes::Result
Success but CHR-ROM may be bad.
RESULT_WARN_BAD_DUMP - field in enum Nes::Result
Success but image dump may be bad.
RESULT_WARN_BAD_FILE_HEADER - field in enum Nes::Result
Success but file header may have incorrect data.
RESULT_WARN_BAD_PROM - field in enum Nes::Result
Success but PRG-ROM may be bad.
RESULT_WARN_DATA_REPLACED - field in enum Nes::Result
Success but data may have been replaced.
RESULT_WARN_SAVEDATA_LOST - field in enum Nes::Result
Success but save data has been lost.
revision - member variable in struct Nes::Api::Cartridge::Profile::Game
Revision.
Rewinder(T&) - constructor in class Nes::Api::Rewinder
Interface constructor.
REWINDING - field in enum Nes::Api::Rewinder::State
Rewinding has begun.
right - member variable in struct Nes::Core::Input::Controllers::CrazyClimber
ROB - field in enum Nes::Api::Input::Type
R.
Rom() - constructor in struct Nes::Api::Cartridge::Profile::Board::Rom
Roms - member variable in typedef Nes::Api::Cartridge::Profile::Board::Roms

S

Sample() - constructor in struct Nes::Api::Cartridge::Profile::Board::Sample
samples - member variable in class Nes::Core::Sound::Output
Pointer to sound memory to be written to.
Samples - member variable in typedef Nes::Api::Cartridge::Profile::Board::Samples
samples - member variable in struct Nes::Api::Cartridge::Profile::Board::Chip
Analogue sound samples for custom chip.
SAVE_BATTERY - field in enum Nes::Api::User::File::Action
For saving the battery-backed RAM in a cartridge.
SAVE_EEPROM - field in enum Nes::Api::User::File::Action
For saving the EEPROM in a cartridge.
SAVE_FDS - field in enum Nes::Api::User::File::Action
For saving a modified Famicom Disk System image to patch or directly to image.
SAVE_TAPE - field in enum Nes::Api::User::File::Action
For saving the cassette tape recording.
SAVE_TURBOFILE - field in enum Nes::Api::User::File::Action
For saving Turbo File device data.
SaveState(std::ostream&,Compression) - member function in class Nes::Api::Machine
Saves a state.
SCALE_2XSAI - field in enum Nes::Api::Video::RenderState::Scale
SCALE_HQ2X - field in enum Nes::Api::Video::RenderState::Scale
SCALE_HQ3X - field in enum Nes::Api::Video::RenderState::Scale
SCALE_NONE - field in enum Nes::Api::Video::RenderState::Scale
SCALE_SCALE2X - field in enum Nes::Api::Video::RenderState::Scale
SCALE_SCALE3X - field in enum Nes::Api::Video::RenderState::Scale
schar - member variable in typedef Nes::schar
security - member variable in struct Nes::Api::Cartridge::NesHeader
Vs System security bits.
SelectNextSong() - member function in class Nes::Api::Nsf
Selects the next song.
SelectPrevSong() - member function in class Nes::Api::Nsf
Selects the previous song.
SelectSong(uint) - member function in class Nes::Api::Nsf
Selects a song.
SetAutoTranspose(bool) - member function in class Nes::Api::Sound
Enables automatic transposition.
SetBIOS(std::istream*) - member function in class Nes::Api::Fds
Sets BIOS.
SetBrightness(int) - member function in class Nes::Api::Video
Sets the brightness.
SetCode(const Code&) - member function in class Nes::Api::Cheats
Adds a new code.
SetColorArtifacts(int) - member function in class Nes::Api::Video
Sets the color artifacts for the NTSC filter.
SetColorBleed(int) - member function in class Nes::Api::Video
Sets the color bleed for the NTSC filter.
SetColorFringing(int) - member function in class Nes::Api::Video
Sets the color fringing for the NTSC filter.
SetColorResolution(int) - member function in class Nes::Api::Video
Sets the color resolution for the NTSC filter.
SetContent(const void*,ulong) - member function in struct Nes::Api::User::File
Loads content into the core.
SetContent(std::istream&) - member function in struct Nes::Api::User::File
Loads content into the core through stream.
SetContrast(int) - member function in class Nes::Api::Video
Sets the contrast.
SetCustom(Colors,CustomType) - member function in class Nes::Api::Video::Palette
Sets the custom palette.
SetDecoder(const Decoder&) - member function in class Nes::Api::Video
Sets the YUV decoder.
SetDirection(Direction) - member function in class Nes::Api::Rewinder
Sets direction.
SetHue(int) - member function in class Nes::Api::Video
Sets the hue.
SetMode(Mode) - member function in class Nes::Api::Video::Palette
Sets the palette mode.
SetMode(Mode) - member function in class Nes::Api::Machine
Sets the mode.
SetPatchContent(std::istream&) - member function in struct Nes::Api::User::File
Loads patch content into the core.
SetRenderState(const RenderState&) - member function in class Nes::Api::Video
Sets the render state.
SetSampleBits(uint) - member function in class Nes::Api::Sound
Sets the sample bits.
SetSampleContent(const void*,ulong,bool,uint,ulong) - member function in struct Nes::Api::User::File
Loads audio content into the core.
SetSampleRate(ulong) - member function in class Nes::Api::Sound
Sets the sample rate.
SetSaturation(int) - member function in class Nes::Api::Video
Sets the saturation.
SetSharpness(int) - member function in class Nes::Api::Video
Sets the sharpness for the NTSC filter.
SetSpeaker(Speaker) - member function in class Nes::Api::Sound
Sets the speaker type.
SetSpeed(uint) - member function in class Nes::Api::Sound
Sets the speed.
SetValue(uint,uint) - member function in class Nes::Api::DipSwitches
Sets a DIP switch value.
SetVolume(uint,uint) - member function in class Nes::Api::Sound
Sets one or more channel volumes.
sideA - member variable in struct Nes::Core::Input::Controllers::PowerPad
sideA - member variable in struct Nes::Core::Input::Controllers::FamilyTrainer
sideB - member variable in struct Nes::Core::Input::Controllers::FamilyTrainer
sideB - member variable in struct Nes::Core::Input::Controllers::PowerPad
size - member variable in struct Nes::Api::Cartridge::Profile::Board::Rom
ROM chip size.
size - member variable in struct Nes::Api::Cartridge::Profile::Board::Ram
RAM chip size.
solderPads - member variable in class Nes::Api::Cartridge::Profile::Board
Solder pads.
Sound(T&) - constructor in class Nes::Api::Sound
Interface constructor.
SPEAKER_MONO - field in enum Nes::Api::Sound::Speaker
Mono sound (default).
SPEAKER_STEREO - field in enum Nes::Api::Sound::Speaker
Pseudo stereo sound.
state - member variable in struct Nes::Api::Cartridge::Profile::Dump
Dump state.
stateCallback - static variable in class Nes::Api::Rewinder
Rewinder state callback manager.
StateCallback - member variable in typedef Nes::Api::Rewinder::StateCallback
STD_PALETTE - field in enum Nes::Api::Video::Palette::CustomType
Standard palette.
Stop() - member function in class Nes::Api::TapeRecorder
Stops tape.
Stop() - member function in class Nes::Api::Movie
Stops movie.
STOPPED - field in enum Nes::Api::Rewinder::State
Rewinding has stopped.
StopSong() - member function in class Nes::Api::Nsf
Stops current selected song.
stream - member variable in struct Nes::Api::Machine::Patch
Input stream containing the patch in UPS or IPS format.
subClss - member variable in struct Nes::Api::Cartridge::Profile::Game
Sub-class.
subMapper - member variable in struct Nes::Api::Cartridge::NesHeader
Sub-mapper ID.
suborKeyboard - member variable in class Nes::Core::Input::Controllers
SUBORKEYBOARD - field in enum Nes::Api::Input::Type
Subor keyboard.
SuborKeyboard() - constructor in struct Nes::Core::Input::Controllers::SuborKeyboard
system - member variable in struct Nes::Api::Cartridge::NesHeader
System.
system - member variable in struct Nes::Api::Cartridge::Profile
System context.
System() - constructor in struct Nes::Api::Cartridge::Profile::System
SYSTEM_CONSOLE - field in enum Nes::Api::Cartridge::NesHeader::System
Console.
SYSTEM_DENDY - field in enum Nes::Core::System
SYSTEM_FAMICOM - field in enum Nes::Core::System
SYSTEM_NES_NTSC - field in enum Nes::Core::System
SYSTEM_NES_PAL - field in enum Nes::Core::System
SYSTEM_NES_PAL_A - field in enum Nes::Core::System
SYSTEM_NES_PAL_B - field in enum Nes::Core::System
SYSTEM_PC10 - field in enum Nes::Api::Cartridge::NesHeader::System
PlayChoice-10
SYSTEM_PLAYCHOICE_10 - field in enum Nes::Core::System
SYSTEM_VS - field in enum Nes::Api::Cartridge::NesHeader::System
Vs System
SYSTEM_VS_DUALSYSTEM - field in enum Nes::Core::System
SYSTEM_VS_UNISYSTEM - field in enum Nes::Core::System

T

TapeRecorder(T&) - constructor in class Nes::Api::TapeRecorder
Interface constructor.
throttle - member variable in struct Nes::Core::Input::Controllers::Pachinko
title - member variable in struct Nes::Api::Cartridge::Profile::Game
Game title.
TOPRIDER - field in enum Nes::Api::Input::Type
Top Rider bike.
topRider - member variable in class Nes::Core::Input::Controllers
TopRider() - constructor in struct Nes::Core::Input::Controllers::TopRider
trainer - member variable in struct Nes::Api::Cartridge::NesHeader
Trainer.
Transfer(const char*,uint) - member function in class Nes::Api::BarcodeReader
Transfers a bar code to the reader.
TUNE_MODE_BOTH - field in enum Nes::Api::Nsf::TuneMode
Both NTSC and PAL.
TUNE_MODE_NTSC - field in enum Nes::Api::Nsf::TuneMode
NTSC only.
TUNE_MODE_PAL - field in enum Nes::Api::Nsf::TuneMode
PAL only.
TURBOFILE - field in enum Nes::Api::Input::Type
Turbo File.
type - member variable in class Nes::Core::ImplicitBool
type - member variable in struct Nes::Api::Fds::DiskData::File
File type.
Type - member variable in typedef Nes::Core::ImplicitBool::Type
type - member variable in struct Nes::Api::Cartridge::Profile::System
System type.
type - member variable in struct Nes::Api::Cartridge::Profile::Board::Chip
Custom chip type.
type - member variable in class Nes::Api::Cartridge::Profile::Board
Board type.
Type() - member function in class Nes::Core::ImplicitBool
TYPE_CHR - field in enum Nes::Api::Fds::DiskData::File::Type
CHR data file.
TYPE_NMT - field in enum Nes::Api::Fds::DiskData::File::Type
Name-table data file.
TYPE_PRG - field in enum Nes::Api::Fds::DiskData::File::Type
PRG data file.
TYPE_UNKNOWN - field in enum Nes::Api::Fds::DiskData::File::Type
Unknown file.

U

uchar - member variable in typedef Nes::uchar
uint - member variable in typedef Nes::uint
ulong - member variable in typedef Nes::ulong
UNCONNECTED - field in enum Nes::Api::Input::Type
Unconnected.
units - member variable in struct Nes::Core::Input::Controllers::PartyTap
UNKNOWN - field in enum Nes::Api::Cartridge::Profile::Dump::State
Unknown dump.
Unload() - member function in class Nes::Api::Machine
Unloads the current image.
Unload() - member function in class Nes::Api::Cartridge::Database
Removes all databases from the system.
unlockCallback - static variable in class Nes::Core::Sound::Output
Sound unlock callback manager.
UnlockCallback - member variable in typedef Nes::Core::Sound::Output::UnlockCallback
UnlockCallback - member variable in typedef Nes::Core::Video::Output::UnlockCallback
unlockCallback - static variable in class Nes::Core::Video::Output
Surface unlock callback manager.
USE_COMPRESSION - field in enum Nes::Api::Machine::Compression
Compression enabled (default).
useCompare - member variable in struct Nes::Api::Cheats::Code
Compare-value enable.
User(T&) - constructor in class Nes::Api::User
Interface constructor.
UsesBankSwitching() - member function in class Nes::Api::Nsf
Checks if the NSF uses bank-switching.
ushort - member variable in typedef Nes::ushort

V

value - member variable in struct Nes::Api::Cheats::Code
Value.
value - member variable in struct Nes::Api::Cartridge::Profile::Property
Value.
version - member variable in struct Nes::Api::Cartridge::NesHeader
iNES version number.
Video(T&) - constructor in class Nes::Api::Video
Interface constructor.
Vram - member variable in typedef Nes::Api::Cartridge::Profile::Board::Vram
vram - member variable in class Nes::Api::Cartridge::Profile::Board
V-RAM.
VS_DUALSYSTEM - field in enum Nes::Api::Cartridge::Profile::System::Type
Vs DualSystem arcade.
VS_UNISYSTEM - field in enum Nes::Api::Cartridge::Profile::System::Type
Vs UniSystem arcade.
vsSystem - member variable in class Nes::Core::Input::Controllers
VsSystem() - constructor in struct Nes::Core::Input::Controllers::VsSystem

W

width - member variable in struct Nes::Api::Video::RenderState
Screen width.
word - member variable in typedef Nes::word
wram - member variable in class Nes::Api::Cartridge::Profile::Board
W-RAM.
Wram - member variable in typedef Nes::Api::Cartridge::Profile::Board::Wram
wrist - member variable in struct Nes::Core::Input::Controllers::PowerGlove

X

x - member variable in struct Nes::Core::Input::Controllers::BandaiHyperShot
x - member variable in struct Nes::Core::Input::Controllers::Zapper
x - member variable in struct Nes::Core::Input::Controllers::HoriTrack
x - member variable in struct Nes::Core::Input::Controllers::Paddle
x - member variable in struct Nes::Core::Input::Controllers::PowerGlove
x - member variable in struct Nes::Core::Input::Controllers::Mouse
x - member variable in struct Nes::Core::Input::Controllers::OekaKidsTablet

Y

y - member variable in struct Nes::Core::Input::Controllers::Zapper
y - member variable in struct Nes::Core::Input::Controllers::OekaKidsTablet
y - member variable in struct Nes::Core::Input::Controllers::BandaiHyperShot
y - member variable in struct Nes::Core::Input::Controllers::Mouse
y - member variable in struct Nes::Core::Input::Controllers::PowerGlove
y - member variable in struct Nes::Core::Input::Controllers::HoriTrack

Z

zapper - member variable in class Nes::Core::Input::Controllers
ZAPPER - field in enum Nes::Api::Input::Type
Zapper.
Zapper() - constructor in struct Nes::Core::Input::Controllers::Zapper

 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
nestopia-1.51.1/doc/index-allclasses-frame.html000066400000000000000000000007131411157722000214000ustar00rootroot00000000000000 All Classes All Classes

Nes
Nes
nestopia-1.51.1/doc/index-deprecated-list.html000066400000000000000000000054401411157722000212350ustar00rootroot00000000000000 Nestopia Core API
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES


Deprecated API

Deprecated Methods
Eject()
          @deprecated  
 


 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
nestopia-1.51.1/doc/index-overview-frame.html000066400000000000000000000012041411157722000211140ustar00rootroot00000000000000 Nestopia Core API

Nestopia Core API

All Classes

Projects
api
core
nestopia-1.51.1/doc/index-overview-summary.html000066400000000000000000000055761411157722000215370ustar00rootroot00000000000000 Nestopia Core API
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES


Nestopia Core API

Projects
api  
core  
 


 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
nestopia-1.51.1/doc/index-overview-tree.html000066400000000000000000000210061411157722000207630ustar00rootroot00000000000000 Hierarchy For All Projects
 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES

Hierarchy For All Projects

Project Hierarchies:
api, core

Class Hierarchy



 Overview   Project   Class   Tree   Deprecated   Index 
Nestopia Core API
FRAMES    NO FRAMES
nestopia-1.51.1/doc/index.html000066400000000000000000000013201411157722000161570ustar00rootroot00000000000000 Nestopia Core API <H2>Frame Alert</H2> <P> This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. <BR> Link to <a href="index-overview-summary.html">Non-frame version</a>. nestopia-1.51.1/icons/000077500000000000000000000000001411157722000145345ustar00rootroot00000000000000nestopia-1.51.1/icons/128/000077500000000000000000000000001411157722000150465ustar00rootroot00000000000000nestopia-1.51.1/icons/128/nestopia.png000066400000000000000000000606741411157722000174130ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYsÅÅ.cltEXtSoftwarewww.inkscape.org›î< IDATxœä½ypÙ}çùÉÌÊʺï… Á›l²OI}ªÕVë´-ËcrE‡wÇÖìÚÞÙ°Æ;kï„ûÏh&¼3>Ö²li¼´HÝR»¥V«Õ÷Euó&A q£ªP÷}WeæþQ @ Ê«–cüý ÈzùÎï{ï÷~ÇKA×uþ1àø±}Àv Ì9z¸õ3®Ò? ~–…ÿÙŸÿÙsKKŸ¿vîúþ……¸T.1È&úûzôh.}¼×ãÿõ#G7~–uüoÂÏb8~ì„øîù³çßxùüÞ……Iêõ’dÄåè!›ŸÀïàcŸ|2ý§ÿåOïyÿ AüYzúÊ¥Sß8ñìÞÉÉwFÙ‚ÓÆfõ­¤I§çùûï¾äÿWŸûÝþ³¨ã?¼ç[ÀçÿüÏçùo¿t°Xˆàvõb”-´;M«ƒ ŒTæ:º®QÈÇX¼ýSàoþ!eþÇ?ùOO'R™?TUÕ³odôWþûñÙÓÿ´å¿¼§8~ì„üʳ/>½¾ò¬ZËcxêña·Œrù*4› ¥ªÚ&.™þå9¿ûìÒ'ß>%—‹i$ƒ‘=»î9Uï4?ærø^ŒfâÿöÂåÉÿµYªŠO?õÄo™Ë—=üC*~ðž`rnúKçÎ_4­CÛØ56†a LÃÜÂPiãv¨•üJ12…¼püØ ùÈÑÃí»)ëø±ž¿ýÚ7Òï¾ñ–hŒx\ýJqÎ_8I³¥}O4æg)•Ҁ΅3óÔGý?Þ#GkwY– ¸=œºéÙÈé ç¾>q~êžï=þ'ð‡Ÿ¹›<ß+¼g8~ì„ûÕçßþL¹”BÚÿf¥‡´’"ë—(9«„+NRÉâÊ{•r`/pö.Ê’¿÷‹©So¾-Ú­~¶oÛ‰AIfÌNŸfâÊ;tI‚  ë:KKÓ<ûNØas¼<¹ÅrÄóW.¿úÒ÷_{¸Z«ó×_ü;}ß¡3jÓ÷ö[g±Ø ­vÉ©éÿ®Ï>õÁ¼àÈÑÃõ»è¶Ÿ:Þ3œ¿2þ•k„üc„#½˜ä m£JÁ¥m£@|‡ó´ F½ÄÕ‰+ÿð[-kznú«o½vZjµj˜=N};1ª<þ ª¦27s—+Bÿ™Lštê:¹ì<Ï~÷Åîݹ³ÿÈÑà ›•séÊø}ék—K݉]._A¨× 8zz·]¸Â³ßzÖ/ 'ß?&Ç{r 8~ìDø…g_½·VÍá°Ù¾sƒƒ)zkÌçi+ö|ûÉ8º†Ó Ñ,3=½øËwSÞ»ï\üùB>ŠÏ3Œl1Ó6©d½QfwT ?6Bÿð=ˆ‚Doï0={"ì~ôìÎ Ù\à±-´ÉöÒóo=Y)g õìa×®÷ÑÓ»‹F³L½^À(›¹gï^<Ÿ<ľ=ÒnÕyöÛÏÚgg¯¿}w½÷ÓÅ{²œ¾pî‡ ‹ÓØ!Øî!G‚lÀ€vK5Þ9£ÁŒß;B©¼„¦©Dc)ûÝ”—ˆ%DƒAÁãêÇî”i˜š”œª ù™ÞÇǰ[MøÜ.*v#š¤b2Ùh·›¤KùÑÍÊ(f—>˜Éeðú‡8xè>J v‰ê7 ‹q,b¿›ºUÇú~|©4KñË<óÝ— ms9z¸t7múiá=Y¦®ÎïjµjRq”dLpíàäû-vJå¢ !Š]~¦³Yáø±[V™­f½Õª¢ªmMlÐ4u ³•òñÃÛèl÷a®µ±T ÈÆîaCWUâ…ì¡ÍÊÈ•Ë?ßh6Ú>LzX çk ¡ƒ `”-ø{ƨz:f#N{—ÃÑxœd>õÛ[mËpüØ ãñc'ÜÇP~Ò<~ê+Àñc'„x,!Ýø¿ZNs}bï6uËZÔl"¡2‰ë”«i4­+Œ§RQÎ\>ÿÂØJ™;íZ:þTO¥šÆj¥0ž Çg&zÀKÕÖB - äüá¨WÞ¦©èš¶éÑ3×jïmÔ+´ªM4 :ÔÏG)—ÐuŠVƲÜ>MÔh¶ºíJ9Ù3ã¿üÑVÚ²Ž;!]¼:þì[/Ÿ~ºPª`V^|íõâ“>ò¾#GOÜM^ïÅ °+—Ïu %"ûÙ¶·Ýà߀×kE1ZXJ^F×»ƒÒh”øñ+g÷o•é{¶ ýV››R%E¹–%™¯qízS]EVùÝ?Û´Œ-´å²$ƒˆÛ{y³2Ò ©ívT:R×qäšÌÎ/"NW„ía/mYÀ\î`|q\¶+(jºÊÔå)ËVÚ±þú¯þúÃÇ¿ò­ö±/}óé‹ã§A4‘ÎùÞw¾ïü¿ÿä‹—?÷¿ÿþÅãÇNx·šßO}˜ŠÏýN¹RÄ Ý~û‡¶sȦU†`“ÙE³U]óÛÌÜ,Ó‹3Ÿþ—ÍÊô9ýßvÚ_ŠÆfÈKtÔ&K  _ð’x0´’ΑkR¹’BÕÑÅ.1Œ²‚ÏéÞ¬ŒD4eÑuZ¹ˆ¥¬RðË meDFÙá%Ýgí–q-Ë/Ÿ¢ÞX=ÚVk5Ž;¡9z¸¹Y97pü؉Ñ>ÿâé·~|Þ™J΢i,f=/M—‹+W²L\=ÍblqïÙç3Ñ¥ùÿñw÷ß|a³|÷¹ýŸ •Æ/Ê>{Ñm³½¶=2ô_+GŽ®Üî«S¿ÒnÕÙ¹ë~„n§j6Lç]ª=•Äíu`s¸(ck~¯TÒ¼ñ£S¿ÍïmN€#Gÿò _Ò£±i!±ÅbwÒjW‰;X^æÊ»‹,NOóÇŒI1 ØDçpüØ !›Í íV c²J'ì¢óÁ^Ê7¥Õê*ÍVQ4 iA`lïXënÿþàßýíw¿÷Ö¯NM_¤µ21@`1–ÁîpÑÓ·›Bf‰R%É»§Þ ‘Hÿ¥¢˜lÿò_þ«ÿt§¼ïŠ..üÏåZGPd¡WDØ}J:ÿ›¢,òo?§›CΦÍcKx­¶·Çƒ_7¤) qí´Ùbv ½ÍàºHvæ b}ŸÛMlqíﺮsåúuáÿúŸÿÝßÿÜ¿þ›ÕÕávi€¤i*j£ƒ®ë4òeúRrŽBƒ«s3 ´}œKÝÝÅétüx“ìGŠåî0·ÛuÚ¥àÚ0a³ÖFÓTüžJ•$F“…ûØ¿iýoàø±ÞßüѯÎͯl‰CÃPÞéE5€?¯a=«à,„Yˆaaq’oý‡Ÿ÷{‚_¸ÓÝ2Ž;a4ÚŒÂÇž`ÿjÚZ­Æl&ÎTµ¢Ø(£\}åÍF…z£ÀýÂà&8³ ¬9BÁ0W&OQ,v•@²lFU[«º®sqü’p~òÀ3GàçnW×ãÇNH…bQ0›]ÜV’ñFÙBÈã¤bìHS%4]¥XZb)y…ƒÍißÔæpùÔÄ'u]ÃjñP­åh´×sQRu¤“ D£W–Ÿèˆ¢ýìNÝiFÞŠr1÷>M]O°ŽªbhCû&±X38±î¶à,äIeAí¾wÇ1Þò)`2ý-ÁfA2l,ÀÝ ‹ÅÂîþQ>þÔc †Ñudò*…bw–ükOY–™“S œN+“‹ù…w0+Ž•Á¿j%ËóϼúÔñc'†ïP…±R¹ŒQ6Sk4)UR8Ü=ØGº¤3´5ê¥îÔêyV¥ˆÏÆ7=ixûü9Ù`Âbõ`2×¥ñO™¸v•v{Uõ/Š÷¥Íò¿éJùá°˜N!ê‚ÖŠFx±­dDª–È/ŸºÜ./ÀÌòß2ªµêÃ^ûÝ^DQâã¿ð8áðê’. ûZRj"‹qš- o`pù©@«]Ç([„µ²Ctá_ù»ïLýíß|y`£r¯^Ÿø‹r),[H¥K¨j›þ>Rƒ]eŒÜì w:ȲyÝ»‰TZ8~ìÄwj×Îmƒ­ :ùü"¢(a6¯%€¨Á⥊Å8Ã*ÙEQB‘ É;å}+JÅÊ®['@>µ@æ›gi~ûùïÍ@4O&%3#—›C–ÍìÚ¹­}äèáÂòßòÐnwü£nçæ o×åãѽï~=E½^@%q-ïÔ°Ñh$‘Í3Ö •ð"M<þáG%‘b²D!›'_ªP­U©×*ÌÍe„¯}íù¹^z³ ½66²í/̲’ ?|îõGÍ2Ɉ„¡‘Cïï£.u‰Ô4ËØ½>dÁHliíöX,˜ŠÎþ{î`ˆø#_¶Û\¿W­dQŒVDKwUt0tt -•x6ÍêC1ÚVÜÜ@G¿KÁ»\¬øt½«“$#&ÅNµ–¥Õª±8w¡[ŸÐ^Jc8R&f§Ð4•pÏOFaL&ëš—AàÔl®Ltñ:ÆêÚ~ÕÁAíB‹…dP€è‚Àøø$Oäqyu[VŒ&¶E†ØZ“G¶œçÌù ^~îu:j×ÚZ«ç™¦!îfxÄInYöè¹’áÊTŒDz€|1Æ 9@×U.^š>þÑ'~ øêFqäèaýo¾x\“$£è°ѧ‹„*pû©Útt“BoÿNšÕ6æªV@U;Ô+õÈû€èBBQµµr©ÅìážC{Ÿ0‘Œ^ÁhV›s‹‹èºŠ/0ÊÝt+ùo•{¢@±Zâ_ ™ì*ÊVÜ_0Ê&Œ&V«‡ÝÏãÆßï'2ÔÃH H$ÐÃÈØÉ¥E(¯´K£^„‰4¥l†vÍ…Õâ%•ŠòêÉwù¹GÞ´‚^»›bº@©G 8ìaLf²Ù„ÓjÁTꀿ›6“lRHGWœBn2é(Ï|˜­ŽoÝîH yKšÖqMÏ¿MtÉ‚ÑhÅd±3éÁ´w±pòígnyK§˜Ê;6mÌ2Ž;ˆ'’ë–Ìpß6Òý¸E’Ñ+Xìf\É õbI”9°k»úÙßú­ É{+¶D€z¥ð˜Õ&ñú[§Éf¢¤Ðiµë´Úu*å4É\¤Ó2ŠbÃjsÑ Ü>H[mÎá/µFdú»ýa›+p9qÞÁ]Dv©¾“£RJ3y~†½ÿ!DéÎU¦b\¼0Ñhe÷Î{°mÝÚ&‰†E ®®êõ÷…¸¿ç1®Ÿžfqæ&“ƒþQ4 ÊÕ Z•«“‹âß~ùÛÍ—Þx³°clèK‘@äkÀå#G׌^‹&š¦aµ{éí “Í—YJð¤[è¦:õjq]=+¹’´îámpeæê_¥ÓKkžY­>Ç‚,,&#‚ â´›Ñs šÍ no„~ì±_ßj["@®PxÈé²’};{“*rs¨j›Z-O­–'“žcnD×T®^{›ró;‚«K{#YEE"ýn’»lŒf{™œh‘H$xûâ>pÏ-´/\#Ÿ[âÀþ©>5H]ÓéŸi‘u‹4Ì"–Êê,o%’Ûœ8'—;ÄÑ£Çãñ“Égˆæó¤biÊé²°p=éž½’ø ~G6|ã›ß×%Å /L/Šš¦ÒÛ¿—ÈÓû)ûöMyÐ$†¹C§°D§³^Û›IeÅãÇNxŽ=œ»S{Ž;Ñ÷Âß¿þÉz}­ØFb_w)3YdöŠßDi6ª¶Øµ}TW̶ÿwÓÁYÆ–Ь´C¡ ©Ì:wݵS.4Ðt —»—{z‰ïò¯VÄ(Ðî4КÝe¹t_p±ÍüÜ$Óççq¸„\.üN߆‚d*–Á )÷© wºYÃ,b©j´a¹Þ]( T±« pجøýaA äò‡»AjËètÚijI¦§ÉD3B2Væçgp¹z||/9—ȆŽHÁ–¢à•P,&¼áAšóTuuIe²ƒÀm püØ ñ¥·Þš˜š™\óÜlr18à%±Ü ‹Ydh÷R£ªçæ0öÞ»ãòÝ8µnJ€ãÇN v:š!VÈP(vÙ89ÄRj‚V»¶Õr€®"D ŒmßNüžµþƈ »ÕO½Òí¬¦I$¼ÃK2åd1–!zâ%j• V‹—ÛE¨'ÄèÎ~öí@6ˆ´;uL±2ŠÏJ˨±Ôg$ôÎå’J`l€¼¯½b†6½%¹4…(èêÙT+déöÒì{^}÷&¯žbtx”|ïª.Á Š$߸ŽÃj¢óÄ0îBxY`a~Õ¶T.¹0uõ8vâéÛ¹ ŸŸÿѾû¼­Ù\«0tøÂ¤÷­ö[òžºÐU9/‹ÈF3a§õï6‰›Ú¶…4¢:ÄÊÔ«AdpÀ‹Ùq©kï®HÜ›A$ÙˆQ6cò¯XÌD | %:KuÜþ!¬n…Í.íø|^R‰$­V\a‘4ÀHã2µò+ˆŒõ!½+söÌ%v–[¸ÃJÙ‹ñ&:^U™kÓ0CøRšSW&hwôöíæÃzänúŒH$ˆA6!štáF;DU Ñj‹^ç>›‰ÆÞNw’(Š E¶"Ëf^{þÒÏM¦µß}· 8ßÙÞ7ò’d˜OO^úú·ÿý¥Rj]¹½á0uy•¨7<ªlÙJ“bÁéññnÚ²)ª¥ìÓýf+ç/_£Ñ(#"f·•¡±0‚ÞaòÚ©uêÚ ̸\FâK*JVÀã¶`LʼnM•X¬41:L YX:\y§¡€Ëf%©kÈòZõ±¦u°:V5“û¶ ñ‚ÝC&3Çøx“`r Ñ,á÷Ê**šš¤àOT¹~5I±Çjóñð“÷árllÉ»B6&³…ù…¡F]’ Åè‚ÆPÄO2~3çβ_Ui4ªˆ‚Ä>ð‘Ý”k ÉõR…K‹öYuáÉ7õKOj€AXˆÎ‘Ioì,6VÜêé2º®¡( ŠÙ~WËò¦(Ê›m éDUkct³‘_º×Ë3†XŒ"'ÎÒîÜ9ˆ·ÝiPo¶hwêŒ_g ÆîßNODK“ ƒ¸im;F ³Ó(0Hkmƒ “m•—§ÃI.+á Ð7l£5èEÀ”Œ*ªÔÆüNŠÔÂUDQâž{î!èõˆ.`µY0Ûœ¶`ëÐÕ’(’ZšÂü-;½arhˆŒ¿Dy[˜{:0ƒ¦Ñ¬W±Ú¼<ôØ=ôz׿£ë4kerå"±\‘T4Õ*ôÉ K9êÕüÊV[®7Ùh£ê´u$QFïºÐùè†Øo › Viö">2¹<’AF³*ZŠÇÆ<ü¨2ÂûìVÎ^¼H¹|{5·®kLOgçö{¸2yŽtê:=‘ƒï$Ý»^'ªß‹Åì‚[¢˜£ ‹s­ÂÉïó‹Yö°tµPqæ5®ÍG©7ЏÜ>ðÁû :]”sâ¦*³´« Zñ¢$bóÛðö¸g`pr«ÒlR«×PÕós§hÕv²Û.“ÝáGEšìÇßîC¾˜¢ÕªÑß¿}ÝàCw[4YôXô„ú`×Íý¥“HŸ<åGÏ|Ÿ|!E©XÅÛÖèÈ«ÅRÑ‘BV$I¦R­pîÒÅïsŒ{·IuG?vÂ]©iJ»T¤Tî €ƒ‚( èb»}ÅñÑBûbüú4ÉÄämó«7Š\›¾L8¼‡hì&“DųvÖËmS]TI f«#*2‚*¬xÕȻöæ]oÈóƾKg§[ϽòZÛÛç›9]ßðG¾\ÛHµ½Ù p ŽFrq‰F­«Ô0È Š¤£Iý «ìïm0© ,.Õ¤Ù¨P(¬ºsùÃȲBµR¤Ù(Óh”H¥®òïd)>á+~ꇺÇA×Rè‹—)æRhZQ2`w„I‘ &š­nÇKK|ïë/r12NÏÎ^"/­†Š®kp“H"è¬j­Bƒîén—AX¯“E‰}Ãì軽µya|fŠ×étSq®Ï«ØjcµyØhç&Ý|g4›-ŒF+6ZzU·  ÷‰Z× Èö€B¼ /MgöŸWõýª¦ÿ;YøÆw¾¯x`Ïþàû7¿y#; ZÌ>­4²×Ó+Nš²¬`Q$@@j½FÈRÀm3“)uXXÌŽŒÑjÖ¨Õóe #ý#äŠ9Å‚¦F0Šf:j A@ös}|¡€©¡1ñê9RÉkÂÁ~Œ²D<9º€Ëу,¯@ÓU¢‹ãD/c:oÇf÷ãóõÓnש'êøó1ªµ:µZ¯×Ms_E1H2µ…lܲBn´›NÙƒB8ä%+­ßªŠb²ñÎ+ç˜îY`p´—>hÅÿp+ÐuJ­Š+8ˆ÷;ÈÜ"') ÀDž·1¬V/÷=q'î»å÷v§ÍÄÂ,s׈N§ÅñwÇ? l‰Bþ£‹T¢A ]¯Y·¹‰¡ù#Ðk˜¤îù¾¶!´Ì¨‰*=ÁÝ,ÆÏcRì$’EæϬä)"&ÅŽÅìáÐ=»¹2µ@þlŠr¹D!exh/Ÿú¥!vFº„ûÏ_²sáâ»rÀMpº"¸]~ÚíÍV³ëóW©Òj×8{þmZíúŠ•(JØ/èïÆh´Ñ©çÐ5MSÅ»'‚ÃçÄh´éÝG½Z µË½a:½Õ"“žå•׿PŒL&›—ÉÏãÆæ6ãëÐòÑë o(€¶šuêõ*=¡MóúS€µ¬q}r‘j-ǃ÷>²fðdƒÌþáíìÞÎß~ùÛøƒž5ªÅ;`¡XóyÈWuÚŠb$h­‚¾zÚЖ´V¯±¥ÒŠ- ïCÓ:”Ê Ì&'ƒƒ;ð{Ý\ºr™|n‘z£Hµ:ÌPoKK5Ìf~ðI>òX§iUÝ<¶?ÌÄsw¯]v½’e3þÜ#<õþZ£Æd*Å«ßy]×VV‰•úi*Åâ—Š«zõsÞeþ£xÝ^<^.ŸƒÀ@P€ ;pGÅPd ˆ(H ö8]~–;Êh­6²l¦Ý®ÓlUi¶ª]´xw"(F&“£É‚ÅlÆa³âö:pöxñ÷øèu»Iåòt:m‚N[WBWwrCÞPò$—f†FxßG¼Óp¢ª:}}¡“7?»-Ž;¡Ô[ªœnÔ©VV `2šèq¬í`UÓ±´Ûæ€)“£RI36:ÄÉSp:Ã|ìS±­˜o~ÇÄ+/¦é¨m$Ñ@4Y  ¸Œ<$¯|€v7ø‘Õ‡Õâ]6Û‚ÃàÁƒ{0./¥N£‰û~Ô~iÍ»ý;ݤR%b±©5ºyMSI§çI$¦èZ3Í(ŠÅlÇf³ãv8ðxœØvü?½.~w×Q% ‚•†JgÌKÏÙ¹¥<í¶Žw,Hv› Õ  «¬ÅRœ[ïbÒuF³D£Y‚[lF¢h@–Mf ² I”±*Ú1dAÀâ¶‘îµR·ŠÄgSt:MöÝ·—íá ¤¨uZe¿ËµÆDy§`·¦!Äc)UÇdR0ˆkS©Õ° Ôv‡Šl@ßÙKãÍÎ_:GGm‚(àqtݱòéíN£ÑJ"Ýbaþ }áT|†ÕÍ5[S(ÔdF|‚=Ãh Vtꯟ˷¦ªÚ¦Õnvýî~J¥|`Œß_AÕ-üÛÿÐ"±´z3ÉÞÝ÷c·Û(+äK%ª•Íz™B>F&Ýdny £E±a±:p8ìxÝN,Îî±+“¯ ~ããñ‰e=ˆ€mÖGïø0C”uƒ¤ (v­Ç‚jZ‡f³Â Up0¼‹XªFµÞÆj6gÑ'¢ …ݼŸ#ÙŽÉae6>O°IZ¿•D3)d“ŒÅæ^3KnK€f½òˆ(Bf.µÆ±Ñj5³FÌ–‹ ö©7˜”m¨v#Îí»ˆž}µÛ U¥ÑQIçSÌ-v´öŠˆ IDATþeƒ‰N»A§Ó¤XN ›­Le-xÝet©Ióö:#¿ŠØ¢¬ÂŠç¢h Ói‰l£·'Âø„ÆèHw”ðºœ$–wÅhcÇýc<~ï}ݶ6jiji—RdbYŠÙÙ\R¹DµV¢VËS(ƉǻåÛmDA"› Ñ,ãñöâu»©Öjär)®N¾C,6ƒQ±"‰2Fƒ™?Y0°ÓÑCÐßCd,ˆ+K›ë—Û\8›àÕÙ‹Ýí¥Y%÷8'­6\v¿—ÞÝCÜ»c ½ëÆ—,08€¹›ó¿-¦“ñ£N“ÌÕTf5±dÄâ¶psìËÙ Õršz=D«ÊuØk¾Ÿ|fŽf£ÄËϤÝi‘Ïu/‡2T¡{,­Ö³ø:CL].ðÀ¨Ž ÆqY;T«ÝðÚ9“M¬ä-IÒ:Nl67=A?f³·'Ä û&oœåÅE$F†wòØ¡{W~SL†" E`õ1õF•¹t’X*Kn!M!•¥Xª l$bS4šî=ø0¿ü)+^Kw{™XØÉ÷¿ejf‚r%MÈ¿i‹®s·Âh´ðŽÒhjt*Už|_·=ÃàïÝÇÉ—ìÌÏž_ÙJJ•$©$0ÆÓNxìé‡xô¾(Õ˜ýÎö­¨Û ]©E,6ò7 €&“sÈFG/s#ÈçÕwŠ´ÚuÔN›Ží¦ã `Ù¿—Ò«1jõo¾ý]ŠîêÑn×ñ»ÔÊ£J1ttfóhšQìCÓ!WS©¼yaµç/žåÏþ´‚/äÇpá‹øñšÍ„|>ì#¢,â÷ú×lUÙeWéá‘|æ×>qG!ïÌ&+;û†ÙÙ7 Ëóƒ7ß&›Æá rÏca¼–ôÊ;»ú«ìúM7_ø¯1‹#) ?Ù… v«Añ8 (!+/LZxj¬«mÕd‰€Ó¬¶±Ûb«]#»Âé×{DçÙW¦gº7®‰¢Àâ6;æÉ2uCwfê^+îð™èUt][£Í­Õóœ9ÿ2f“—£‡N§ÁȦÚ!W5±×E‹‹Vî+c~Û …ׯŸ8Ý­Äjóáñö`2Ù‰lWh«[èÎʯ4U žªÃX÷·L²ÃÕ©ë›âòÅ åjUÕÙ­3ß..`TlÉB2ž^#¼8ì.®¼Âôô5þôËM~ôÂ[ÔEAÂë÷¢J¡ÆZ£ÙÆéì¡·w;ËÚó²®kÔêÒÙifÞ!-²P´ñÊËÕ–ŒÕ,‘˜nà°¶ 1›˜Í.x„=»ßÏÀÀ^\žtM%œ§SWÑ 2ŠKÁènG§½üøÝSt–#ŒÒé ¯_¼Ä|©3 üf¹èi´V‡îÅXwI1.÷“N[èéÎ×kY'©«KŠñMó°Y̘3N—ï¹[ßpè´ï3ë‹ é•£“ ˆ ™ˆ.œ¢Ýi/,¬mÜÞ>Ú÷vùì·x Œfwñ™£OñÊëïòü÷¾ƒ¦©8!‚þƒT6K&=K4c.7ŒÁ¬2ž²áëi“_jòÝñj­Åîqgï½üó_ÿ4C·sš×çg¹6¾ÀìB µÕáþme„~ òúó3T—g`½^àå|£bÃd¶a³Úq;¸=.\~;C£ýŒôõ!KwÞ³=^vGÙ*SI×nÚj25[¦ˆo@&ÙC½^زÏÄ­¨ÕòìØ&˜ÏSljŒîíÎ×ó“Fææg¸/p'8v …²$¬‹JÚÅ|æÓ«H*½*Ú­~êµÂŠÙ÷Æà˲™=»ÆÈ8—¦[²ÔuŒ‹åF„€ VAÓ)×4¾ð—ßdjúâŠ5/“,0>=É ÏÚnw} dÆF›©³Wiw:Ø­¢ñù|wµ±Ù| lïß°¡‚ ððñãsW™É[ò¶xó¥%jÕ²læÐÁùÈÇ¡X¯Mf)Äsd“9r…"år‰z­{»W©œ ½ìŒsC`”-MÌ 6«‹ÉŠÚÔiêªMBZ\=zÉæ Ü1Òh¨V³[¨ÐlVˆ's¼±c;šÏÄ8=gcjöä–f¿Á à ‘­Ôñ:¯o˜f£‡©ZÃéRª•îþoRØlÒÉk+idÙÌÐÈ>ü’¿ÉMÉp«L¢Ctá•j–›IÇ'N2·0…Õæ¦ZÉ£ë:v‡ ­TeföÒ†µ’(0[×=¿^g(É™«iæì*Ós3(Šû|ˆÃ¿ü ™06°«Øi7)sÌgó,-¦È'òd3Y ¥•j™F½D©’@/ß¼µ ¸½ôÇ-hº¾rÄp¹ÛD ×3®Í[¹zæ'E,¶ÀÀX?¡L‘M…HŸ¿F©”ØüEÀd²öºYL–èñùo R6 Àñc'šmM(×Ë4—@§=DµXÄêà öÒãõ⌸Èíð‘WÖ§¤[+]ÓPÕ6‚°Ö§C×uÊåårwº‰¢þžs3‹>@«Uãäéq{ø~lfÛ†i>´ï ß{ñeN¾°€ªvxôƒOð©O<}ÛcŸAVðúÂx}aÛµR·zµH*—c!•'µ`)š$›/P©©× J1rÅa4d:7]wÖ¶ÈLõ„ˆ¾=E:5»a™wƒb)Nr&Fgß‹i®\»²ùK˰ZŒÂÄ–ª˜,Ž—6J³ŽªÚ~PÓur :j I’±ÛôŽ8hìÜIÅ.S—nwß©¨é·üC£÷²0wJ%ƒI±ãñ÷¡©-:íÍV“N«‰ÉdÇæsrþÒ…Û6¨Þ(òü³ßãägpØíøÜ.Ãñ.’°›÷ßwß–;ìAÀbs1hs1ØÏŠr¨Ùj0•ˆòê³§¸pñU¢Qz"CÄËf¦® ÷NÔO=–æÊä¹--Ó›A×5ÎÿÇâ,åRú¶“c#¸$]ÅfÎo”f¦b ÿB!•è €[MÖÉÜBÛÀæ}+„[ h:jGGZ–¬ûûÇxð z2…Új#;,ˆ‚Ž^iQHd©TÖ{ÃÞ€ÙäÄ ›(–H§¦™FG ]ÎdÃbµá°Ùñz\¸.üâÙaOpKŠŸÍ Mìîå”ùÅBŒžžAfrVvø‹¤k&&ëœ<ýã5êó(TµM>·e7¿xý^ÊÅ.«Ü¼] Ê:ÄËåCÁ@©ÒU;Vªi"æ- >€¨k¬Q/¨:ºÚµ½K¢L_O¡Zç­7^£¶|¥ªd0"ŠªÚZg5[©¨AááÇÇ·½‡J¦D%ž#Ê’/»{u­¿qÝ›d\‘ê­N»¯×3è"4`0‹Ai«hµº³°Ýi‹OÑ“ðòµF/•+QÎ]|‹F}}HØ{ I”ñ)”j„Ö©Û¥[G€R½e×&jõ®½_D‚}–Ö½zÜ2~Z»E£Z¢Õª (V¤€›ÜôÂòÍ]•%[0±Ú|<þăxk•IN›D6Élš$ŸÍS,•¨ÖºÂèfê`ËI±”GÑ;~ûàfÌ?ôäÞç¦/ÏýœÍj’Bá1–âW$³bFëèhÆ…IÕq½³ÄÅ3( Ç;Dhÿnp)8wìeâúìÞËÉÓÅ»R•êºN½^ ^/IÏ3yíÒë2&“«Í‰ÓáÄëqyè ³­/‚ݶq´Î |à¾ûØ·k/¾ô&‹3Q*µ:õFv»I1áu»yô¡µQ6‰…äçÅh#Ðï'1už½oŽoº ЛÉqî¹úÅO1—JQ¯­ê ’‘@_`å,Y1³½·—±ˆv ¡‹NtSqæs9r‰óã‹\™8‰º¡? €?èe&“ƪHí;P¶B€#G«Gà£Ç0Œ_Ÿüñ—þ2}¨RÉ0·pýWäwºißBkI¥ñòuÞ½vf«‚Á`"8²Ÿƒ>*Û"´ |W³Lxf¢É$öÜÇ…ñS´¶@³ÙŽ÷ ›Œó% ¥"•J…z½hZ­fI%—o% ¶®ú×jÇí°ãx öé£ÇZ£/pXíüâ'ž^ù¿£ª¤K9NÒ!c«w$ua²Ø ©¿ñ6ÆÎíî”ì"M*‹3K´š«Á/f³ ÿ`7”]íÔ˜{áEFÆg±4šˆºNÌë&½»Ÿ‘Ç?D0;áç®_;‹ÚZ_¦ÑhÁ3 U©Ñã´m*uoèpäèáÎñc'>ëtùÏT*òùνÞá¡æ},Ü¿ª´§›ÞXdqvE±áŒÒö£÷˜€` ~0ÈŽ³I®íÝIì­W‰ô<Ä£?E1["W(PªThÔÊ4W¤äUEL¤gˆ_ûþÙcN¥Vf.$:#½"ÉS,—¨VË4Š…8…¼F VGŠ ‹ÅŽÝfÃëqê Ò;ÜËhOûò !I"ì^½¸êf躾rGÒ Ø¬6n/åìæZ@±L]¯‘ŽgÖ¬"&‹á`A+Rúâ78”X«$ëOgé5Ë™z›‘|€f½µ,¬‡Éd§¯'Èx4Ép ¼é]wŠ ºäv؈áÈ.zƒ!4çÚkZ#á^áÞ÷ÑpP XºŽ» µ×"OÓ×ÇÙsgùô¯~šOê#45ù,±\žÌbšr¦L._¢P*Ñj5ØqïŽu–<›ÅΞ;{nrìÐuxf‰™Ø©Ù$©D†|¾@¹Z¡^»±ZdH§af„³"FÙr“MÀA ä§g¸‡Á0}þðš›l>½Nt;ÈŠCgóó~C6 ëά%‘Ýf#ä 0ûoq q{ éS,=´›{ˆÔLlÝ÷nÀjs0èáâB§ÝõÂfõº-Ž=Üþê×¾£1¸sxF},×&o+©û·æb­Ê"ް Ëö!Ò¯Mò­¯|›Äb’í"3îëÞа MSi7(w𺂠ñ÷ñ÷ÀMß«Ö*L§–ˆNÇÈD3d²¹eªL³^¡\Ju­ˆq˜¸ †7L&;«·Ã‰Óá@ ‹õÒMå‰x|]9£ä´Aúή_y‡ ±Ø\ãfàv8‘„ów¶HšFòôÖ'Éenïfî¶;(ÕJ,ßÇ}{çŠeÜ1:¸w¬?.¿nêíèU—¼òuŠŸù€•±X…´ÍC¹”âÅçŸãì»—éééÇ$ë8Ýv‚½^FúÃx\ž- ¾®ëÝÈáV“L)ßáÆhZ ³ZlìÜv‹M@%šJ2‹“žK’NdÉ ”+eêË¡`•J¦ese ®pW9eûШ-,aiÝ^Þ*¾ÿÅxrÍí¡¢hÀëwQÎ¥è­ßùŽ%%Q¤ZÊqãs5Áð0JaR ê‘£‡7½ÕóŽØ>ÐûU“Ùþ¹Z½CdÑN¬¯HÝúcAaÈù¼j9C§Ó¤T\ÂëëcvzI2Œoã·g1ÈŠ¬f §ÇNd0Äöþ6‡gÍ– ‚ !  ™éÅ"jKD¡njáv˜Ù9´mMAZµ \}^ª–¹¾#6#1¿D*“£T.R¯æ×}ÅÌh´àqwÍÆ®P? Ÿ~”Þo½í–¸U9Ï#ûïã™g~¸&ÐV1Zq÷x¨W·öaô¶ÉÀR6OµºñGdƒ O¯Ÿt¥†Ó¬lÉõޏƒ?°Ú\Ÿ+UêDtS][GO²LùlûÁ¹à攨ÙdŒ7IØš¦ðXH.QÕ¶'z;–é¥T•wÏœ¤Ó®ßäõcÇiwàó:ñ\ oëg¸·Y1óЮ½+ùêºNµ”#[,Ñn6ÈeR˜Ì&œž™D »Óµn…qXíÝÁ¡ÑÕݳ¥ï_yß®ºÚMi`3ð ‘`ˆÝdŽK­‚ )!D/­@I+‘"ÅeH¢’ÈÕn@P±»$wWˆ‚ÛÓ¾ºªË¿rÏÕóÞ¤Ù?^MUõtµ¯_DÿÑÕ]™7ož<÷ÜsÏù¾ÞXM³Œµ}CÐÃAâ©,Æþ¦«Bt Âb*ÇDØÿ¾ ÌôýpÀÏüÂ-œv >{…·•Øó-®ÏÝäˆi áý<7ÐE“´Ç Ñd`µ;©Uó´­"³„fñ‘¼9Okûœ½Ñ,¡i4µC¹eq±û˜Í¬ÛÛ>ÛE(è%ÔäС!¾0Š»›© ÷ì&‹œ/Íz³Õަ©÷¥†ó»¼|øÅgùî7¿{>îf«Â÷_þW®]Åãöðû ÷…‰ 1v.Šßs'¥­¦uØÊß¹vÛ =>?&“•[''8ýúô=Ç‘q»yþ}\ú³ÿrO¾f»ÃÅp(Êâæ£±¡ÿížÛƒûÀ…‹çÛWVn-õ·>:{û ‡ P¼ýT]{öÈ&3†a°º¶É@>JÅž=CI”0If|ž~r…8‚¦âr*´Zu a[yãåµZzQ”G1:Ô‹8èD×@È4¨ëlËTËErÙ$››sÜÔÕnÿö¶Ïåtâ÷¹ Å‚ÄF{ïéE±;±lÇ oùšÚ¹Ki#—a¿,ªµ(—Ó”ËiÖÖA¼.uAmN”íúDŸÏƒÛï¤^n‘LÞyzi·9°)Ý8bäc岪rêòí»n•Wä>þºN:•¹ça’Ûé¢Ùéò1‚°oèÛñ@žÀ?øŸçcJ}ã/¾ô—=·n¿É!MÇúÁ!šÛœ»¿Å °µÆÐô¼pwáÆÛ!›d,'C#Ô®%ÑEŸÛM½­¡ÊþÕ×oÏ¢i]Š•±ÑØ?8Nεg¸ÛPNb…J¦Ššo“/TÉ—Ê4Jeª•éô" ì6yXßbq»E„‡£Œô÷Ðè’Eï'Šõ8vôÉD€rµLc;%ûö²nh4š%ÍÅݪ1DAÂ@¿ëÅ•Êe¾}åÇÂïp1ò‰ŸàFß+è ›8 UZ63M‹¾¾HÔæ¤TØ"W¼wQ‚ßçe)“Æ$KÆ…‹ç*ßþPlá玟.¸TúÚÿ÷UëÌí7×:Ø>4NC©ºa¤'Æ+›slÄSÄ&ýT|÷Þ’e »Ã‹/¨`µ¸ºŒa“Æ’V2ªAâ•Êå$v›—S§(¿4H};ô;=(†eŸ…òž{º€¡d æ‹ÌÎÌ“Í-o«vІHµR¥XÈ1¿8‹ñ=ÙlCq¸ñz<„B|1/#} …"جv'ŸùôyÚj›¥äk+ Òñ$Ù­nIw[YÙ÷ç^Í!Ù­%þüOñWŠ¿×G8 Ô¦÷ìI¡û'™Ké µJaßkI’Lp D®ZÇn1=xK±‡2€í|rO>S̾üò·„Ù¹KŒ´;„^'¶Ð>Ó‹o±ŸdâÎï9‘?6BG¾÷nAqØ‘¢=ä‡\X/¹0É鈕bÄJàÕ$sk³XÌ gÏ>Mö\χP{_þý‹:ðX|œrX¸r²[]n¿pp}$„n3aˆ"µWߤ‹wû³ÌÍ«È& V›‡âÆãòð»Q¼v¢CQFbQõu‹G¶9¦;í&‰\†x*Cf9E&¹Õ-L­n—šµj÷LÜ´Ú5Zù…ü‹KÛ¸«}7Aåóy°)V–STkû'‹l6‘‘VS9Â.Ï}¥âö⡬.\<ŸW;íñ|®¸0}ë —.Ó0tîgsÜËÉç¦xý;M–æ¯rZ1S|i`ßu€gú1 а øƒAŒ.u öŠÆüì šÖáøä3dŸ‹=ðò~(úZ”¼&<§è|µÙí²Ùš#8FSº5&K7»Ù?| Ñã -½ÝÆhµ)Õ[”‹ d“…[9¾o¹Õ,`·Š(N+þ˜Á¡}0ÑþÂTÃ0Ȳ¬lm‘Œ'ɬ§Éåº)ëz½B«YÙ·kXU›TÕ&ÕZ–ìö»î“â=Àãñ3îemm‹á`è¡)ãIÂìç>û©Å•ôÚÏ—ÊÕ?Y[›fså*†ÅLŸÏFb*ÀSµ“¼öÚkܼyƒ§;¥#~jλß`ŵû3ß{³åÁÐñÜÈp3»NïÐ$ú‡Gºá~0(Œº™|êW^iRoä©ßºù=S’ˆd±šÓA­Y<õÞAHTQÍÆVFr•Õõ*W^[C¶ØÍ"»ŒÓg'<a(äÔØ8âÄ. p«Yî"ì IDAT'žI±¾‘"O³•Îv¸jš }*†º¿º¹'¢Ónbˆ~wàk;?,ÿóüi.]øìŸÿŸÅ犅 ’s—ˆ9,ðáa2ÏÄ8Õ:Í¥7_ãÚµiÎØO¡zhÚöZE½+âÝð‘ æY\Ë`sx93JÊü„iÇ·¡ðL”ñ­InN¿L6³@ï\íH’Åhµp]D4‡Œ6æEN×Èdhwê˜LdÙ†ÝêÁï b¶š¨–;,Æç±ßÊñN Œ6.§€ß‡¿ÇOï@”`€‰þax®{y]SIç3¬¤2¤âI2ë™íC²noÃ~ç^Ȳ ßP”åL ¡»ô>tá#À¿ü£?<—IæZ_ûjÚ¬i–ã« U©;DJïíçXSåÆõט¾æ¤?r©c¢æºû…ú§óÌ]]âÈ©CØVtÙÄÑ£‡Ií_Æõ$0_ ˜ß"µ1Cfþ*¡ }ÛÉt*eàÁ;˜v|J-COd’ÔÖÕÚÁÃ1Zçz(ÙDü>ìEûJ‰F¹N®Xdvamz¯¯Ÿ–ZÂj6áq)ø|}~¢ažŸ@žÜ=ȨTŠ,g2lÆ7I¯¥Ée +eš:j§¦µ1[„CQž=}”7—ã˜uÔÕìÅcÀ'>þ‘“·nÎÝZ‰ÏPȯsâjó‘ þ6úKCŒ·:Ìß¾Œò];}OEµH´,wZ±jˆ³,^•zÿ› `{ì!=MEæè¡!ʹ$õFò•Ë8üÝróN½‚lpŸBi5Orc–Hè0õF‘v»FOÿqõúw®—®‘ͬrdy Mê¡êjÓPLø>zùkÓ379p:}§ˆC]è‹’IÍ1?¿ÂÐd˜’÷É<€Ü0o”Yɨ¯±U\³ ŤÇëÁsâò“KÄ(”6¨lo«jõ<þx É5€¦Ü™ ÚësTj[(Ž Éô,nOŒ©§Ú?n°Õub‹%6×¶P53áãCˆ†DÙÓ¤n‡º£Ž¹)Ñ´ZÑú¨’ͤ#™5†r¾ŒƒøÚ nϾ®«<yöÚ„Ó}£\«Ÿ]¯Ö/-­XÚꢀn 4ÛÔÖòÔ›c±ÿõQæë‰fûÂÅóÅ¿úæ·Š«ksžv§ÎÂüÇãÔ•6JY ä5aÿøQ&¿ë °QB<¾k[g:À5%—]åðô¥÷>™h[ §Ãx«*ž…®¤ÌúÚé¹ë$ô³‚ÍáéÊ8ïaè¬m^!ª·ÏŒ£ïá:2/ç©kÑÐ’™ìv/§O'qžÉÈZ…ÂL†oÍÏ‚®sêøidÝÃÒxŽŽy7šo[urÖ»Ëä…V×ßüíF“F³Œâtãqù~õó_ø»ýÖÿùò—¾"#º¡ON'×Ï×ÂÇ‚Šò—vÙ|ù® ÞO¼à¾ç=Ï<÷ú÷¯ÎlnΑIÄiÏ£IALªFÏJ‡v£Ž49Ã0‘ï®,Dí„"1 …56Ò9\õ莴ۓ ¦˜¨ "œ2Pêeäò0ñåUr¹U ùõ}Ç0t‰›ô\7!œÃÄZ¹¦ãt„XO\A6Y9zì$égîz®d¸|õ6ùô2.W„³gŸ¢=ÚG<´o?´\6$I"›ï–ôu:úݾ;Š·µ¶ÿüùC_ümxâ™þ…Ï}vvòøD[M4šEâë9”2}r¹ÎÒkKäÞœÁ\Q»;À2èù0I²ù,öÚ“³j¼ýúuLùý}„>õO?ÿ~b±#˜å{]¤7naZè. ºC¦´‘Úš¥Õ®Ó;võù»O=%ÍÀóÝU^þÞ«äR øüý<ûÞÉŒ°z´f˜Š &ÆÆ±˜»ÇÕ­VƒÍÄÚo?ê³? ¤/~ñ‹O|‘ÍD|ãê•ùŸh6ËȂ€ÉL¹GÁ$ù°WêÜš½Bak‹aÉK%rg—‘¤ŠXÌ"¹¥ z•¾‰ajî+w=tI Ñ§à9Ôè)@£i¢^+°_îÞ¨7pº‚ôVlLOS®¤p¹"{öÅÈÆci¨¨ÿmWÞ Ù¬N0õÂK$ŽHw¸ü‡…!€Ù “ªP.¥QÕ&jSê—Mâ?œš<Ð/ä@²-á@ôKáP·ÿ®Ù,³\P ^NãX‰:9|hŠB~“W¿õ×(ßXÆÒÜælƒ·`!±ã „1 ]{ç š6‘ìs=œ:÷ãOc1ßù—+iXɲpkžBiAž yèÎ~¥Ø¦ôÕYf¯¿†ª¶èï;ÆÙ3?Nf¸Û+ù¸(øë ôa·uï73w[˜‹/þéc_ð8095i|ûÛßþµÅÅE <¦ •b‡Õtš¢â¢0LXñ±•-°º:Kg¡Œ/Ù&Ø2,î²F![ÀûÌmëÁf÷ƒ!@9  “]”Ëõ;„  Ë,Z©v }¾FÏSõï¶È¹òM’߸ÍêüA`x触>ÌVoƒšòxì {Çç­T×ËT«[´Ûuê%}Êf5ýóÉ©Éû7!<ÄÖñê›oÌ|´VÏãT‚H¢ÌæÆ5, ‰¨ÓF{,ÄÛC³c¡VÊ‘H®IäQDÍ17Ct¡zPòÄï‰!@]é`D<Œ¸GPkªÕüN_‚¶ç°&6tŒÖs};k¿µ¡’þ«YÖ¯}#§‰~è4©¾:uåájü“r¶ÍÖ¶’h¹R%ÔzþÃüÀ<p€°2¿róúµÙßÎ哆ŽâÐé4É×ä –±2ÃV<£ƒ!"}Dz#ȃ.ª^ µ€ aÀ}Ç×/ÜûDñ¡Ê:u¿À¸ýQ T*ÜqR'‰2ãƒã4GÝ;㿾Ââì%tC#àØñ~¶†íOàöߎ¶U ˜ÓI§RÝ6{µI³j 8læ?œœš|2³óµ.ž¯l‰{´ø<î4­ÍÆê-,×WthØE2‡¼¤Ÿ‰’y:ÊVßnÞÿímg½×‹^N`ê¼óq&$ûKŒŒcbâôNÛÂÏ{ÓÐÕ-–o¡éœ®Ñ‡H{| ú{Á@îÁáØÍ7¬o®“*f?sP÷8ÐÅöäÓ“¿êp0Œ.;¨¦uE‰Z=Çí¥8žü£-]†Úby5KdåñäVM›ÎF‰‘Ág:ÙeH§ËÛ/xºuJ©ÍÜô*•곂çé³D\šéqUÅ`p7ƒZ­ä¸53÷uý5€þPᅫ†£”«i:jÙd%èëʦæ2ËH3Y¤}r÷‚°P-¦HÏ¥‘Ôw‡~­¦´)Œ OàRº/Š&¤í’íÎ+›d6g‘HÿqÆM:‰‘ûw"? T“N(èÛñHº®²z;~7åÉcâ@ àÂÅóÆSï=yÛju‘ÞšÃð)ØÆG‘ŽÚ$¾²I0½ÿaË~È ¸±ûƒÄãKx7Žyó÷Ô\~‚án)y½Q Ÿïº‘ei~UkãRÂØBnÔÞ'«ZzØÃ8ì»Ë@ûý‚ú O?sîÈ¡IÚ:™ù+¨‰ÌNTÏo"d²XZ—Ö Ÿr9MîÍåmªw†`°ÙW" `·y©7 ¬Ü¸ÉÜ‹”+Ýb[«‡!ÅFñûø‘T‘غ‹êúõ­@ÀåsûÔÀ…‹çó?öS/~òðÄ)Íñ7wþ­VÏ’[[ÇY¾Õð P‡p¹Â,­Ì¾ýî±p¶¬*¶ˆ¯§€BiƒdªK¶!‰2æ€É3pG¦ÏV—ÌH–½4æf¹vó•me¯7Æ©§'÷@nÂn÷â=Ï» íïf3µOe¶ÒwÐ¥©š„{ª‡–õ>؆IiÛMø2:‰äj¹Nph”–õÝ¡_óäê”T µlMßu»6«›þÞ^èóï$|äŽë ¼3²ÉEÓ®>öV0 ºé¢½±ÄÕë—î¨>ûì3êŸü»?~ñ‰lÞ±Õëü[¿ð­_ø[?{îÜs/{·TÅbë­û3múR5, CÐ0Dç‰.W„ÍÄ"òõn~à]@Ë&Ð 9ðº{ïø¹,Ûp[lÈ{v↩LŽ—¿õ5²ß}“àÍÛõG³¥b¡wVbýÕWxåµoîd"¡Û‘<~æðkOôPoÃ;âÞÂäÔäº`h_i©ú/&6ÓB§ÓD×U l(±{n<óŒl‹ÍNË*Òð˜ æ \£P(Ð?8DSy|ù÷‡EÝmáPªL]V(mmîx2§#@ßð ‚ÙAÉÛõ º(¶{hfª¬¬Ü ±Ç”­3Ò ¢t¼˜´n[œ*éwy“*âËÚ‰­»1âK\~íûllÌvew÷À¡øøñ}èž>ûÔõŒï¨LNMæÔVó_ fù—“›y¹Ù¬Ðn6íé£v¯Rªdͺ€·XE÷ÛÐL"N¯ƒÆFƒBn ©"ó)Ô§ÈùÐ4‡ŸPI%Éì4eZ-.ì^6­D)ªì¼Ð¦K&8ØO°e#“M‘J/±¾±L»X f8 —cxóvÌm†hБ5äŽÄè\¥b¡Þг0¿„¦kø|ý8lþ;Ü$<ÀG>ø¾¿=95y`¤µï¸LNM6•Êïé6ñï­/'äz½€7Æ¡=|<{Ò¾¦Tj±A>‘§¿&«Ÿ¶ÍB¯l&µž¢\Hƒ»þv›Šïáø ‚.0÷’ÙZassq§4[U[H‘ ^;—„fÚ-mÙ ÄA?£¾„–L©¼E6»ÎÚÆ2Ùb‹ÐÀk¸ñ•ã»b“S“z£Xþr<žþ;©Ô:–Jìð mKו{м 9ÜM‰N½AÑå pã UAa@èPŒ9¨Ål„¶Dé8b¥C=#ª©ï˜'ðæmˆ‰ÛÜš¹M­¶+¡§ë*.Ñ-â¢'W§Þq$Mdìv‡À7ØOo_­Õj‘R1Éf2ÎÚÆ"ÉLœr9‹Q*!•ªF “`aiã2ŠÃN½–%™Šð3?óÉœ>}ê.ù×'Á»f“S“ÅlfóÈõËGË¥$ÁºG$@Ûb ‹*Í+ ë.œÙCrþ25[ˆX£E+hC `Ï@29µ&a8\(6‰öÛõ Ÿ‚¡¹4·æÓ¤“ûôYèR¨‹ ÓŒî€!ørvÚõÁ‹Uðã‹2ÔE±øA´ÐnÕ)•ärk$Sq6k¬¯¯°±¹BµÞÀå4#› ß \I!gŸ~Fÿƒ?øgŸ;Їä]6€Õ•µ¿N¬§}#±*4›ln·šÇDИ½rf["Ú3…/袜«²Ÿ¦íëÅÚÐq˜5lã=HY‘äú4榋`Á+[©?!}Í^DWJ,.I._¹c øZínÁC±?HPÔiíégè˜Ûl^¾E|soÈŽ`v°vXÄ<¢/ÖËðèI£}„|1W‡Ä¡¸ ø âw&µµÄÚÚ,µÓâ§~æoüÑ{Ÿ{îëö€Ûx× `rj²Y®ä¸vmé}ùÂ:v{¨ÍIÛm£6ãJj,.\£Q¯ÓÆó\_§²¹‚î£,ÈôTª¸†ctÊ©iLªBÃbƪÎÖPí2ËãïbËeVç lÎ^º‹h/:Í*Н‡p­I5º›ân[tÂ-Å™l¬.ct>U—€»è¡mèøìÞ(QÏŽ17œ#õ¢+”Š™•EÒÛ:‡ÆŽò¡—^øÐAïÅ»n‹s‹/— …ߎÇãb½V``äÞFˆ‚¿‰'äAÏh¬¯Ý X.ÑÁëQX][ “Laö‘¶Û0WëŒzZ6éÕlM+刴ÕJ­¢\/ÊÖÐmòNœñ ˜Tƒ™< É:›W_£ÙªlK¸ hÚÝ^ £6±·Í†z*×vRZAÃ’—t2ÃÚÚj¢É ä¡å—‘4-k“¶¹Ž¤™p—¼(;ΊWÑJ­¶Ì š­ f³ÿÔGV~ýï}á÷ò¼…ˆLNMêõFýʵk ò…MÊÅ}ƒc˜T‰\H'êw£f ÒÉ9Ò™~Áâ ›‰£§óØzz©Ø-$­f¿ k0F+‘D©šP6 I¤d6“1™©V4BkEÂÉ*ÖÕ ®t {²†œªݨ`Õdü‹9LÉå’ÊZU%ýê÷Dá‘Fƨ¦“wqGB‡‘MV*•4.OŒ¬ÍÂP¡Fe»dL—´—ñ`¡m!“Š“X‰£TÁv¡™Mئ“Ì^¾F¹²Ø)#©MjÍÓ3·Èæâ ôsþ§~âùÉ©É{ëé=„¤ÊÕ§?÷·ËÿïÿýÎN§ÁታôŸz–µ¡ L¤^Ÿaeþº®âóËÇÑô.w ×¹gЕÝè_PuL…&ªÛ‚a¾û‹7×Û˜oЭ&T·ÕcAwÜY},¶4š¯\E¶9£º-È‹YÖ®~—F’dòÅnn1;ˆM¾Mm#©­#$ 7k$…Ð$Á¥¬aêØf·¸µ¸F~k§;‘± ¼Ñ£L_ÿËKW³ì@ÕZ;Þ&›àc?ýþ/ÿÑ?ýÝŸy§ÞÁļ…z¹ò%’Ù_J§Säò)„–Ž/ä¢é0QwBLq [Âå&¹B|‡j¥Õª %2ØQ ÛöK…î •öåõ b]¥]-ci€a5íDì@0‡CÃat« AÕiÞ˜¥VÏë›D™ÂÖ±Q¯çé¨M¤H'FQ#NÀ2²%Y!ZlÐT,4 MQL} .ÙO±T$Ÿ¥K21v˜¶fê–k- Cïjõãü§>ñï÷wþÑUÿ쇨LNMæEô?miüÊæzB̤WÐó}N5…ºSf¨­Ò°úpá¡Ý©íˆ<øhWKT*i<‚=t§Î`ÝdbK0Ñ,vðm”ñ¤+ˆB«…b“bH½ÃH&ÑÀq!Öä¬__ÿq>õ©¿ñüýßúÍŸÂ)~ ~ 0ubª¬µZÿÜæu~ns5ëL'æ¨g5†l Õ RÐFŸ(RPì8ía,š™F³ŒahhZ‡ZfgÕ„äT0î— 4§ÍmÁ0=x»hJUÈ]y•f«L(|ˆÎDD¯ª"lî(b¥Eik g Ý~w3‹!Td™¬ÙÌ–ÙÌ–ÙBÚb¡n2¡[Mè^;šb¦©‚ºž¤Þ,bð¾¯ú/þð÷ž~’y}XüÀ `rjRýñ}ô_”j¹©µÂáäæmÊ[-†Í µ°ƒŠÇL«EÄf¢öasö`jj´Ú]æŒJ)Ù]*&“¥kâcžÅòRŽÌÕWi4‹˜e;¡‰£´¼V¤J›öôZKÃð:0 ô`mŠ˜ª*ZäÞj£÷‚XW–Rä.¿F±¼¹M#0<8¢ýÍŸþäÿòxðhø¡0€·ð¾^øÏ¢ØN'6J__Ÿ£ª2"+Ô¢ U¯•bØFPЉ :ÑpÉCÛÖ&lwê” ›¨™,޲€àr`ó©WuA|±X¬~{vî23×| F”»[ÓÖ!Ñ×¾(î¦ÆxŸBië0ë‰ åô&µZŽúÂä•\žÉåDt:0,&t‹„!‹;ñ€9UC²˜9vôY-ƒÅ…WQì‘(f5F¿Éƒœçv%‰Ýæáã?ö¡ò‘©ñò½ï_úg×߸.¥R3éÛ(v?VÅ‹ÙçGòxÀÐP· TÒk”« CC–mÄFNcêEõtƒSnìÊÃË€^`þžëJøô§/~'³•úWÿö_g)½~ Ï÷]HŸß©À ÏWé$ ´ÎD©)&Öà0xõF7FЗËl¤²²é®GÈv¹AÄ,Û0™¬xÝ}øŽôRöÚ9ê“°„>‚`@2s… ‹—'J¡˜ce}ƒF½L§U§\I3yô,/½øüØ…‹ç3_ø~ÿOþí¿ùÉoü÷Wþìõ7n˜ ù ÊÕ4ìCÔ*^o?Ωã¨!…½]Zkwh6hZg€wÁ~è–€½8wîÜז⋟¹=³è)æÓ 4ZÃÛ" ÉW^~Ò*›–£kˆЭäi º°‰Ð3ÒLjC6¹Ñ4N»AGmÒé4ðyûéó:° b¦gw òGvS'—]akkz=,Ûøè'?’þµ_ýÂÎ}ê©§nÿÍŸþä?‘Ö÷Ê%ýçRé„°©£ß;ˆý=O¡í³Õ–6¨U»GΊÓÇ ï9ûŸOž>½pÀSz~h=À[xöÌ™‰ÄZªúÍoþ7ÓõëorÒ$Rx_/™£^†&˜{CU ÿØqªî;×^]„RÀBÕÆy2Ä@ö0úz™µÕUÒ™Éô-°À ÛÐ3¡Øúp{S€@³VÂãî¡P겊ˆ’D$ùö~cýüþÎ7Ý>ßñÒ•oÞž¿›©ÅîAÛ‡Mèè´öh ôö›òÕǘ®Gƽ\¸x¾ôåsÅĵk—„Ë—^åpíúûá##ô6¬Ç¯#~UÄõ“ÇèXï4‚àfìLžTb“-ìV;ŠâÆ¡¨”ò V6§xvçwAæøáçÈ–f©å¡ª‰Ømê"†®SkÕïÙ¥rñÓ?7ý߯_K®ÄoG Ã@’ä¡ Q±íË÷)Õ;;J"f³3/ž¹qáâùw%GÿCoÛÔç£ÿåë‘[ßûö«Öéé×é«6ˆ<7ˆõ¥ Z_k²¶r¡ÿGÂû±CÔœ»U Ú ¨%…åÅë;™D³lÇíŠáõöÓ‰î{߀û06þ’7d “ (Òé4ɤ³¼ßxG†Þçü×b!‹K Óh–ºÒ6–ýk …jkgÛ÷söÈÔ?Æ4=Þy&†Â…‹ç—¿üŸþÔöÙÏÿì›dcuš¥¯_DZYåÐKG euå:•¯Ïc«ï>VÇ,:`hp IêæþG«ÅI6¿ÄÚÆe–V×@ß­À•"žö2£¹×ºò¯Zg‡UÌ0tóû[Ì6þÁ/ÿòW{¢QÃ0 ¬ÖnÌ"Š÷>§èds†Ž(J=6ѹpñüþ,Vï~d à-üÎoüÖçéW>ùäÿðɼ@›Ë/_¢=Ÿç©ãcôŸ ¾2Mû¯fq–v½€³la%¾H³UFÆó?E¢œ›ÅÅââ%nΑ‘ê4?yé«|èÚkœZêî|j§Ë½l:'~ùK_¹¯÷ ÷­v³lÇd² I2Æ>ÙI¡­QMÄðx{8÷ÂSŸ?ˆyzXüÈÀ…‹çÓòïþØÿ[¿ñ‹¿i¶Z¸tõUææ69>ʱc§Hç³ðòâ6’k9Eb£[]ët„øh»Ì™j‘_+¥…'°Û¼,-_g!þ:ÏÌÏÜu?§s¯`±T8v¿1F{ƒ·DA¢Ù*£ØHâþ™Bi5G¥šA&FGŒ°7ø{b?’ð¬6å÷†v»ÆüüÌ¿z ÷‘~F>yë!ºØmºX_LíôÖܨne€Õ" imTµÉíùÌXïÖ*t«í®€r¥Hº”ûÄýÆÖ }Å$[ÉVq;#8ì¾»N,Å–FueÃ0p:Ã<óÒ™/½[ÁßÎÞÍ›4.\l$" ˆ»SU¯™™™ûÅû­'Ü÷f‹•z#nèø{FeYßey“6‹Ë]ÅÐh$ÆáÁÑ_z¬‰xüH@d ò‹¹ËÛ§éænº¶ÛO'Z¨íî Vµæ·ÕöEµ6µ… ˆôFOL¯2c¿›®^ÜcšÖaöÊÜþ*Ó»XµZºåaf [ÈBÛmŤw LÐ 2œœIDAT*Ë èºŠ(J?s8sáâùw‡ e~ä à©cÇÿ±ÙúVE®Ðå)Œï–Ï5VzÓߨìÜYXkë´0 «ÅEo_Y¶ò_÷iñÞk+kqáË_úÊ=Ù.\{;íßÇm ô½å— HïZdR˜ …ï]Ùžü³†ÖØN!žÈIo¾xô‹'Ï]ùÎ{gûº¯^¿çÈ‘#ßûƒ œ8qÂò•¿²må>KHÊ&/’^B-d˜šÊ€ б¹(ƃ­XQÄpm|êSŸ›Æ­›Éf³„¦#O­è>tøÕ õíF[ë.ã¡Y¾ÅÀƒƒÿ‘e®üù±¯ÿôÅ¿NièšAùhMÓHÄÙ·{ìC¶A"“C85Îôl·»ü*@l9©KEÄÖjbËó¸ÜΩý÷NŸBU Ôìmg2¸è~õÕW%y…PSYiJ:r8Ý.S­×gºäîE ÅÈŠœeêë(¨ZÙ¡ƒÏæ–"ÂÆ†FtU£XÌ01Ü ›$lfùËshz‰Ú¦ºãÿ-/ 9T5Ïò™Q$àÀÚÅB¡éŸ¿ý/†ŽÙl§b¥¤cZoÃa/§©¹÷íÞûÍ»¿ÏÒUMñÚ<O5f“Y<úù/…uægf©oÜ€aÌŽÍ<üÛ“O>õÛB!Kg×Ý,ÇâÔV­Ë®Ä]5ð»ß]n©ôÕ^ ’ϧˆDEêqZ-Usþd?§OŸåÎmèØfs,Ì-ñÀ¾Ýì¾w—TŒ\ÃÝÖN>Âã­%—×ZþBò|o¿S%Ô=MÈ'/±sÛæCk œ8ñO®™™y±­­‰Jo%#×.#I ‘¥®Î §®¡—TÒé8ñD ³E&ÕXNiX§»»ƒÁÑÖ×Ôɤч¯ãÉÐ9tèÓàÜwÿn^y建ÆÕ©ðëÏ}.ê«ôí•ƃñRé þ*…\ÑEUC'Åô¥R‰xÿ<õrüD W¹]ƒÑ‘ÌSSºÆ¾ÿc,fµë«°ÛË09d´¹—úûèÿ‹+X¬œvåå^<£Q– OxX<ñR…b§$‚Ð]Òtl‘Øb}C™t‚l&N:›e1,Sæ°£é:²,ÓÕy7ëÜ^¶wwñ—_þÛ{:H&RDãqÌÌßXB’ … ‰ø"¡ù .g9z$Åøõþê…—(†ú—¾1,,æzCà‡ÿþ6&›L™Ã‚Ï¿ AP I&ç2Ù4m˜-VZ:\„#‹Ü†øö?çbß§ƒúõu4µú讯DÓÔ5Žg@`MSI&ú^XíÉëÓ.›³œm›(|¢ËÕ( ‘d“Q9óÛwPÕõø|pz¡JQœ[דnòâ8Ä$‰'¦ñõl&×Z‰’×°Ì3pîn=F.C…Ç‹Ãn#›Í’L%ˆ'“d³)òù4V[þu>Ìf #ãWq8<<úùÏöÿà[ßµš€Ÿÿê¤ÛÖº Äûƒ8}åäv¬Ç:¥úÎFÒ­•-ÅžZší&g‡‘,VÂ-uDò…ÞøýUÔlÞˆûðˆÅâŠâ©$.wu55˜dquZZ35íë¾o1¼„{w¦@Í$‰’Ùâ[ÓÅ®@‚ÜØ"¥|†ÄüF,…>5‡(ƒ¾¿ AÒ½n’=õØîiFQÌØmvãéç½Óº­u¶¶¶ák·”`[·Ü¥—y}‚¤—À¥ FÒ°¿MÖðÝ ô³«L#›,H²Bóá½NO`2›(|²ù>»‘(“g.sczx­ÈÍèìjyc.0M*•B–%L÷· ©Îpv ϤÇ:¹óÀÃȲ‚Íb%óÞùbnMp€t«UUùÜ“O¿ö±~ôã~ÆQf#4?‹ÖRKÞnB“%²½7n¦ØXFûλ(ª%Ã1<vÞÂtY–ˆ†c÷}¬€{ºw[,r§¨˜M¢K:¶óÓi"ÝY Š8lVTED|còѲ*âHšÈüä‰D„Ö[>y‹¹›{`/ûÚc?ýÙ[¯Õ?Òƒ44Z*[Nâ¿s‘Mî5\{(Ãо…hR¸ãàļ‰ÔÀ¹t‡Ã…(ˆg' oíùæ+ø»ï¼òúÀèðâò¹1Ÿ¦ÌÎÍR¹¹‘©‰8u 'º’$082ƒ¦)•òd‡Â˜;«1‰fœ>³ „ØÖÑø¨8·ÍÀ ví¼¿¤#J%qÊ66!6×#ª:h:ºÍ„6ÀÈç ¹±›U¦:—g¦¨“Ãe7W‡Îd¹?ÖÀ®»÷ª‚U‘-5,\%žÈ )&LµÕxËìÌœ»À¦ÍÍÌNOcµ;ȉ"†F&G©T ®Â£ö^<­|”ömÍ~ïŸÛ$kºš a·Ù¨8úÇ4ú+QÇ&ðç$z:ï!¸ÁƆêì®çÛ#%5=‰yg’ÙB™Ç1w;í?ÈÀ»gÞTÜv%’Ч(ë›!á±Z›eÿÒ³‰D¿Œª¯-§¤²˜l6Ãö·.q:ûWÎžÛˆÃæ °¨”’†)œ:sZ÷Æox¯fÝ#þæž5-cÏny¶ùSüÍ·þæþ'ÿöɆ‰÷‚#a]ÃÌYd¬NO©t”±±?ÚòÒÀ%^KK‹’Ïgéìöa?êCN)d $IÇê«3—x¡HT E©¨¯Ã¶b';ÑT•@ÇÀì‰v7>¶ñÑ™3hï½ûþšóݣΗ^ø÷ckï}¸s"çŠ)ðEÞÒë$ák_ÿ†*™äl %§b°Q4 1¯áïA¯3‘Qâ9~ºxóºuÆM?ÿy@E2©8ép%8F_0ŠÙl›hBˆÅbz¤5 ƳŒŽú1-Œk©O&wíný×¾þ³L›ÖŒmM#¥ûì>ÐZûÊ+¯è7lؽBÀ믿^R5£Rl¬ž ’¦iû°•£­­ÔÝV븟”ù¼‚(êˆFìë ÿøÇ› ÊÊÆSé&“Ýœr¿ý#@V›‡u›×¾é¢HI‡(^˜îÙÏ‘ÉÄñ¸ Ù´i“:ÑŸñD\ …p@0ˆH¢È† rWððà—,¢Ž÷ì¥`J15…%XŒxàs¼ò~ @ºÊÐÃ[PÉÃÝI`x”p8ªÛ·§;<äoe<6BIq%ã…&L& ‚ ’ˆ‡‰¶çNÓM/  6HÃxò¢/Âä™°k×.]:BD%Mo漢¥aÆ ¸üêœ$ ¯äÿúí´Ÿ;‰ èe3f“B¯·³ç>ÑEåär ‚¨£ß7ĪU·_ž›Ÿù!uuMx+<„5$IÒãõ–áïšöå/­-ªôn“$‰¾¾N*wdq9Ì$“ÉIÞzó­gR©qdÙBÓMÍÄG£ôöõpëm7ÕOäMZÄ:½¾lx4ŒN’Ñ4 %“  p¾ó‘ð(ª^@Ð4ŒfµK9ÝîgëÖåƒßí$I"‰öÏ7!še¤¨ù,ÕUõ<³ùÛ|ó›ë™}S£'<y,« T­]†£® S©YoFQÒlÞüô*€§žzʵ}ûî§òyoA)Êìb\e¬ ›6m꾦€X:[›N'™7wz½iRDd“QgÄÓÄS_ÂX­UU9sæ»wÀh03%½Û‡:’ÂÛ5Žß?ÈmwÌçÒDz¼°„U+nGÖé1tųyFÎ`¶º¸õ–[9~¸kÇÚÉnmÅãã‚€Ía&e•I$6û¤52i mÛ¶Ítâh›GUó¬¾{6²AÏ¡ÃɤÇE‰d"BûÁ£LY¿]"ã°Ÿ˜^$é€ñd›Õ޼´„Ý@æ—ñ¸=4ÕOçt_'Ñ`˜)•¥”•Gè9ÙNÁº¥xÍUä+´tzåŽù¼HYÍ<†{OcuxPR)Œ&;ììÆ?Ä(k„Â1A$°å¹AÉäzç²^"‹S\T€Þ`¦©j*Tý)jzÙDQ‘—œ$ ŽÆ‹Fx~ËVŠŠ hlžNC}=½IÒã™_Á(0>¦¼´˜%‹ç»{úoßñ»Ös6lÔ]0446†,Õ¢ C¨uc+"›MP]SNgW/ÙŠf³¬z„ï¿l£·'Âí+ïàÞ»×ðïüáð.W!áð%ɦï>˜Œ<.'%EX­vDro&ëqG …|œï„=û>F¯7a4Yp¹JÑõ'(NÓKðøÆ¯à²¹˜×ìax,Ÿ4…$A*ŠÇc8|þ!ªìœ-u“lóÑÛ—EuDBÄ{ ø$h¤¬@ «SÁ “É)jªjÐh˜fá?~íç᯶0§±‰ŽÞ.ÚOv08 íL'áPY'a6ê9ßv$“ùӑͦÈçÊËh˜oc߃çxæ»[p:Ü<¼î~d¯Õ?I@<™©H¥bNáû/… Q¯«D¬-ÃØ7@d̦©˜M.Bci,˜ì:½‘={ÒÚzв²JfÙùÃÇm8^¬63¢ Q_;úÚé—üá_eÑíå,¨çµ7œ8ßþçkI’)v™Éç4‰y5G""sâí4.nÚzYÀæÍ›Å¾ö‹(ꈌ2ñÑÔ´€œéÂÞ§¼¼–^%ŽÛY„NGÈå4úú}8üã3ß!9cç'ûpYô†|x<żöêÛ¨ª†( XÌÜN……Lf£,Cú<Åv3‡”øÔ|—‰H–¾þIÛÌ6j<…¿º,À`7¯ú‡«Å‹Ån§¢j!ùÏ×Cw4 ø…H%ÇÑ4•ªÊì;ð{JJj9zâ$3gÖ³|Õmüâgï°bùrî¹g Ét’öó´Ÿ_€¶ãgñû‡ °Û ‘ FRÉ8étœ|þƲI¯ÇªãÐ$(y!RÓ>Bt‚ˆ¨Y`ìÐQTòÄÇG¯ÒÆpÐÏí+o%ûA–Hlœt*}!Ù~ü£Wô!ŒÔO­áÉÿù8Ï?ÿ2ã±î¸c Mn”®A² Ó8¸ïû|‚^oÂlvNÇQ”ž³V”P\ZùÓIŒ’0b±: {öŸÁ3cš¶cÎî;†ÝS€mv#'ÏÉ$&-¸\.Ë÷þ×Ðéd¬Ö »ÖÒÒB:º;™ZSÇC_¾›÷ÞÞŽ’Q0˜ŒD¢ôzÕEVßþAÓˆœë¥cÖ…×lmõt¾ñ؃ô>NÈ`äl[?‡ï#ŸÏ¢×)ª.É­[·®{’€×^ÿYÑšÕ÷;vº z0A¬ÜBv(ƬÏ/$\çÁNíwQçráv» ‹ÇXµj)‹o]ÄÀŸ?8Âà@€³çº8r쪦!‰"V«•B›’’BÎ÷tÇ0-»£kO¦ê PVVˆñ¥×YH’’e¦®»ŸÖÃ{0šmèdiÒ2½ü!k˜Ûð„Ï7úZ¢ØŒ&@zõtÒŸÅÜFjj Øû»©˜2‹§“ò²rB£Qzûz©šREŽ¥Œ„†4»ËK^ÍsêôÚN'84̇;ÿ@<>F:=NaáLsšHžïÅ”Q8SWI Û$ê¨qZq¶_È LŠBß™ó¨ù<6‹%—K\UÀ–ï}ïõÞ]ôš«#ÂHƒ éý6¤åÓP,—Im¢ 9’Jâ9ví9ÈÁCG±ZíäU½(àq;¨®›ÂÜ›šhžÙÀ¼æfA@ÕàÍ7ßf×®„B~¶þÛ6Ü.7…å¥xœnÂc' V¦-˜MìxöTšÍJ»o„K ˜ÛåDÅî« ¸yqãÛí8ðÀŒülÆ•ÜGgá‹$lª«±ØÌئq|û^f6/@]Ý€&€^Q±v‡ItóŸïÿ–¿Û…Ó[D>“Äå°3eJM³f ©@H4J¿¯ŽŽÓäÕ i¥(Jüxë/(öz)««¦´¤ˆ®ßï½ìŸ§¤ˆR‡å…‰>_Q™ûâ]-#û´zçÜq+ýG;¨h¬!º  9­bN=Ö ƒÜš™\ ÖÃ~N~²ï²eÄÆ9k9EA§ ˜sUÅb’°Û ؽ6â±8¾þABáãñ©ä8Ùì…|@ÓTôz_xôËÚ=·Ü¢oiiÉ_S@sãÍj8ª^AàýÔ.ŸG¸Ê‚Ï¢ßÛ‹¡ÐAxnáU¿„ìahtTÇâ[Q-ªêÉnb}”–WâZÙˆ¡cŒÔÈ8²,_ ‡ÓŠÙa&èbxx”lVÅëq2uIsòÕç¶X&Ú¹jiñŽU‹V½þ‹wvšºCT¬l&v¼ªÈZôTÏ)¿ªÓ‚žý~†ƒ!Ì6ª?C*ÁÒ5€8«)®íïÄæô`¾o. ½€¡ÒM“Kê*Ç9¢’ …è?ÝG,æî‡Ww©¢hFãÖ¬?2~¥Íkw›nѲy•²{b<3DxayI…÷N Ë2Êšú«¶pÓ³÷@/š¦"ŠE —¡W ÒÙÆÔ¯® å1locp0Híê%DË&Ç2ñÚ~FGƒüÛ?üÄ8±ª÷ç¸fmô¦ÙÓöGÂ#hGd“‚¯~ŒíÀ3+ɤ¯ÿÙ›æÆ¹þvæÞ»›Í‹ªæ‰?Bðt+åe¤í2Ù7ÓÕÑEÙK¯p |Ñ,²Ù4¿Øû«=׳uM_¸ïÎ¥:½ŽÁ.?`ˆê;f“†I”X±®¨GTAÊ^¿4Ÿj(¤úñ{™>méô8ùœ‚qétòïeph€ê¯¬$ã”®Ú6ZmÅf÷rôhÛüÿ/---ùºšê¬¦iü½HIõžÙ$mzëXÝÎŽë ÈéTŒ÷̧¸¨‹Íƒ¡7Lo7/^HÖe¼f;U„’âFFyá…¦}fË?·xI*4|ÇÎ!LxÌc$Š ¤>UDVÎ3m~™t’“»[qWn*½n½"‘U²èôæÎ{ebp#ž~úéÖ»î\¶Å`2  O\®©âMSRUÄðû‡®Óß›îÀî-&‘Sæt¡Àñ‡~û‘•ÉÓÈýånÎwÃëöjË–-Ë]£ÛO?àxù_^þÖÃkïºÏh´’ûèBò­Ëª„º£k ôz,;¯U]‚b(°Ùˆä¤œFzAþÿ=¦ßž§¸[¤¬ßùä(âÅòæ´uÁëõ{C'4[^xὕ·-úýà`§?‰c¿Ât–®=g©¿yƒÃ¼nîöÝm õ÷PÒ&§©›Ú@ã­óI¦Rœøp'v¼O8<ŒÅdÄlqqû]+¯8•™ˆ>ä˜5óÕb¶¶ùµœûÍ~,&+ IezmÝ=A¼uå”èóäÝf³Œ*h(²wgˆû’IÆP”¢(Q³`Ž[ÊЦðï:IyC-ÔUbñÅÀhçð‡¿¡¬¤P;xx×uƒ|C‡|—°xùü§~½mû÷g¹h˜ßÈéÖSDÆ|´k¦ù³Ë©„e Ò¦ãC(òVNıpñÖ#˜lnò™4i£[g »Ä/,dä“Ó˜†"t 3òc³¹¹ó¡û¦šOŸiþjãÆìøÍ¾UUW‰µÐEÇ™‚=í˜í^¬Í³P=Ö+i=Ò†šQ05דëBtX¡ìBP§jè4EÈŸîa¤ç$_zä¡gò¿·þݧùsCk`"~òâ‹ß~à¾Ï=ÚÛÑG2šÀþ`3KV¯Än·>¸Ÿä'Èöø@¹XÐ4Ä=Œöœfze¹Ž~’ýÝd{ú΢ §È§²ÄÏôýh7©È0ªšCÔéÜ×÷ä>Óº„ç~øÜ«‚ êÞy÷£ŸVétÄMEóëðTÌC÷ÇÝ>B§O£×›Xxó¾ñËÍV›A°T×ÕD®ßÑd£zFí]QÏ>ûƒ÷\{Û”±¡aÍn22|¼[Ç9—áaNY¤wЇ-ÝÁr_Í¢J6›áàþÖ—6n|âDIa±f69‘ŽbS~•eS´üû¿ïù‹ Ø´éûýßü:ƒèu-¶=ÒÉlç%AVI±·í$eá1<…쪻Ã÷à¥öV«9'ë͈F=BB!“ˆpÓ-Í/ݨýÿ²€õë×»^üCƒb §·ùB⤗Dr’LP/S¨©èuFüCÁË;p{C:«¯¨¢;߃Ýáᕟ¾´ñFmÿ?&l2@¨äIEND®B`‚nestopia-1.51.1/icons/64/000077500000000000000000000000001411157722000147655ustar00rootroot00000000000000nestopia-1.51.1/icons/64/nestopia.png000066400000000000000000000205411411157722000173170ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsââz\ÀtEXtSoftwarewww.inkscape.org›î< IDATxœÅ›yx\åyöçœÙÎì3’f´ï’%Y¶Þcv$N€8!@(IÈB ý²6 IZÓ’öKÓÒ$%-$J& `0˜ÍxÁ›dkß·‘4;Ÿ™sú‡Œ7 cœôûîëšΜç}ïçžwyžç}GÐ4?Â]wÿÕÓ¾e“ºùê«ë>ù…Oúÿ”ÿŸCÓ´súÜ÷ýûÖ47®Ö\Žb­²t…f5;´Úê•Ú¾|oÙ¹¶ùÿã£;GÝ„ß<öÂÞñ‰>*+VSTä@Óá÷y8)£­[·ŠÝý3}#…k7ž÷œ§¬ô®iß̃—_ØòÉ›o¾3tî?ã¹ãœ¸ãŽ/ìí<ÞšÖ¶÷ê)VTææ‡˜š™[ùnv¯îØžd³gžúãu‚(\—J„Ù»³%84Xÿío{ïé6·Þþ™ý™x¶²¡¦tlçkûW¥’ >ü‰koÙzïwž8î§C<£=»­³ZݬY{1ár3a7È&=Fƒ…@0$-eó¹/ÜùpwO¯TW]KÓU›(ò”¡©*kV]Œoj/¼ùæé6Ÿ¿íÓ¿ñ/¯zuçkEÿñУ«'&§„<áÉÇ~û˸¿ì\¸ŸŽ÷-ÀßoÝú1ßô8¥ååL,׈Û¬‘,C}˜eÑX„ûï¿§êt»p(vlrâð:˜+ÎàÚ²Ž —]ŒyE%F£p8²H¸®¾±k—·´rÞ­›Ñ4•ºÚe¸6·ŽDyö™]#çêôÉxß¼ñúÛg³Ib±$yQ î0 ×KÄsD#stõvŸn×¼¢ñ;élŒ\\ÁÝ9KÖ¨1ß\€^1ƒ( ±x7 †#’¤—È÷O#é ŠŒÈÓ 45ÏèØ¸þL<ÿò‹_||yÓueë&íò׿ï¿ï¾µ_ùÊWVÜõ¥/ýã_nýFíéßMOû m¸o^‡v̺¨ÃÓîFɥѴ<{w(Ù¶m›|²]ë²æÇQcb:Hïáìb݈¢€Å"/R žH0çB‹‡±™Èš2&÷ HÉårlÛ¶mѨÙúÍo6nX}¹úÄ϶}Òç F=ýâÿó¿¿ãÖϼuúûK.‚@ì¥d4í&Å¿ùø-ŸÑƒ^ÌU§S¡pTXùávÔ™ÁrÁ‘É”rÜÞïŸä™^:¼eË–eï<Û²eKþž¯|‡T2N:“Àwp„|^@S5 ã'søÇüþºD"‚Á c,0 åTþ) z™òÒmË–-ùÓ¹¿¾»£ëH÷~4Ö_p9Ùõ•¬) gw/¾ºkÃY `õºŒW_ÑŽ  ¨j^êÔŒVöoÛŽ»°ûmàš‰“·šé8Š$êÉ«94-Ïî—w7>òÈ#¶OúÓ1€'²1ŸWD—Ý… isDBShšŠ¤³'sèýš$ÈåsÇŸÉoŒ‘HÌUe¾¥¸‡æCǦ“¦åQ Y¯‹²’Búü<ÿ£ç×Ü}Mæ÷—œn³Ù´àû ˆ¢DKý2Ö¯]A6›mXÖ¨gj:ˆÃåÅluáv—áp”ˆÇxâñ?D¾ú•¯½ùøO~Òø›ß>ór>§‚¦£ä¢fļ†Î £i*CC#'÷·zÕê­ª–Çnw ¨064‰ ,p©ZYû㥸Ç)A¤ãÐAæÝ.c`x€ªò*ídça‰°í¿¶¹F“éwÏ>O`vž²ªR–µÔQ]Z‰ |ðƒWÑÕ5H:› á2"›Ì¸lv¦f2|÷îEbɽ½ýÂÄØì…½]}‡;‘H°»½dŠÌH9 QË# 1=3-|çî¾ow/@]ÆÛ/›,Ȳ뼂&„%ùX—g~"p ðÝ“¹?ÿ£ç©TÐ ›½T&‚2ê'“NpÑÅ«~zº¿‹Hä¢k%Q`ÇŽdÒqxôz“ÉŠÕjÃë-¤fY]}ŒF˜¯v`Ð dó*¹lŽ;_çÊË6a3ÛXsþ*Öœ¿öyr¹,Õ5-xŠ ÈçÀÊ’Ë+Øl²Ù4o½ÔµûÞì½ßmijùÞ-wß5ÿà› ö  4KMU›ž©c<§G}‹¢ÍŽÐžR©…ž*ªªËñÏÌ391KyY5ÿòoÿú¹÷ œ¾µ{djÁùcP”Š’"›czzçX9Éxª± ¨vM†©l¬Âbjäè‘ V¯ ã²9Ûwu ÒrÉz¤ê"âvAÈëdJK½äs9þ᾿!œŒÒß?,ôuMÜÛÓ9vï?{–D2Mû† ˆ­hä_;ˆ ˆhšJ0•Oçþ‹_½ð‹L&Ž(J4´Ô#y,”tôtpÕ5÷Ÿþþ’¤µ­ûpNW9éT„t:¶ÈHÐlŽB¢›ª0dòØmˆ.4¡üqˆïýÓ¢dTWVóÅ»?ƒ¢dI ÏâÉCj6ƒëüJBN•Á¡!jª0Mx&¼ë<Çû÷MÐ7:Flc%…~‰‰»¨Xß„ut„L&A4¡ŸøØíá¦u߬­®þï'õ»¹Ñ±~Àb)"½ÒKʪÇTê ßÑMãò†¿^J€E‹ ^ÔÍÎÍc³˜¹ðò+0[Ü‹@Uó”t&°îš¦ ÂA ÞIÊ*aÐk¨ŠB4êg>´ß”x‹!>ŸÅaչ玒Ï+\qårJfQÅ…$£A¬¯ŒbŽ©Ø¬23ûúQ5•[ï¸+¯Û€ ˆŽƒ»»ÜöÄsñ¡¡IY6; QOÊz,NŠ*h¨HŠvä=GÀ¶mÛ¤œ¦ÆbaJ‹ËøÈËÑ2 ûß~›hdöø{áwAߨEõ§®$cVõ˜lff¥…Î-f+µ •ŒMûI^]I0džFú¨ª¨¦¶ªŒ‘é)&A²Á5¥Ô”•MÆI%#ôífE£—ÜæJz‚„¢ó¬kkGh;Õ™l6Åÿ÷6º{z1‡³$$³„’MóÊöݳÃ3_{¾µ¥ö¯îüÔÃK ÷ûW÷Œù¤t:ŠÉTÉdBSTŠKš@‰Åf)¯hAÉæÉe3õ䓘ôýûÐé hª†š_ŠFÇúÙzß¿P\TŒNÐQØ?OÒjÄ’È)êë0™í4TÚi¨<5èΑÏ+èFÂ¥ Ó]™‹Sàt3:5FUi¢xj h0È€ÕUˆ¤‹‘r‚(¡“ âܨÿºC3×=ÿôëÔ5W<üÀ÷¿÷ùS Ì~Å78Žªæ1Ë&¤Ìkè$=é2'…J=²ÑN4DgБLFðx+™ŸM£ªYÖ®mà†«4îý§rù,‚ PSU‡Éd"šH13=€ï©^̲MSéëâõ9šªi¨¯Ã 3ç"‹z =µÔ6U96Q³i…¾þù»]LVÌf v«ÂÕ˪h[ÑL,ždYK-¢ÑR¯öRì)åã=‘ üîÙí8]ŽE# –VÖûçXíf ‡¦©È:D•åðJ.Í]wž‡ú9©tšœfyk5[> ¯ T–W0<<ŽÁ`æ“wÜ„ÇYÀOþ9‚ àr—²je;ߨE^ÍŽFÙ½ço¼±0ÉV……nÜåÐ >ÇÿÐJJŠQuz̲‹Drž\"H2$0Ã#°oÿ.~-éq9+p: °lÇâÐÑríG/CÓ4Þ î£žšŠÆ' ‰¢= "nˆ26>MQQ!±Ê"D‡•LdŠ]o"™Çå¬`.4DpÞ HìxSOu¹Ž“ÉJ‘caE‘Ö–µ@ž›?"±{¿NÏ—ïù<…7SiúŽ212É\ Èèø8#ãÓDÃ3ÈF‰ò’B¦gýD#AÌæ–‚ªªXmË˨´$xù¹‚óc<õèSu#:—U½í¶-S‹Póš-‘ˆ"ËNRÑi#S3ã”U• jÆóš‘¦FxíµH$ç1mÄ’”¼x*ªÍ¨ZžxtޝÞs/ž¢ Ü^нVôF½²ä²i6]v1EÎ…è·¼¨”òKKáÒ\vïÚËïŸÛÉu[–³ª<ˆ¢ºyàá‘HdIç z§ÓФäX_âÃÌP>G*&• ã÷àøïy Ç·ãüòÑGk¾ ”ÉÄ)*ªg׫{ye{‚|>K¦ÑMÁT’9ÙDIm;F5Eÿ!TM5ÇŒ¯?v\‰ÓgÄ/a0ÉT4SZì!Ž%il0Ó¼LåÇ¢ä2ôtö3;1Ki™—æÖêªk99ÿ(¯/§¤¸œ±¡<«ÊáíÝ2n1Âl2ú® @±MQÐ88á¢gà58­Î 7è1ˆbx‘³þ™OùF&Ð4ƒÎŒß?€(ЬX±ŽH¡Œ}b!24͈é‚ °fÝjœv/½ô‰™Ó0“Ó3„CÓl¾ñv6œ¿ €‡‰¥ct¤ðû').®F¯Ó1雦o°Ÿ/ïD”t˜e+6«§ÝŽÃaÇ*ˤc I¢6ÅVæ!Ö×ñ®þ+J ½–äSx}û$ñØÜ©ú"ö /e6Ë‹‹ GnŸŸÇh´¢ *EžJŠ‹àêÆ…á¥.dmÑùf&bŠ7^{Q”°;:E btr’ìëiž~ƒI6c³Ú(p:)«*¦ay•žL&3‚ éTŠL6ÁÁÃèê60˜|OçÄS—tÀn³c„à%—\rü·Õl{l[q6™$AOÅúe—jXAÉ ¡×Ëø'}äòÙ%ÞXÞºŒÖšZkÈ©*:q!’ '¢=ÒÍPï(þ¹y&§§éà¥_AEd“‹Ù‚Óagtba:E£¾“¶B·›œ–œüLp`´ëΙŽ~œ®‚ ‹“ AQQÕåÍLÍ/ùž^g¤µµ€ûï€À¼^Ýj§qYÿØõ\´~ý‰v5¡Éú:™Ÿf>d|j’X4p¬=&³L*FVIsúª~ö(©.AÅSÀDÿÄš ’J%(Ȩ(ÆÅ•²\± uß(Y%Éìô(‘èÌ’Ý f*ËËpØ­ÌÌNH‰„g GÂl¾þZdýBÈûãÁ˜Ç 7P]]Î'ÿâF,f+¡p€­[¿O2¢½m5w|öVf‚~ú‡éÁ?`vn–x<°$‡¥yÉ8J‹(ñzO© -¬"6³ÅA8|ç¯÷c¼yí)ƺTž¡ø}ØKj0ªñÄB²r:2™8þûcT×Wò_É òuØÝA*›¥°´à¸ó‘hŸoÐë&‰ñ…;oÇ ’Í&‘ÚÆ*†_ÚNqï(WÅô´×SwûM<øàctt0›]´·µÄG£ÄãQ’É8Š’ää“oY¶c0è4“ÅòÆ"ZÛë¯>¢ôÿÁîð¸ÁyB’®¢Î¾Ý;ö+×\„Ñm¡ÿH?%ÅÕø¦‡QÕS+Ó“… ß8Ã=láydÙ†ÅbÃa³“N¦Ø­ßO[k3fÙÂ׿~7;_Û….H.Ÿ§©©€ž#ärLFe#çýî-ÄcάÚÛMg©—ht¡Pãõ”rûí71ݘdÏŽöF7»_=È«¯nGÕøY­v2ù¼rË-·œIé¾qÏ7v_xeöh×½öæ|¨ }F%Òí£¦®c[ Ñ+ùLžjµþ]{¸â×™ ˜‰EI¥â\zéF6ðäU…¾±ŽîïbÚ7K8ãH—Ÿýöó`4Y°Ym¸N*«Ëh[½‚Êâ…ã¾ñÑ…ÊŸI¶¢Ÿwþdƒ¢ñ…À¬°ÀÅÄÏÅŠQ”Ž~:7OAE!êq›—ƒ¼š_´=œ’ 4´6ìõM.Ò®X~£×/'¼~(F ©¹¹×î×Þ`eëy¬^ÛÊòåº Ðé H¢ž–šFš«HgÒ˜ŒAZØ :»ìaÎdÚ?ÇÐè0/½øz£Œ^o$™XˆT-+î娻 ª "du:—‹x,TT–дïàqôù<òÈ4SèO™ÅåÅH’¸hK9E€šŠÒÛÞÔ[†í‘tÅÂ3çdŒH™ í¤c‚´E‡×éàÈh7ÃcS N09>O6“gjz ‹YÆSX@]cmm­ ‰ø§} €³ÐÚö\¸~ "š–§wtˆŽ½G™Ÿf(¼P}ÁlãÐå`ïB—ÏZ^KßL˜L&ŽAo¦±µ–ÜôùSQ¯äð‡N$Mz ¹¼ˆ"»õ©3 ð­o}käé'_`nßQŒE-dL"‘£XlÄ/­>ÅР×#Iz$QE“uD7•‘|êm|¾Î²ŠÂÐØ$|þuÐTŒ=n§ƒÒ2/ËÛ–Q_S‹€†$‰‚DSuÍ5dÒI¾úµ{ÉfsLN ð·ûOØlN6;‡Çx˜¡ñ Œ²Oa =-uœ¸€¸ÉˆtÍ:?:á«I¶¡3èi­ixðŒlþèe·<þÈoQðlã‡Wb+rÐÛ9@Ù…Uä '†d3QQÞ„¢åij¬"פw|ÊŠfì·l@“,è »/†2$0=ÏÎ/³óÕW°Ù=FÌ&ž¢šjXÙ¶«laÓ¦K˜÷ŠDˆ'bƒ³øå'#™óп?JeM9ÑÍ—âµé1»‹ÑD=±Ø‰-Òj±£¡©7ÝtÓ¢ã4a©KRwÝõWÛžúÕo?ê)©Âs];#¿z‚BÄž¨BZf3è“Y2=~²W×øÙ[H"8n»ð]C½"`|mûvQ\s¬¨"ôâËÈVˆ"ƒŒÙhÆnµà°pÙhl©Eo4p´£—±¡qÁÑX”T2F6›<~´¦“ è 2F£ A”OøÚ¶b-Õ¬P~ñÀ†÷>øÃ-“ã¾èÎ/ÛôÏ Ô_½O¿NÓËvb—Õ  ð4#v§ËI¢F#Ž-矒@E¯¡\QGÅÌ<¾ñ£xJ‘ôF õ5å…¤4P¢B#úÆ8°× š†Ng¡ªÂL]ã…ÔÕW16é£ïÈ33s„#ɱh¼z">‘Цt¢˜XŠÓ»ÞºþÆz†‡Æ“ccýBq¦…–«×ѳ}ms­h‚†H3·£‹ª5¸n8¬îìî[Ø?r¡GD÷¾ €–Hr|r  Š‘éAŒf‘ÔU ׎¾,Ò`˜Ãúè8ÜÇÌä š&`µ[p– ×I;—â"ýÝßýÝ’$ÛÛÛsý£ýÉ£‡»¯ÔGó(ÕQf´1Þ9†»ÜMÖ¬#/ë˜{«—ÓI¼ÆqF§þ º=3H}³XÓ9 ÝFŽ dSè²`¨*QM#³§“l:†ÉjÇóñ ä "š’(`JäpU,CWéEiwâqcăQºŒ²g×Û,»¨=[ÓP•÷Ô•Š¯KðcY[Ó§6­_?u:¯%×€“ÑÚ¼A ÌÏÒ~ÓµdÌFÕ¨#\±Pv6<׋&€ûö‹Pßc¸f¤M34ò"©Dˆolýêç¿ö¥¯=¼mÛ6kÏw¡YU îùò=O°D&õž×äV-o}f{u¶s qmsG&qÚe¨¨ÀÚVÎÐÀÞ¬FÆ$œ±­P±®©§R©Ã¼g’¾£½„æ'ÀT%ý:‰pd’5—m"XhBT5tÛ{ØßÝÍÊUkHl¬F•ç )³H±×K_ßûötÜ<¼eË–8°ýLœÞsÒ®¿|ÃùV[“Ss$÷ù¨)v2:6Å̼ˆs¯œÕŠ£°QUß«©ãÈé¢+¨¿õJš›V£ÓÑ4P_'S{qT\]‚.§’~ú0ýÝ=´oØH|S5ªôî#Ö»¶Yvrä`¯÷l¹¼§wÞyg¨ª¼B‹†§ ŒNÐ58IÓ5«©¬,crh},NýúF2¦%¯ž H7´±á’«°X H¥#(JšÊê…t:ý»ÆGûh_³–è/špæé*7âpz™çÎÏ|ñþ³ápVËöºKVý0¯*È&'¾É²³d¯[ŽõæuÌ—[ñ×9PE(‹QðæÄÙ4yª¨ZëeÝ…›ÐëL f U\{§ì¡vÅ*"WœŠ¿ò’@ii J.ÍáΣ_?›þÏJ€¾÷½/y=%dÔ6»—þ®>ŒéÅËGÂ#34å{IQ‘òP¼ª†‰ÑÌãKWfÏ„T™Œ½¼Žd*„AoÆ^`G5 »æ±¾8ŒsþÝ7-kX ðë7éêÞÀŠuËŸ;›>ß×UÙŸ>òÐÆ[n¾ñ‡g1¾éqLáÛQÑd Ï¡"5vŠËÊß¾CúýM…P‘LS©g¡4.J¹…öcõ."á(G~þ ¯;)4à Ɉy[ÔHU¿Ììöœ÷£iylö"®¼øâ›Î¦Ï÷}Wø_þíŸÿÏ•/Ü& éýÒ Çz#Y<{|¸?І&d^Ř>Svp*ôŠD(Òé(±8ŽPšŒIÄqÍZV_p!áXœ}Ï=ÃØ3/">{ùȆ„FKC+Ë›VPYV®‹þü<öä£[Ѳ"?9>JÑÑ VßðÍf‡Žöaèò³üÒvfGF‘vû“g'‚uÏ0ÝÝŽgxáþ~ìc … Q…l4NÛúK9ïò ¸.fæü>¼Ÿ=û_ žâóÏ¢“ ¬Ýؾíl}9'¶ÜrE½N¯#Ð?E²ÈNNËÓq¤‡’/÷î#JÓÚÜÀpß áÎ0žƒ³”õÏ#)‹&}6wÏöî;eÁ‹…§é e)˜ŽudÑ$•ݯz5«?tM›¯Åî,%œ¥°¨Œ\póÙúñž¹À™pãGn ¿úÚëŽ .»†ù•VÂOí'87¦ª¨¢†ëŠËÐÍ&QÊl ˜òy\ÁYU@gÕaÖTf GFl²³~bÁ)2™8.w²Ûƒ{y9®"A¯¢·gèîèE–eZV­áÐ[o" ÉTŠT*ÂõûÈë?ýÏ7­ïš ž DIûÁ@ïØ7»: •:¦‹0FõDçý$!”ñiä²rTŽˆæD‘lT!“Pˆ¹,„d#Š$!” ZÌD»R¶æ" ¢Ll~ ˪vRáŒ@ÉxÙ"QZYL‰ñùÞ"7ヽ(JŠË.»$òóŸ=Òô~|ø“F,üêàþ£ñÝ{Þ–Ï[¿ŠT[ò¡Y†F|ÌOö!J: ª[—U¡ž!\S ‘×ßB¯7aºtº™ùD!žBm¯^š¼ª¡Lì9„ËíepøðYÄ‹§µñ§ ð>ü¡-‰={˜Ï»x=Áó½È {g€î‚Ó#èu2öšF¤eUhúÓ–ž@Œðž·H&ôµo$RWŒÿ¹—% “£SMš×&-؉I…Üð©©Iòy…l&Ùjgrª_ä}þÙ„Í×Þ˜ØèˆÜzÅÂÍnä@†t‘¢¡ó]Sø¦gH§âèŒ2:³ƒÝ…£®”ÂPœ\F£«§ƒóÛ×á››Æ79–[7ÿl¬oòúCG­éTÁ„$éIĘ-.­mäKÄw¼ANIñÃýß²¥ Ÿg¹þop)h¿î×–«.ý`¦wçA}S®Œ?Jj&ÈüMkÈ×»(ÖZqL%HeÒç#œ£Ñí¢È½š|>…ßglt†ÑÉýWóïüà6€»·~¯ô•'žž_8Ø•MlWl$/‰ ’N 3èѢѥÎëψsÞßM„/ßp—­©±Níßu£UF”ô$žÜ”×Ð0ÄÒÌèšF»š@(€$É´·¶Ñì0½áøÐüÑßþµï¢KWÿÔh´;.?1´pœT:JUE•ö‰Ï}îì‹áÏ-×Ü}MæÅWž‘.½rí¾C]8¬2½žì¯#ª0ßP„ª(¤’1rù833c(éìÙQ.›ë¢sètb‰Äñ¿ë<ô?þ¬ÓYˆÅRˆd6ï/36Ž^odÍm ß?»ïàÑÿzxõ·}ì¦þá~rŠ‚ÛíÀîK⚌ úh.©æ_µ,ƒ™]wqEÇìtóÒIDATn*çæqç²H’žT2ÆýßÚzÊŸœd“I ½l_x j¤§&ñz+ùÑþíÎsáù¿&À×ÿá;O:.†FŽ¢¢.7=2AVIQ%.t®©¢‘sJ§i‚H&£ãhß/OnÏn5kŠ’F./FÒ4„É©d˜ö¶¦ÅÇFg‰ÿUJ½ž¼ÕZÀÀÐ0:EÄ^í¡´´žêc—+DTꪙȦQ$‰¼("›‚ÄèäTùÉm¹ Ý!“ÙŽÃ"PO ŒM`³ò…»î¨?W~ÿ´8£J²ÝQIEND®B`‚nestopia-1.51.1/icons/96/000077500000000000000000000000001411157722000147725ustar00rootroot00000000000000nestopia-1.51.1/icons/96/nestopia.png000066400000000000000000000374171411157722000173360ustar00rootroot00000000000000‰PNG  IHDR``â˜w8sBIT|dˆ pHYsÔÔ…ÁtEXtSoftwarewww.inkscape.org›î< IDATxœÔ½w˜×yæû«ªîêœÃôä€d`ˆÀ &1˜"EI–)a­}µò•®tWÚu’×»–×–mÙ«`ËY×^Ù°IV¦$ŠiR$y€09õtOOç«»jÿh`ƒLÜûø}žy€îSuÂ÷žô…sZÐ4·öªºëLhê·uFisïÚîÝ·'ó–úïÂ[EÀý¥ç>}öåÓ£±E¡®ÔPU•@ GßõЗ¿ð'òá·¤àoÐ4íŽÿ}õŸˆoàɆÛÙª¹­šÓæÓ6 <¬YL6Íb²i=Ý›µÿüë¿uÿ[Qö¿·?ñ­ õg‡^=}jè¸X­ð{ûioÝ„Ùi§Å»€d"ÈüÄüwÞHžöÙÏ>öÌ3¿”}êégÊŸýâçïy+êýÿtw:ÿûû/oýéó¯m®ÕÊÈz3&«‘žÕmL½hdó‹Tª9£iç­æùñßþ­o<{àÏ$“aDQbbdæµÅÉàñás“ÛgfçD§Ã¡½íñÝ¿ÿÅ?ýŸ¿;u>°ÿ`çÈÌħÖõ|lï¾=êíäq»¸ã<÷ì Gãñ9 ²•­›wÓÖ±ƒP÷"¢šÂ¿ 'fvQ©æH¤S·4ú~ﳟýø³ž}F©5ؼé>òÅ*³3'ù—ÑåJˆÆ4!‘Ê|Úª·Tþð3¿ÿÙå÷±O~ò§ÃÇGÞîò8ê6®úɹ¡©ÇÏ Ÿ×‹9¶ nù¿ ¥}ßøåÈÆ-àŽð…/~á©§†ôz¾UÛhs¯%ã.Q´Šh¸ûܘ¦ÀùBŽûúöîÛ¿^~ö4ýô[/üy2¹@Oß6º×ì¢&UѨ3;}»=À@ÿzfƒ³$Óüø‡/ýñøØÇþÓ÷¿óí?RÈ'Ð4UèUË“µZ »#@{[/'N¼.”Ëå°$éå½ûöÔï¤l®‡;º|ÿÛ?ù^&Á×ÖOûÎÕDj,¶Ðð…r_ŸÁ [‘r1Ç|0ø¾åW©Wgçg„ŽÖÍxì6 Öó}EïÞHoÿV:;ú±vÒÝÑ@:›ì?h¾^~Ç=UWjìÜþ»v>D£¡ i 6¬Y‡áýÛèè\Í™³Ç…üèG“wR.7Â#àÀþƒ¶¹`H¨ku2N…¬«±”^´›HÇf(•Ó˜ŒvªµCgGþèFy*år\¯7§…Œ«†&‚(±¼wÏ=ýˆš€Ùh@u(Šà¸NýôÙ\^ؼi •û{Ѷ·#,¸œ]a-é‹é™D–l.‚ ˆèõFzzþñFr9°ÿ ðܳχ~väD[:5¦iȲ…dº‚ËÛN]©rfø„05;ý·‹ Ñwýù>÷ŽkåsSFF‚_.jzI'Þ5&Mì“tßúþ5½Ùаxmq‡Í|Áeµ½ E¯ÏwMáÌÍΑsx0šìK̇gxyèø+{÷íY­÷\NÇ«:aK½Ú@©W¨ä X›A'éP t’·ÛuÝvÌOίRµµJ }E¡lÖ¯H/—«èuFdÙ‚Óåf]Gßgn$—¡Ç¿öÜ /´U*9ìöwÝ·‹Ì:7¢*ÐvÌÄ\¨ƒÙàQ~úÜ¡'l;è¸Öè¼):ŸCzæÉ­–¥ï’¹´0ŸŒëbñTk(žk ½½Z®€ Ãùì8©jÿcë(Ú›t¤kn7Ó3£èt@@šfF£Æá½ºîÀ–ƒ½ûö,^Y~5_|Tm(´ZXŒ  øÇSL$ÂX,Ž~šR¦wMOþÊ÷ì?(ONÍét:#ŠRFŸ*‚{yéñMä8 ¡Ô+Ô5îèÞÒÞ}{Ê7’Ëâbê¾KÂÐée *¦æü(ÜÕNŸIO4æ _Èø€7FÀý=:M/>€ÇîÂcwAïE!UKLž›bzú ÑÅ ¬vNÓÆ¥çÓ‡Ãø\N¦¦5 …8f““R9½”>šæ‡Ï=?ºwßž«äÐx°ß`°RSªH’̪¾6b@-ZF©—Igæ—ž/$®·TµÝæ§XJ!ê——>}McîÈòù’¤cÕæoÜH.ùRiÅp+³˜rJöLKÁ zªÖ@ÖIs×Ê熋°¦i÷ZìÖ›ÕƒÁÌ“ïz‹Åh€†rY#©–‰$²øÛz½lÂnoÁh°!ІÂáÃg¿ùë¿ñãû.Í ö4ÎŒÏêL&'©dš––^2ÛSUdýÊŽ Ft—¿ {÷í©ü~- ¡×)z–yrLg˜c›í £,Ïެ͙LÎpéÿ‚ R®dþÞk$ÿñuJ‡CäíÆ/LP­æY?¸¡¾wßåZùÜpdR±÷´X7« ›Ö®cû]wqèÕCcåZèñÛ¸04– ‰†&ؾmíï$›NŸ‹$Éf‹œ<>óøÐÉÙÚ?}åۚɬ×Ðææ'±[[°;Zhßê'jhqC‹@ËZææO ëÍÔ”ÉDœéóÃ_€=»²~mÂÐYÕf4;¨% DU#~n‡­õ²‚Ò¨wܬ½ÙlA€&a:ŒÚ¨“É„Ð4•žžLñ‘…iìŽVî»wËǯ—Ï (òw·zœ<û£sþì8&ƒ·ÏMko]Ý­ô:uËî}Ï5 â! Ù`Ád¶a³Úñ¸œ´uµÒ¿¶—õ[×!%נਚ%t²H<™Álö ó⫯ñè÷_U¦ÃbgÛ€Ðh|>†ÕâÅbsárº0ꛣ^§¨„bYêõ ¥^E$4­ÁØÔ¤ð?þäþ¥¿½÷ƒ{÷íYRÅ·mÞòÇÿ,}Ïôä!"!':ÙHog7ömëY|ùè%%€X0¼êFrÙÿ•ýíårqé³,[X5ØGl&B*nD²é‰'X­^}t÷ õ‰ëp`ÿAY’DëëG†–¨KPµ•JŽJ%G:&„ÓgŒ?µ±eýªå³_?ÌúÍýÄv·b,Ô ÆÃlܺ AO&ẩQ¹ÿm‚pUÙš¦122EwïF|mÀ\‚‚C¢Ð"u=˜ŸÙÌê8súƒ›î¦su'éH’L&ÏK?<ù#Æ3øÆ×ŸÕ~{ÚÛå?¢Ó07ê5¬ƒ÷lGÐD¹RÝJ©\XQ~*žºáÂ÷Ío}4›]–‰¿½Ä?Ît Ùd“Žj!ËÀªÕÚoýîýÓÛ"X«‚°8CU7xlIlT*9fBQ”z“ÝFn³¡Ñ@ÕT$“žÄV?ñ ÌÏÏñâK¯²å®xíî9-Æ#¤3Y6>±ƒ„[µP£lêЖÍõå|Aéîïà©Ç^ú^UÄRq&fæ…ÅÙ¨;2›|2ž.!뾇ä&íAÙµiB¶<›ƒTBZjg"–¹îæäãŸüO_yíð«¦5ŸÕ댬Z×E\‹ÇLÿêµS¨Õʬ¿{ÃÔͤv]ÊÅìÃzYG"•Âdt`­drá›å‡$è1›Üt>°š”¹™}ÁmÄîmE))¨"È[[`až¡S üøÇ/`4q9\ ¬íãé§Çi¶£T‹H¡B·¼ ä—øLzJk}dÜ"ޱ,g“X¬¶í\QQ”x¼ØÑüîsÿóïikë&¿±¹{”"‹ß?Cï†N, Rúv‘xt€\¡(|âS¿ýÂÎõƒŸÎïÝ·Gø½?øo÷=ÿýW>X)/ïÿmîÉ-M³Kd³mÐOîG“H:=]ß µéL%Ÿ)«Ëe$‰»¸›cGŽ“L\s;»ÜxYB¯šh˜Ü˜Š%ìËÄ3 ì/õµžfý2»FµJ±&—­‹Í!IÍ5Ãdµb¶Ú9zôݱAÒšj tn GÎDÍPfîµóTkEvoy€6—÷fíÄn3N¦1Ʋ} DQãô«ÇØyßN”Z‹ÅCwWzã/¿ýä+òNà[ßüaCg‘ë³ã³†ÈâôŠ|]N7ªØœF/m:RÙ<ÙĪö¾½Y½n0jëJÊ¥,£{—•»=÷sê'GYX˜®mvщuÊÅ åWÏÓÚÙA¥.á èˆoñsi¦U%ŸÇEp.†$êh4š¦%«uy_ïu¹H%¢FgŸ%àD«ÕI;j˜Ž‰F' ´®æ¾‡¶“KÇ1Ûèt×7>Zlfâgãùž›–Ž.J‘Þm}Ô^¯›OR-éíYÅ'>ñ!ª•é|†PÅÑÓøÎ׿N¹PÂWnP55G¯-«¡™õ”Ëyf/ŒŸý‹¿ù›ûþß|äÜ"àÀþƒ=UMÕ-.4WzƒlÀm1a2ub`E3±yÆνN½^mŠF¶ ªuêõ óóãøÜ}ÔjTꀌÔÐ0¿z;Ûhõ´ ŠÍ©fanI6’ÚàE‘—uçl–‘ÙIÖ¬ÞÄã6M·Óǽ;}°øN—}t‰°kU6R( Ös%.™[MF#‚ÖÔü¼–*‚u‡±ÝãIÚ»×3=qœµkvòè»îã[ž'ùüÝWŽ¥)P£Õ«6’Éç(ò„23LM@ƒlÅh²aµÚp;›½Xuäò%ÔŒ2™£\Jãòv²vãñF«ÅK¥šãJ¨jj5Oµš§‡Kn;AÙ°á>_ £Ót襭^3'çY¿f-&ˆª6–FÌ%Èf½$¾.öôŠR,–¸X€Íiá’¯{|¸F6>Ïún+@ÚÜOí'³Mâ”:gÇFXXl*lB]#Wˆâ.u±0–ƒ¾fq‡_UøÅwVø‘,]´ãˆZW Ôk¬ØH(¦¯¿ (±z£—c'$@cpó>ôýš¦Q,f™ ‡ OGˆ.ÄI¦²äòYRé‹‘êçjx\Ýdr dÒ&ÚZÛ(—Mä Y¿ü"f³›Å‹ +lB7B‹o ~§Ëzíöçg8uz˜\v‘SCyFÆÇp¹<Z|ô¬éàÝ»Q*’ÝÄÞ}{®K@­ZÞ-élsþ—e Ö¶eNOP«‘äæž[5H8Öm¦tê&¦Ç˜ß¡XH &›¡i/¥†ÌKÅUË iV“E)#Iz‚S ±ž`Ug v‡‹€¯‡Ë’•ž¦Å5©míkx÷{n©ƒX­N¶¬q²å Ëj2›`ja‘Å`”‘³3ds |à—àîµÍž®¨"ÿ•c“Sˆ²QÔ/é$7‚ÅäÆîP¬ÔÙæ+²Þ—aû3ðÕomàÕ#Q*Õ•jŽt:Äô4œ:e#Œ±ãÁm<Öêåy]EÀ|,ük¥b³’V›R®Á÷_4áõjÌÎÂh°éu [(S„U­Ø¦ä³ …eßúôô6«Y6c1è©« ""ŠÃó6,ú8’$ÓhÔ8qòΞ=‰ÑlÇãnÁnwÓߦ§\”Y(ÒPNžF¯7ñ¶‡¶ãuÞ\ûõ8¼x^X·‘© ÿ ¯¯`ÞÂÝ4Û¦jïzÜÿ”Lhâ­‡é›Lt²ˆ³ßÇÈDõ>8ö19wîšVªyfgCtfVᶘV˜®" ZV¶TÓ9*•¦ƒÂn÷râ•“ iJ¥4Nw+»DËT…°Å8ÛWávz(WJÄ¢Mu½Z- ÔJ¤2A}ƒ™ôΜP°Ù5&FUÚÖ°Ïø%‘޶Vª5…r¥F.ŸEÒl=}ë º,ÿë;*‰D½ÞÈÌh˜gó/ÐÖÓÂêö6lvÏM…¦×ëht¢Æ—çùHH&´(‘ɇ1H–[êý¢N‡ è5°øšzÊäÙ±+Ì—Ãb1’+UØÖÛó•Ë¿¿ŠµŒ/2³€ªÖÑI2B]"™˜Yšõzý›ûHNµÎ%óœ,[è ¸ðüZ‹ÅÅý<€^”xå¥Ã¤“‹œì¢á¬±¡³Ìè„ÌùSÓ‹)îÞu?Ø÷ž¥:TÊE¾vðyê•·5((n†ÏšNüc'~†pRÄ [0˜lXÌVìv;^·ƒ–V}kºéëèºLɇ݊$ ÔÊËžÁb¤ Y‘5Ýœ¿pKÂ(’ìÚ5H˹ilO¶3–p062vMËÀ%xZ<  øÞç®KÀý-U5Äͨ6‹ÙC©š]¾ ôöo ±­¹`ê —­ðšF2SæÜèh“<½î®Vº:8zø8Š¢CM žŸaá Dâ ’‰9 ²…þ-+ýF“…ÝÊÐTšþ^¾û½çÈf¢˜Í.îÙ½‹ÃÆbh‘d2C¶'“MÎ0R¯¢Ó0è-LVLf V³—ÃJEÑãv¨U–cns ƒ&‚Q¤P¼nŒðU(—Ó¤ûÚØÈòõ³±xƒÞ/Š:ÚÖtSo°‚é4êʶ”V%›má²X<¤³!AÄdtÐÓÕùñuK±¢¶¬Î׫eÎL¼¾õ–N…øÇ¿ý &‹“\v¿¿…ñ #cÇWVNÒÑÑzµFÛÛÙK4Wä»?z•³Ããx¼üâÞ§Ù¼~¥¹@©Uˆ¥’LX˜[Œ“ÎæÈ²ÄcAµ ¡“d¶n¾Ù°l°ki72œw2>tb©Þ·MÓŸâhåÅ >.œ<Ž¢\?ŠÅh´ÑævMç”+ƒÚV0µ0ûñJ£N±˜C'ÉX~Z;|Xü²ý(²°"ðR¸l˦—dìöéô<’¤G§3P¯WI§B€FGk€ÉÙ«ýÕj¯þã·éîî µ¿•¾Þ.:ÜͶ{ÃFž^Àëöò¾}ï¤Ã¸ê}½l¤=ÐN{ v. ¨TÈ0>bòÂ, ¡(Ó³#aúºz–Þ=£y Ÿ› }ãÁÐÉD±“vÊÕ‹Ñ™>k±Ø°ˆ:\&9teÚ ò…‡ÔJj5ÓÞŽÏ£'óp×åö2EÃh²Cúû¶Ð³e=õT4r¾ˆlГÍ\}îAUU sÌÌ^@zUl´`6Ù°Y­¸]ZÚýÜÿÄnÌÆ+¾×‡ Xl.¶®w±uý&êJ•ÿöéÏ“N†Ð:º)ÔôTë"Ù‘g/œZr꿨j±‰¡[zÖa³“-”èôºŸ½2mÙ²â*›.ÈšRBXe¿òù•Ð.ûW©£ª $QGg_cÇOšC%QBÓ´kº6·îfë£;HÍG‰ÎÅH$’dr9¢±‚Áqê§jÈz²ÑŠÙlÅaµáv;ñwøèèkgU[;6ËëY(d©+UjJ‰áÑ“|ç‡;IÆãŒLœ[²æ¾•ðø}%.2 (*ÕZln§«F2I©”¾ñ»€ÝácãêµKŸëu…r­ŠÕdÁïòãßá_òéÔ”*Ó‘³ãóD‚‹$“i²ù<…B–d"ÌèxáhÓQÞœÊÌØ¬Vr…òŠ-âÿ)áCÓØÙ݆R¬×öîÛs•P– Í|BH䘦·{-©µWZÔWBÐXr‚ õ•jž@Ûün;‘Ùà-5Òép »è¾pŽo|íûTkudYÆl0àr; ôwñðÝwá°:õÖv­bm×Êmk:—f2$4fq!N*Ý´årâñÐUuEÝ’¡ñ­†ÉlÃg2«ç¯ÙŸ—˜›˜·(@£®èh!vu¸ÎUhØLtç‹„ªåJ–q5³¡YŠ…›ŽœÎåPö©É ‰Dd…6:áÌ1Î;ǧ~û#褕>ßR)O$—Æb0±cã ;6.GG¨j`4Âð… ^øÁó”KÍ­µÛÓÉCÞK.›'KÍfÉò”JªÕâ'Æfµ³Ï°Z\+}‰€T4g7wzEÃgÏÑ¿ÎOÞ%]ë Ùùƒ,‡sTÎO i* A¡V)ÞpO|9¼-Ë£ìñŸ{˜pp‘™à Å|š†ÚÜ—kšJ&“ _®à².ðÒ¡×øÑ³/Ш7¯@0™m¼VmìçÉGDuô´vÒÑàÐO-ÐÖÒÊã=tY-T¥ÄL4ÎüB”ðè<¡p”ÙÙs\/ðàÀãr’)ÕØØãÿÚµÒ—¨ÕB—ÛŽÁh%™b~ö$¾÷n¥b¹*Øx ¶Ã Œž"›‹`±ùÈæ¢tv­e|üè-MAÓ㳜»pŽukÖ`’ü?ûU‰ENN™§ªÔQµýëzpYWnj…B>¾¤@5(sŒŒŸ¥œ/òÌÏ? ÀLxžr©iבֶ¦Ò7õÒ ôž¼€£X¦¦Óaé ðÀž§ÑíÜÍ+£gYø«)jµ‚ °ªo f£L6ßÜ”ËEªÕÂ-(oÎUµNo8v­'–pºÌÊÈá ½Í Ÿ‹Îo#+€IDATÐw®›Ê®–«^ëâÆ¢¦”ð¶¯Å°{3D³ägçñù{– r7Âøä&¿t“ÉŽÕjÇåpÒðÑ=ÐÉÓÏ<ŠÇá¹fè"ÀcoU­søÐ …,J­‚ª6ÐéÈòòH™™¡ZkÄÈz3þN?S¯¼Ä¶—s)gS­Æ†© £û¿CàW™l$…¢T0¼ã}³±§yÍB£¡ŠGƓ̟›%IÊæH'CWÙ‚dÙL{ñrEÛ»oÏ5ª–øú7ÿI>°ÿ`çññsßû×Ll-Òd3ÈU?5òÑ áçÏ ]@§3Ò»ùz}hbi¿ì,´ûüT«²™…k• €Åê¡£­ƒjU!_È“ÏgIÄÃŒŽ+H¯é1¬MVlVn—“öŽëzXÕÕƒ,'{„'{„X&Éüb„l2G7þ¶¥rBÓá¥Ñh0ZYÝ×FàŸ¾ÃµhíEHS$f"KïX¬.Z;i4Ìþäy¼Óa¼ø\lzhÎ@Ÿù̘ Ž®ÈÏh²á³YIV+×5³®PÄöîÛ3¿¶úÁkêHzAb—ÍLâáNÌÙ:©WgÈ2ôõÒ±ª•ä` óºfsZbE˜Id³Ú0LÄ¿ü¶‡–5ùödšT(JñCïÇìô£(WËØf±/± óW%^‹€KðùÜê̬MzÛ½÷S^½ìø(9t˜ŸZC»¼U„Øï¥ýeòn?'çÝ¿ð$ïÿŧE™lŠÉp˜Èô"ÙtŽÝìXñ®ßéÿÕÇ=[·/}WSªL‡CLΞ‹LgÈåsäriâñ £ã ‡KȲ³Å†ÝæÀçqÑÞÓFK«Ÿl.G&·¼õ¶ÛlÈF7Y³éº$ÈvÙü²ÏÀãt0õÊ‹+„ îB‘“¯¾Žý¾ÝŠ…«Ò]N±B‰k.Àpº:Ο:=´¹Òç&ë\¹ªo|´8´ÞKO¬È‰Cøú¿|ƒC/Ÿ¢ÕïÃá²Ð;ÐÎÃíÄbq\wnoF‹¤3 ìV;k{V±¶gå¾?žI0:1ÍüD˜X4N:—£Xȱžavö<'N‰Kž¶Ë7—™`»çøìUeÏûÜT% ¥Bs‚ˆ¿Í‹Œ^·½ŽH’ùDŠj¥xUš¿ÕK½¡Òãïü—ë½Múû:ÿ³l´¼` «¨zôe'AkZA/¤^ Î6;²l¦\Î_\@Q$RgNòrãBÓ¿ •±[ ´uX½®‡ÎÖv$I 4 e³$"iÐ@2‰xý^Ìúæ©xŸÓ‹o‡w…–\UªŒÏÍ2yn’ù‹£%•ŠP­^ê™ÂRtGûûßÉØW¾Éšùå^q;QÞó(†§—Ž+ɲ™Ž¾V®Ž–¸„º^GxzÚ[o½ÎHÛ@I¥0q½÷¯IÀ¯ÿ—ßxñïþúë,„‚¸[WË£Àw<Âb4îÉÕ¨× %‡q)CUx]V±Ç›k‰å…iŽŸ<Šª5KȲƒÑ†ÅbÅi³áõ¹éìneÓæµ¸˺‚R«PÌe1Z¬¤ã1<þ¢(aÐØÔ¿†Mýk–žÿüçÿžÑ±“?iœ:E6›¡smý½Y" ciqâë^ …çŽ-è F+m~/š¨Àùk‡úú:\­mL6\.éDªq£;ˆ®·iûÚê¡_5 †Ç¨/šMް}ÔG|ýµF×:DA‡A¶ j Ü+²±gMV9?>Šª50ôô®¥¥ÝC9_!•ÊËd †æ8vìßù–£ùâNÈé ­£…¾õ½ ˜,øZ¯>GweŽÁ°²yÙÌ"§N/24t£ÉŽÉlÃl4a³šq¹ÏbsÚ™—ž7™¬Ø.lþvNαõÌøŠüÆ;[YõÀ<ô¥«êb±ØÈW«XŒú^Px]~áOú³±lfhè„Я60<±†ªQDhsÐPëÄ.D®C@Õ¤CÒééé]ÃÜܚLjÏÛ* äÌËEq:ÛÙøÐ]¤6x¹ä ”©2†…"ÅhŽx2G.›!<Êé3*úŸ˜0^-v;>SoX»º¿Û·¢[vl@k¨¤²Y …<åržZ­„ª5(•š72šdÒ‹üà»?¡oCëy˜áþN”‰¦ƒIìl¡gç}dÓ rù«¯§pÚ$ eZÖ£·EÀÞ}{rU¥²*“ÎMާ§^ÇûÈâ]&Z|íƒãì8í%¶õjw¢*Í cuñd’¢[ý‰£)^Ÿ£%ÐOïÓ;Hù›s²ÔÐhH9ˆñšÀk¼˜€ž`…™Cæf†«‡ºI"]/3{üu~ £ÉŽÙâÄåpâ÷ºñ·{Yµ¶›|ôƒH:=õFÙÅ#3„gH&SdóyJÅfÔÛµ´ÚjµÀKÿö¯²`±:qØœ8ìV<>=’ S*ÆÑcg¯iû ´ù©Öê¬kïùÜU‰·BÀ¯üê¯Ì„ãÑ_øò_%¾9=~‚Z½N÷Ãk°>:Hú;YÎ9Ëzßݤ;®v•Öì Úo§u¦’Í€ iLŸ#éôô¾s'9¿qÅó7B¬Óˆ÷éÍT¿Q ²0N¡˜@Þ¹I0¦“èªü½ë¨ÔjäjU2ÁÓs1N›Áh5c2è°˜$ì.}mÜ»k v› MÓHdâŒO N‰Fš;ªB!Oµœ¿¸°jÔjEj©"éÔeG´þM@§“Eé*§Ž,›éØØG<_Âb4­t‚_[º7ôÃùè÷¿yðÛïT” ½ý[1?³ßH’c?=„ÃÕBÿãw‘\›KgJGÆ]§íDŒGN1xÏâÛ¯öíÞ ,© #ûŸ§XHÑ:x/¬n§öÊ)JÙ8Îw>~ÕóRQAÊTJuÄLA'‚ "ˆ`2Iõ`4JøÚ=ô®î¢Ûߎ^§§R)1žgjt–p0B*!ŸÏS.å©Ö 7=´èñtñÞ¿`4¡}ó/ÿâ†ûö[º3îïÿ毟Ï-~öòK–¹é³Ü}*@ô®;‹;yýÕ#Ä^ÅôŽÔŒËç¤l9ãHë¦N‚31Ú;»Hn½=áÝFwmãèË?#yá4¾7‚^O£¡ (*š~e[= ‹áô4‰ðD±yrÃÆH÷w`˜JQKT8{z†×_;h˜MJ,ǰ{`éÕ­ÂPðÇ0Le±G تu“—×A~6K&¢Q«¢(:ZËÊ»ŠÄjƒüácXŒ.R™ vw=On£äXI”¡ª¢S*Ô*F½«­¶´`ÙØJ—¿ŸÝÅh¤\ªZH0rv–—^ú á()ICAÃäµÓ·º‹µ«ûÈV«L£om÷_>ü¶ûv£6¾¡k+wn{ÿ+‡ë“SÇ&iõÞKÁ^¡üX?›e™É‘ž >jÍu@_w§‡Ž±ît”ò½­o¤8jF@ÈÂg')—3¬‘gͪ.èYCŸ¡j¬#hP3ˆ(=fÌšŸ®“IBÓ D"êjŸöÄöíj¥¸=žŠ½o.—$˜L·”ç“zQ/ië;úþúfm|CìÝ·§ñòëG&§g.ôÇbzÒqÊ+Îdeµµ«º‰È+ua{;úó&¡&%@] ¾Î‹ÐÈ aÝ‚—ÚpŒé™f§Î/yÌ.¡ZÍ;yŸñA^ R®Š %IF–Íl½{±U+Gˆÿ𧇆©• ìØ¶‹ÊæbÎìe僢WW|.¥2LNœh^¨ª\b±0úÚí»øÒmŠ÷Òú¡‡ÙõÀÛiié¿ÊG\©æÉ<…X®#˜ud‹Q²ùEÖoØJ|û²cIT5¬/ÌðúáרWËÜó¶‡ÉÞ×MÎY¹yEv®Åéj O ö¼õˆ±kà °wßž‘U½ªªÖ‰.Äh=³zU½†Ïùöϰƚ‹¿¨ X 2m-(µ †Â­Ç_^ª2÷¶øàýìØñ6ëJí7› #Ž„`h’xl ··ឥt¹Ú@ûÁ§OÁ [Øõà;ˆìp¡èoå> (8V÷¯Au„f99têª`«7‚[^„/GxqÞóúáã»D*ª“h4…Ûb ·«‹é¹9âg'pEüš &³Žl¨ˆmk7ŠáÎÜ”©J.k=”s5Š…—œèµRtjIÔ³eë6òM“‰±T'÷ƒ&ÇN`·صû⛨Ò™ØV²3I Å8¥<ýV‹á3›7ÝV°ÑmI£»½û÷¼ÞV Å”kä§ÇŸ C‹“íÝ?ÐI(²ÀéÃg0Í$ˆ®r²fmÏÒâ|§Pש,léyÏÃlÞp7²ÜÔÈË• ªÚÀfó#wÙ€æ-‹ÙŸgzü6[€ ÷m%¼]wË=ÿrÜ®‹g”ƒ¡YŸ>ñòí¶á¶.ïÞ»oOæ«_ý×z$2£«Ö ج~##ÄÏ»¨?Õq` ]ŠŠ\Uˆ˜e4 ñÀ²õÒš©£¯ÖI·ÜÚuh7CÖUÅùÀ w;l?utéB@Ùj'ÑÙ\x¯ÌñúØŒF;7ôp»a'“@{«Ÿ¹Y=Åb’ÑÓ÷ÞnÝo»KÞ÷öÝ·X½ˆ‚„^o¢ÑP˜œ:g¦yYw])Ù ¨×°óØç3ÄN„Ñ)wîçS2®*âÚ5lÚ´Yß¼”Ïa±ÓÐ xf³œ9=Ü K¹kÊæ›Ÿ/»)V·b17=USÓSذçv²¹m>õ¿ù·½«´DjÙ`Áï PL;9^¹±ÂUj1“Zá9{¥WùÍ!(àëÝŠÛÛ¼7¢ªªèk f_› ÒÒ¾µNǛڸ €ÓÓÜY¥RQÎÌŽýæíäó¦&å‡Þñ¶¯5´:©|½«é¹ Gæq/Ü8یߌÓícäô8⌓ÕueéëêB’ô¤£Aj?ž%Áh°ãøˆ¯j¿#eÙòlKg44áêKYooŠ€u}¿¼}ë65“œcqúм¹°29T¿qÖmí.rÙ8ÆŸÝü®7‚š¡¹Ë‹ÃÞF.aì\3LÞjõÒê¶S´6ÃGíÖÂ+á‹ZP]`bªy ×ÛA›Ãó•ÛÉëM°wßžúÿÃóÃ?ªè.ÆâkšÊìììÅðéëª ä¶µ`w;s küÙˆnÕXÇÚ× ˆKÁ¶²ÕNû¼ð¾&p$…3ezCk±3m"}äCg/EÂm»gKâÿøØíÔõMï ÷îÛSý…÷¾ÓñÎw?™±XšÓP2Â5síÙ5C.«(z‘.Š¥©N¼Ùj¬@ÎcÀé·b³.k¿v³¹ºL´ :Ëôw~‚ÿpOÜŒ¡ª»f¿4GÆHû…:Sß~ž³çŽ.Eq›LN6o]ÿ;·[×ÛRĮĦÁMõR¾ø§V—õ}Só¾r%‡±fDÜ°Òø&h]¬àXÈ¡,ÔÚm³%" “¬Ö\”or"çV¡Ènƒj¬@6Ý tûºpš‹d/ZkKí6zÌN"3aÆÇNQ˜Ð^”é¬öb¬è/æ£b.ÉôMº‘ÓΟ:NµRÆlrQ.7}íí½¼ë‰Çß³ipÓmméî›7ñä;žø«‰àÌ{'F¦[ …<-ƒ4ô"‚& ©"¶\XRót×Dn7®VñÑYÒÙ2k3ù¶›ßU}3H ‘Ö9…©‰QÊOê(ôwb3‰Ôe ({Ltw®ÂU—‰F˜š9ÇBx!—ÁS’hÉ814Œè ƒj¥#°†Îö.ô²JxaA¸ûž»Ëð™ßûÃÛ­ëÿ«vîÞ>yv¦zìÄ+‚ô³itöÓÀóZÙ¨§Å 6Š ŸŸf³·µ°~Û6Î=ÌùP+ƒ’@pÐÏ›X#qÇœ'•œ]ú.ŸâK—ñ)‚ƒM-Ö\Òã»ðw?@`í&Ο&^`|r˜ £Ç‘õf &;Kó†`»Í…Ù(Sºkk±zØñ¶í}3òºc#à6 nR³¹Äü©“cïJ&’t–Í(]6LÕçÓárÐéq3;=MªPÇßÖ{ðW­Ì QÔ»YSUÉù¬h·±Bék*å£!f.œ ÞXö65ôªƒßI­µi²Pd}b‘‘sÇñ;¨Û±ïèa¿¯Õ߯ϧ†Õh¥ÃeÄ$Ú˜¦ s#+оCÖ4ʶ[Sœ ¥ú#aÆÎœ¸æåKµR=ôÔòîæ%#u‹Žô™IÆÇÎà«‹”Ö¸°WýÔV¹qtwÓç]‹usyK6)@naŠÉ™aDQÏ“?ÿÄÑßüÍÿòÿ½Y½%Ô•ÊsÇNŒ|8¶8M_ I¶C¿™ú\žÉ‰ÓšŒß`nü4²ì$æscµ}­dÆGÑIN"隀5\ m!‡IѰäkØSœ±Ö|ªÙˆ>‡{.K1˜gäÄ1DQÂè§[ª•e R^¡ÞâÇ£©”­2uYÀ×Ý-26~&sx½Ên–…4…È.Å‚;ëE¬”8{áù\”î®Õìyæ=ƒ›7ÝÚy¬ëà-û9[€ìý•ìŸ}Önw¶p×ÛŸ&´º‚-^cñgc„'†°Ù”K”z™À–{ÑV5#&„ºŠ>ZDñ™ÑäËtUÃ2¡nÐQwÈh6«R''ëê*Ú‰q$»mU ÚDˆÈèq¬/¹ü"¢¨£kànjJ ]_'F›Ž.ƒÊB¿ Aw¼Žq:Á™s” iV¯ZG{×F޼þ¹L£ÉŽ¢”)—³x<üÊG?ð'ŸþÔï|êÍÊè-ÕRùæçã¿>77!äâIº]NÒÚÜvt¢Bl‘b)‰¦©£!Ì #‚Ï ’HÃniå" VÈáZ®€¤I(nUi™ ÑïFmu€…¡³˜Í.Z·mE¯š(åâÔÊÌ»·Ò°ÉÔ$‘¸&Ñ>—ÆU¨’j1Q÷¸ð÷p©&fÃa2©4}=¤29²Ùêõ*gï~æç^ýÓÏ|æ—ÞR6 n*déÏÊ•úoLŒ_3QL⫝̸Lzt:'FT+9êõ*…Ħ¤‚Áâ@5ë¹ò‘¦Q|f-6ê¾+~.FÐt  ’ŠLà¤ÜíFlób×y(ÄBèóuÄÎåpÊ´,GG9[‡TJ±†b3¢õu zí¤ll’ƒRbIÒó‹ï{÷ù/}é‹+O—¼ ¼%¿'|9öîÛSúÎw~áýﺠi*Ç^Öol¥c׃øZV#IzbÑ1⯿Šx|]êj­¦WNK—Ah4§¡ÈÈ1Ì&r›±Ú@‹ øøï}MQÐe¯Ž—Ò€œ¬'cÉd‚€& 0µÈÂðaªµ:̦­›ãNÊç-—ã©§žüël>Ù2>:»cjl‚ÕÙ.'¹6+½F—Ç…ÇÞN©.PÌÅȦÃ(‘(Æ¢ˆh·^Wè— –ëTœ!>¦©´¶®Fêö¢H"å3ˆ†d£×‡h³¢$¸Î)©¨ Œ‡)ž=G"xAÑ4µQ§c]ÛÏ=üð?Ý)¹ü#ࡇüaU-ÍŸ;3ù®ÿÝܹÅFq^qü7;{¿z½»öÚÆ®Yˆ!–íÅ\‚ÃÕH DDI+ŒâæV)©T)¥Jò’Ëk„}ÎS5QQ•k©ˆÚ€PK$’BmŒÛÀRßÛ»Þ]{/žÝ™éÃØ¬ ÎÅþÒ¼ôé̾Ë9ß9çýÊ5Öºdvòn ³Õv¨õ±:PßS‹,X‘s³$§¢FF1§‹˜¬N}U2ú3¡¨¢B–2ú™]0ÐÖº›e.Cj$†ÙjgU¨Q›¿.¤®D0Œ§0åU š€¨EÃä ÒûIFzÈ&bØ+ªð6‡ñ„Ö2¥X’V×~õäo/×7YvOø‡ðê¡?¾;»ñÔï}¸çâWý„‚›ÉVZ°H*îþñrÈMµ²‚æá ù« ÆbÌ$bÄG#˜ŒL&›®aãñãy°*JTlcÒVpö?Ÿ!Kyææ$&"ƒdçòdrSìÙ³/{ì¯ï¹Þ}çMŸŸ{ÛFm,ÚËøÉË8“yšv´’žŽÿ[f©l§fÅ*buZXÛb[çnÖ‡w€—‡‘år)j]u¯ß¢ÊxÜzÁ¶ÉdÄå­úçâñ¾ùÖ™ý]{×Vúêo˜ÝÞÛ²¬K ½ÖØjs³q{û›Ëùî»» ϽеbëÖÊôx”k'z¡¤Þf6döÓL…2 b®Äd,ÅÙ³ÿâËSÇêC4˜°;* å~Nû*V×oâÆåÑóä‚p[sÑW^þÃЪÆÍl²a·éïš]·‹‘Ê)€úÚšêBß«Y§¸gt?ÛûüŸŸ~þÀ «Qãâ_£–6¬o%•J }Ö‡¨è$¤klø;Öa¶èBNW€ôlŒÑá LNö`Ô2Ôd.Ò;Cµ4ÇBX¡ç|ï’nËŽu Ü.Ý m·ú‚¢"e“ˆ¢™ö޶±AŸåÂ=%`:|øÑ×_?Üòð:©çüyâSiÞ&‘ž†ãƒXæ£-ÅKƒóânÞ° üöàó®äBßפØ>tší—/ñà˜~ cœ—š*%†#Ã-5vÇš–×Ê••â·k þ'—OâÔóË;—Í[ÀÏ~ ú.ìîš<‘H´Ð9G&×FûîÍo¤IS–3r%zMS©6ÌL” œò62v#KÏÀ {]·&z•{ŒhŒŒÇ¿KiõšÅb#—ORá®EXÔiEPTr׆‘¶–5…¥äv*î‹°€ƒÝ]²¯Ò«©ªÂðH?ùèñ-µmFÜ£³$§Ç F¶-Êå4)úôHÏŒñgó­·iŽE·í‰d’¿¼ì6oî`wWÉn³‘ÍÅñ×­—«¢ÏÃXŠ™™ ÎJ:÷ìzünØ|_PSãO ‚E‘¹40@õˆ~÷ªNçpØ}¨šÊœRn+f–õÌ„šÚf®ŽGÉ-*Ô^\»9“ž r±ï™¥Æt:𦩠EIõ€Þ•A4M¡¶:¨½ü»¿¸ æÞ¬l¬;î­¬§¦®)—&Ma’E²íulÛ½Ÿºš#…r^QŠ˜LVÂMMýUœ°ØFŠ¢Hý|ËbAP”"=‘¡%=X_ ²àó5âpZpËEÚ2Yš§3ä³I,f­mMÿ¾[öþɇã}’ýIEND®B`‚nestopia-1.51.1/icons/nestopia.desktop000066400000000000000000000002251411157722000177500ustar00rootroot00000000000000[Desktop Entry] Name=Nestopia Comment=Accurate NES Emulator Exec=nestopia %f Icon=nestopia Terminal=false Type=Application Categories=Game;Emulator; nestopia-1.51.1/icons/svg/000077500000000000000000000000001411157722000153335ustar00rootroot00000000000000nestopia-1.51.1/icons/svg/nespad.svg000066400000000000000000000255101411157722000173310ustar00rootroot00000000000000 image/svg+xml nestopia-1.51.1/icons/svg/nestopia.svg000066400000000000000000011760511411157722000177110ustar00rootroot00000000000000 image/svg+xml nestopia-1.51.1/lib/000077500000000000000000000000001411157722000141675ustar00rootroot00000000000000nestopia-1.51.1/lib/zlibstat.lib000066400000000000000000005005721411157722000165240ustar00rootroot00000000000000! / 1121701591 0 4011 ` ™ Þ Þ Þ Þ Þ Þ Þ Þ Þ Þ Þ Þ Þ Þ Þ Þ3Z3Z3Z3Z3Z3Z3Z3Z3Z3Z3Zmmmmmmmmmmmmmmmmmmmmmmmm¨X­­­­­­­éPéPéPéPéPéPéPéPéPéPéPõèõèHHHHHHHHHHHHHHHHHHHHHHHHHHHHHtHtHtpÐpÐpÐpÐpÐpÐpÐpÐpÐpÐpÐpÐpÐpÐpÐpÐpÐpÐpÐpÐpÐpÐpС¾¡¾¦Î¦Î¦Î¦Î¦Î¦Î¦Î¦Î¦Î¦Î¦Î¦Î¦ÎÞ’Þ’Þ’¤¤¤,,ÒY<Y<YQ!Ðõ  hèƒÄ…ÀtÇÇ@Ç@ðÃ)&(…ÀtV‹0PèƒÄ…ö‹Æuï^à /.Ç@ÇÃ4U‹l$…ít6‹E…Àu6hèƒÄ…ÀtÇÇ@Ç@ð…À‰E‰Eu¸˜ÿÿÿ]ÃS‹\$V‹uW‹|$…ÿ†€d$‹F…Àu0hèƒÄ…ÀtÇÇ@Ç@ð…À‰tQ‹ð‰E‹F;Çr‹Ç…À‹NL1v‹û+ù‹èŠˆAMu÷‹|$‹l$‹V‹NÐ+ÈØ+ø‰V‰N‰|$u„_^[3À]Ã_^[¸˜ÿÿÿ]Ã)m)í9Q3À…ö~ ˆ Áé@;Æ|õ…Ét…ö~SW‹Î‹ÙÁéƒÈÿ|$ó«‹Ëƒáóª_[‹L$VD$P‹BQPÿR+Æ÷ØÀƒÄÃQ>W‹ø3À…É~¤$ˆ8Áê@;Á|õ…Òt…É~‹ÑÁéƒÈÿó«‹Êƒáóª_Ã6C‹Jù¼vé¼ëƒùPvƒéP‹BV‹rÁàÆ‹2ÑîÁàÆ‹rÁáL1‹r ÁáÎÁá Á^ÃIHQ‹NjD$PWQÿVƒÄƒøu¶T$‹D$‰3ÀYËNWQÿVƒÄ÷ØÀYÃ8M‹NƒìUWjD$PSQÿVƒÄƒøu ¶|$ 3Àë‹VSRÿV‹|$ƒÄ÷ØÀ…À‹ïuA‹NjD$PSQÿVƒÄƒøu¶|$ ‹L$Áç3Àý‰9_]ƒÄËVSRÿVƒÄ…ÀtÞƒÈÿ‹T$_Ç]ƒÄÃR‹NƒìUWjD$PSQÿVƒÄƒøu ¶|$ 3Àë‹VSRÿV‹|$ƒÄ÷ØÀ…À‹ïu/‹NjD$PSQÿVƒÄƒøu ¶|$ 3Àë‹VSRÿVƒÄ÷ØÀ‹ÏÁáé…Àu/‹FjT$RSPÿVƒÄƒøu ¶|$ 3Àë‹NSQÿVƒÄ÷ØÀ‹×Áâê…ÀuA‹NjD$PSQÿVƒÄƒøu¶|$ ‹L$Áç3Àý‰9_]ƒÄËVSRÿVƒÄ…ÀtÞƒÈÿ‹T$_Ç]ƒÄÃWƒì‹CUV‹t$jjV½ÿÿP‰l$ÇD$ ÿSƒÄ…Àt^3À]ƒÄËKWVQÿS ‹øƒÄÿÿÿ‰|$s‰|$ ‹èhè‹ðƒÄ…öu_^]ƒÄø;膯ë‹l$ ‹|$‹D$›;ʼnl$w‰D$‹D$‹ï+è‹Ç+Å=¿w‹ø‹T$ ‹CjURPÿSƒÄ…ÀuZ‹L$ ‹SWVQRÿSƒÄ;ÇuEGý…À~0IŠL0ÿH€ùPu€|0Ku€|0u€|0t…ÀÝëʼnD$u‹D$ 9D$‚SÿÿÿVè‹D$ƒÄ_^]ƒÄÃ[)-/?\¸Ì@èSUV‹´$è@3Û3í;óWuD$$PèƒÄë ¹|$$󥋴$ä@‹”$à@‹D$@3É;ó”Á QRPÿT$0ƒÄ ;ÉD$DtX‹L$@PQÿT$8h¸@‰„$Ø@‰\$\‰œ$˜‰œ$à@‰œ$Ü@‰\$X‰\$TèƒÄ ;ÉD$ u ‹T$D‹D$@RPÿT$@ƒÄ_^]3À[ÄÌ@Â3Àƒþ‰„$Ø@…a‹L$DQ\$(è‹øƒÄ…ÿuƒÍÿ‹T$D‹D$@jWRPÿT$DƒÄ…ÀtƒÍÿ‹\$DL$Qt$(èƒÄ…ÀtƒÍÿ‹\$DT$Rt$(èƒÄ…ÀtƒÍÿ‹\$DD$Pt$(èƒÄ…ÀtƒÍÿ‹\$DL$Qt$(èƒÄ…ÀtƒÍÿ‹\$DT$Rt$(èƒÄ…ÀtƒÍÿ‹D$;D$u‹D$…Àu‹D$…Àt½™ÿÿÿ‹\$DL$Qt$(èƒÄ…ÀtƒÍÿ‹\$DT$Rt$(èƒÄ…ÀtƒÍÿ‹\$DD$Pt$(èƒÄ…ÀtƒÍÿ‹\$‹t$ 3;ù‚‡þÿÿ…í…þÿÿ‹D$…Àv7@PèƒÄ…À‰„$Ø@t"‹L$‹T$DQP‹D$HRPÿT$8‹Œ$è@ƒÄÆ+û+þ‰¼$Ð@‰|$hð‹þè‹T$‹L$DjÚ‰D$‹D$LSPQÿT$HƒÄ…ÀtƒÍÿ…övD…íu@¾ð;þs‹÷‹l$‹T$D‹D$@VURPÿT$8ƒÄ;ÆtƒÍÿëVL$LUQèƒÄ ‹è+þu¼‹D$…Àt PèƒÄ‹T$‹L$D‹D$jS‰”$Ô@‹T$HQR‰„$ä@ÿT$DƒÄ…À‹„$Ø@tƒÍÿ3Û‹Œ$è@;Ët‰;ët);Ãt PèƒÄ‹D$ PèƒÄ_^]3À[ÄÌ@‹D$ ¹.t$$‹øó¥_^][ÄÌ@Âc#b¡)ì\%WAR]RyR•RÐWìWR<)‡)ë9/Z/g/›3a‹D$‹L$jjPQèÂah‹†@…À„±‹Fl…À†¦SU»xÿÿÿW¾ˆ+Þ¤$‹Ž”@‹® @‹–œ@3ÀŠâýÿƒÊ3Á%ÿ‹D…Áé3Á‹Ž˜@‰†”@%ÿÁ‹Žœ@iÀ„@‰†˜@Áè3ÁÁé%ÿ3L…‰Žœ@‹Êƒñ¯ÊŠÁé2ш‹FlG;;Ђtÿÿÿ_][‹Fl‹V P‹FŽˆQRPÿV‹NlƒÄ;ÁÇFltƒÈÿÃ3ÀÃímSV‹t$ 3Û…öt‹F,…Àu ^¸šÿÿÿ[ ‹L$‹D$UWQn0P‰E‹†Œ@P‰N4艆Œ@‹F4…ÀvW‹F@…Àuèƒøÿu ØŽˆÇF@@‰N<…Ûu0ƒ¾€u0‹†„…Àu&‹~DSUè‹VD‹Ø‹Fl+×Â…Û‰Flt¢_]^‹Ã[ ‹F@‹N4;Ès‹Á3É…ÀvI‹UŠ‹~<ˆ9A;Èrï‹N4‹~@‹U+ȉN4‹N<+øÐȉ~@‹~8‰U‹VD‰N<‹NløÐȉ~8‰VD‰Nlé6ÿÿÿ:tSm‹srƒìV‹t$W3ÿ;÷t9~,u _¸šÿÿÿ^ƒÄ ƒ¾€SU‰~4uR9¾„uJ^0›‹F@…Àu膈ÇF@@‰F<‹nDjSè‹ND‹Vl+Í‹øÑ…ÿ‰Vltƃÿu3ÿ‹Fl…Àv…ÿu èƒøÿu øƒ¾€u‹†„…Àu/V0Rè‹øÇFh‹†„…Àu‹†Œ@‹V8‰D$$‰T$ ë‹D$$‹T$ ‹ND‹ž¤@Ù‹Nt‹èƒÁˆÁí‹ÅˆAÁèˆAÁèˆAÁè…ÀtÇÿÿÿÿ‹NtƒÁ‹ÃÁè‰D$ˆAÁèˆAÁèˆAÁè…ÀˆtÇÿÿÿÿƒ~\u ‹FtƒÀ$ÆÆ@‹NtƒÁ‹ÂÁè‰D$ˆAÁèˆAÁèˆAÁè…ÀˆtÇÿÿÿÿ…ÿu‹Fx‹NtPQV$RèƒÄ ‹ø‹FtPèƒÄ…ÿ…‹N ‹VQRÿV ‹N ‹V‰D$‹FpWƒÀPQRÿVƒÄƒÏÿ…À…ËŠD$$‹N ˆD$$‹ÅˆD$%ÁèˆD$&ÁèˆD$'Áè…Àt‰|$$‹FjT$(RQPÿVƒÄƒø…†‹D$‹N ˆD$%ÁèˆD$&ÁèˆD$'Áè…Àˆ\$$t‰|$$‹FjT$(RQPÿVƒÄƒøuG‹D$ŠT$ ‹N ˆD$%ÁèˆD$&ÁèˆD$'Áè…ÀˆT$$t‰|$$jD$(PQ‹NQÿV‹øƒïƒÄ÷ßÿ‹T$‹F ‹NjRPQÿVƒÄ…ÀtƒÏÿ‹†°@]@‰†°@[‹Ç_ÇF,^ƒÄ Hmcsm°z–9¤/ê y‹D$jjPè yƒìSUV‹t$3Û3í;óu^]¸šÿÿÿ[ƒÄƒ~,u SSVè‹è9\$u‹†´@;ÉD$u‰\$ ë‹D$PŠ@„Éuù+‰D$ ‹F ‹NWPQÿV ƒÄ;ë‰D$u>‹~$…ÿt7d$…íu$‹G…Àv‹NP‹F WRPQÿV‹OƒÄ;ÁtƒÍÿ‹O‹?Ù…ÿuÍ‹F$…Àt›‹8PèƒÄ…ÿ‹Çuï…í_…á‹F jT$RP‹FPÆD$(PÆD$)KÆD$*ÆD$+ÿVƒÄƒø…¬‹F ‹VjL$QPRÆD$(ÆD$)ÿVƒÄƒø…„‹F ‹VjL$QPRÆD$(ÆD$)ÿVƒÄƒø…\‹†°@‹N ˆD$ÁèˆD$ÁèƒÍÿ…Àtf‰l$jD$PQ‹NQÿVƒÄƒø…!‹†°@‹N ˆD$ÁèˆD$Áè…Àtf‰l$‹FjT$RQPÿVƒÄƒø…æ‹N ˆ\$Áë‹ÃˆD$ÁèˆD$ÁèˆD$Áè…Àt‰l$‹FjT$RQPÿVƒÄƒø…¢‹D$‹ž¬@‹N +ÈD$ÁèˆD$ÁèˆD$ÁèˆD$Áè…Àt‰l$‹FjT$RQPÿVƒÄƒøuX‹\$ ‹N ‹ÃÁèˆD$Áè…Àˆ\$tf‰l$‹FjT$RQPÿVƒÄƒøu!3í…Ûv‹L$‹V ‹FSQRPÿVƒÄ;ÃtƒÍÿ‹N ‹VQRÿVƒÄ…Àt…íuƒÍÿ‹†´@…Àt PèƒÄVèƒÄ^‹Å][ƒÄÂ*yÄ/à/é/û„ƒì SW‹|$3Û;ûu _¸šÿÿÿ[ƒÄ Â@U‹l$<;ëtƒýt]_¸šÿÿÿ[ƒÄ Â@ƒ,uSSWè;Ã…·V‹t$$;óu ¾‰t$$‹D$<;Ãu‰\$@ëPŠ@:Ëuù+‰D$@‹ÆPŠ@:Ëuù‹t$(+Â;ó‰D$ u‰Ÿˆ@ë‹F;Ãu‹Ö艇ˆ@‹D$Dƒø‰_|tƒø uÇG|ƒøu‹G|ƒÈë ƒøu ‹G|ƒÈ‰G|9\$XtƒO|‹O ‹W‹D$HQR‰ŸŒ@‰¯€‰Ÿ@‰_h‰_l‰‡„ÿW ‹L$H‹T$@‰Gp‹D$(ÁD.P‰Gxè‰GtÆPÆ@KÆ@Æ@‹GtƒÀˆˆX‹GtƒÀƈX‹Ot‹G|ƒÁˆÁèˆAÁèƒÄ ;ÃtfÇÿÿ‹Ot‹‡€ƒÁ ˆÁèˆAÁè;ÃtfÇÿÿ‹Ot‹‡ˆ@ƒÁ ˆÁèˆAÁèˆAÁèˆAÁè;ÃtÇÿÿÿÿ‹Gt‹T$ ˆXˆXˆXˆXƒÀ‹GtƒÀˆˆXˆXˆX‹GtƒÀˆˆXˆXˆX‹Gt‹êÁíƒÀ‹ÍˆHÁé;ˈ‰l$(tfÇÿÿ‹Ot‹D$8ƒÁˆÁèˆAÁè;ÃtfÇÿÿ‹Ot‹D$@ƒÁ ˆÁèˆAÁè;ÃtfÇÿÿ‹GtƒÀ";óˆˆXu‹GtƒÀ$ˆˆX‹GtƒÀ&ˆˆXˆXˆXëG‹Ot‹FƒÁ$ˆÁèˆAÁè;ÃtfÇÿÿ‹Ot‹F ƒÁ&ˆÁèˆAÁèˆAÁèˆAÁè;ÃtÇÿÿÿÿ‹¬@‹Gp+Á‹OtƒÁ*ˆÁèˆAÁèˆAÁèˆAÁè;ÃtÇÿÿÿÿ3À;Óv‹t$$‹Ot‰\$HŠ0ˆ\.‹\$H@;Ârå‹L$83À;Ëv-¤$‹l$4‹wt ‰T$HŠ(ˆT1.‹L$8‹T$H@;ÁrÞ‹l$(‹L$@3À;Ëv,‹t$8‹l$< ΋wt‰T$HŠ(ˆT1.‹L$@‹T$H@;ÁrØ‹l$(9_tu^]_¸˜ÿÿÿ[ƒÄ Â@‹G jT$‡/! .debug$F"!.text#›æ2}ÙJ# W __chkstk .debug$F$#.text%•›ìl% .debug$F&%.text'ím7Ï·w' .debug$F('.text)ì=ä°Œ) ¤ ¯ .debug$F*).text+êÅ_`š¹+ Ò .debug$F,+.text-%;«¼à- .debug$F.-.text/û÷ƒõ/ .debug$F0/.text1Mß¿º1  + .rdata2{M-=2.rdata3ïZ* [3.debug$F41.text5I ã(t5 .debug$F65.text7F4ãõ_7 .debug$F87¥?calls@?1??crypthead@@9@9_zip_copyright_decrypt_byte_update_keys_init_keys_crypthead_allocate_new_datablock_free_datablock_init_linkedlist_add_data_in_datablock_ziplocal_putValue_ziplocal_putValue_inmemory_ziplocal_TmzDateToDosDate_ziplocal_getByte_ziplocal_getShort_ziplocal_getLong_ziplocal_SearchCentralDir_zipOpen2@16_fill_fopen_filefunc_zipOpen@8_zipFlushWriteBuffer_zipWriteInFileInZip@12_deflate@8_crc32@12_zipCloseFileInZipRaw@12_deflateEnd@4_zipCloseFileInZip@4_zipClose@8_zipOpenNewFileInZip3@64_get_crc_table@0_deflateInit2_@32??_C@_05GDHACFMB@1?42?43?$AA@??_C@_01JOAMLHOP@?9?$AA@_zipOpenNewFileInZip2@44_zipOpenNewFileInZip@40/60 1121701591 100666 15106 ` LH×ÎÛB*Á.drectveXT .debug$S{¬ @B.rdataQ' @@@.textx P`.debug$F Ÿ @B.textG© P`.debug$Fð @B.texti P`.debug$Fs ƒ @B.text8 P`.debug$FÅ Õ @B.textß P`.debug$Fn~@B.textˆ P`.debug$F‹›@B.text@¥ P`.debug$Fåõ@B.text\ÿ[ P`.debug$Feu@B.text?¾ P`.debug$FÒâ@B.text$ì P`.debug$F @B.textG* P`.debug$Fq@B.textŽ‹ P`.debug$F¹É@B.text4Ó P`.debug$F!@B.textN+y P`.debug$Fƒ“@B.text P`.debug$F(8@B.textB\ P`.debug$F„”@B.text7ž P`.debug$FÕå@B.textTïC P`.debug$FM]@B.textògY P`.debug$F½Í@B.text¨× P`.debug$F§·@B.text Á P`.debug$Fáñ@B.text)û P`.debug$F$ 4 @B.text‘> P`.debug$FÏ ß @B.text‘é z! P`.debug$F˜!¨!@B.text‰²! P`.debug$F;"K"@B.text6U" P`.debug$F‹"›"@B.textN¥"ó" P`.debug$Fý" #@B.text #$% P`.debug$Fœ%¬%@B.text¶%Å% P`.debug$FÏ%ß%@B.text<é%%& P`.debug$F9&I&@B.text‡S&Ú( P`.rdataH)@0@.debug$FN)^)@B.texth)}) P`.debug$F‡)—)@B.text¡)¹) P`.debug$FÃ)Ó)@B.textÝ)û) P`.debug$F**@B/DEFAULTLIB:"uuid.lib" /DEFAULTLIB:"uuid.lib" /DEFAULTLIB:"LIBC" /DEFAULTLIB:"OLDNAMES" ; 4x:\zlib-1.2.3\contrib\vstudio\vc7\zlibstat\unzip.obj8   !Microsoft (R) Optimizing Compiler unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll‹@%ýÿƒÈ‹Èƒñ¯È¶ÅË‹Ê3Èáÿ‹ Áê3Ê‹V‰áÿÊ‹ViÉ„A‰NÁé3ÊSáÿ‹Áê3Ó‰V[ÃG4V‹ð3ÀÇxV4ÇB‰gE#ÇBxV4Š„ÀtHS‹ 3Á%ÿ‹‡Áé3Á‹J‰%ÿÁ‹JiÀ„@‰BÁè3Á%ÿ‹‡Áé3ËF‰JŠ„Àuº[^ÃiQ‹NjD$PWQÿVƒÄƒøu¶T$‹D$‰3ÀYËNWQÿVƒÄ÷ØÀYÃ8‹NƒìUWjD$PSQÿVƒÄƒøu ¶|$ 3Àë‹VSRÿV‹|$ƒÄ÷ØÀ…À‹ïuA‹NjD$PSQÿVƒÄƒøu¶|$ ‹L$Áç3Àý‰9_]ƒÄËVSRÿVƒÄ…ÀtÞƒÈÿ‹T$_Ç]ƒÄÃ"‹NƒìUWjD$PSQÿVƒÄƒøu ¶|$ 3Àë‹VSRÿV‹|$ƒÄ÷ØÀ…À‹ïu/‹NjD$PSQÿVƒÄƒøu ¶|$ 3Àë‹VSRÿVƒÄ÷ØÀ‹ÏÁáé…Àu/‹FjT$RSPÿVƒÄƒøu ¶|$ 3Àë‹NSQÿVƒÄ÷ØÀ‹×Áâê…ÀuA‹NjD$PSQÿVƒÄƒøu¶|$ ‹L$Áç3Àý‰9_]ƒÄËVSRÿVƒÄ…ÀtÞƒÈÿ‹T$_Ç]ƒÄÃ'V‹ðŠ ŠBF€ùa|€ùz€Áà‡­ _free _malloc .debug$F.text$ãH‚È .debug$F.textGƒbÁaÜ .debug$F.textŽr©‰ø÷ .debug$F.text4H¯(£ .debug$F.textNY=ðd6 .debug$F.text 6†2FJ .debug$F! .text"ìħJ]" .debug$F#".text$7úBEo$ .debug$F%$.text&T*ç1€& .debug$F'&.text(ò Yå$i’( .debug$F)(.text*¨ÜÛp¼* Ó Ý .debug$F+*.text, öJˆè, .debug$F-,.text.)Ž ¿ó. .debug$F/..text0‘`œKý0 .debug$F10.text2‘172 . .debug$F32.text4‰E÷û*<4 .debug$F54.text66¸ ¹T6 .debug$F76.text8N¦„í¹d8 .debug$F98.text:  u<‡Š‰~ > .debug$F?>.text@‡ /JKP¬@ Ä Õ .rdataA{M-çA.debug$FB@.textCgËåC .debug$FDC.textEšžæE .debug$FFE.textG.tûN9G .debug$FHGQ_unz_copyright_decrypt_byte_update_keys_init_keys_unzlocal_getByte_unzlocal_getShort_unzlocal_getLong_strcmpcasenosensitive_internal_unzStringFileNameCompare@12_unzlocal_SearchCentralDir_unzGetGlobalInfo@8_unzlocal_DosDateToTmuDate_unzlocal_GetCurrentFileInfoInternal_unzGetCurrentFileInfo@32_unzGoToFirstFile@4_unzGoToNextFile@4_unzLocateFile@12_unzGetFilePos@8_unzGoToFilePos@8_unzlocal_CheckCurrentFileCoherencyHeader_unzReadCurrentFile@12_crc32@12_inflate@8_unztell@4_unzeof@4_unzGetLocalExtrafield@12_unzCloseCurrentFile@4_inflateEnd@4_unzGetGlobalComment@12_unzGetOffset@4_unzSetOffset@8_unzOpen2@8_fill_fopen_filefunc_unzOpen@4_unzClose@4_unzOpenCurrentFile3@20_get_crc_table@0_inflateInit2_@16??_C@_05GDHACFMB@1?42?43?$AA@_unzOpenCurrentFile@4_unzOpenCurrentFilePassword@8_unzOpenCurrentFile2@16/81 1121701591 100666 1136 ` L×ÎÛB­.drectveXÜ .debug$S}4@B.textª±[ P`.rdata@0@.debug$F“£@B/DEFAULTLIB:"uuid.lib" /DEFAULTLIB:"uuid.lib" /DEFAULTLIB:"LIBC" /DEFAULTLIB:"OLDNAMES" = 6x:\zlib-1.2.3\contrib\vstudio\vc7\zlibstat\uncompr.obj8   !Microsoft (R) Optimizing Compilerƒì8‹L$H‹D$D‹T$¾~þAÁ!¡aá‘QÑ1±qñ ‰IÉ)©ié™YÙ9¹yù…EÅ%¥eå•UÕ5µuõ MÍ-­mí]Ý=½}ý  “ “ S S Ó Ó 3 3 ³ ³ s s ó ó  ‹ ‹ K K Ë Ë + + « « k k ë ë   › › [ [ Û Û ; ; » » { { û û   ‡ ‡ G G Ç Ç ' ' § § g g ç ç   — — W W × × 7 7 · · w w ÷ ÷    O O Ï Ï / / ¯ ¯ o o ï ï   Ÿ Ÿ _ _ ß ß ? ? ¿ ¿   ÿ ÿ @ `P0pH(hX8xD$dT4tƒCÃ#£cã         (08@P`p€ Àà  0@`€À€  0@`ÃV‚”¹3ö‹ÿf‰0ƒÀIu÷‚ˆ ¹f‰0ƒÀIu÷‚| ¹f‰0ƒÀIu÷‰²¬‰²¨‰²°‰² fÇ‚”^Ãd!Q‹PUV‹t$‹¬°\ 6;ʉl$–S}2‹´ˆ` ‹¬ˆ\ f‹·f‹¯f;ÓruŠ”X:”(XwA‹l$ ‹´ˆ\ f‹¯f‹·f;Ór-uŠ”(X:”Xv+‹T$‰´\ ‹P‰L$Ñá;Ê~‹‹L$[^‰¬ˆ\ ]YËT$[^‰¬\ ]Yɬ°\ ^]YÃÄ &ƒì ‹Q‰T$S‹‹I‹Q‰T$ ‹Q‰T$3ÒU‹)V‹q‰< ‰@ ‰D ‰H ‰L ‰P ‰T ‰X ‹T‹”\ 3ÉWf‰L“‹¸TGÿ=‰t$‰L$¤Œ¸\ ‰L$¹=+Ïù‰L$ ‰|$ë ‹t$¤$‹T$‹·L“·L‹A;Î~‹ÎÿD$;T$$f‰L“L‹|$(fÿ„H< 3ö;×| ‹ò+÷‹|$,‹4··<“ίψ¨…ít·T•‹ˆ¬Ö¯×ʉˆ¬‹|$‹T$‹L$ ƒÂI‰T$‰L$ …iÿÿÿ‹l$…í„ã‹L$Qÿ‰T$,´H< ›‹L$,fƒ¼H< ”H< u ƒêIfƒ:töfÿŒH< fƒ„H> fÿƒí…íÅ‹T$…Ò„„‰t$ ëI·6…ö‰t$t`¬¸\ ‹|$‹MüOƒí‰|$;L$$‰l$,8·|‹;út‹t · ‹‹ê+ï¯é‹ˆ¨Í‹l$,‰ˆ¨f‰‹L$I‰L$‹ñ…öu«‹|$‹t$ Jƒî…Ò‰t$ u…_^][ƒÄ Ã3g+QSUVW·xƒÍÿ3ö…ÿ‹Ù¹ºu ¹Šº…ÛfÇD˜ÿÿŒ›ƒÀ‰D$C‹Ç‹|$·?F;ñ};Çtn;ò‹L$} f´| ë.…Àt;Åtfÿ„| fÿ¼ ëƒþ  fÿÀ ëfÿÄ 3ö…ÿ‹èu ¹Šºë;Çu ¹ºë ¹º‹D$ƒÀK‰D$…nÿÿÿ_^][YÃØ0ƒì SU‹l$VW‹ù·O‰L$3öƒËÿ9t$¹ºu ¹Šº…íŒÆƒÇE‰|$‰l$뛋|$·?‹l$F;ñ‰|$‰t$ };ï„x;ò§ë›·¼¨~ ‹ˆ¼º+×;Ê~\·´¨| ‹ÖÓâ‹Hf ¸‹PŠ˜¸ˆ‹PŠ˜¹B‰P‹Ê‹Pˆ‹H‹¼A‰H±*ÊfÓîL:ðf‰°¸‹t$ ëf‹”¨| fÓâf ¸ÏN‰ˆ¼‰t$ …fÿÿÿé—…í„™;ë„”·¼¨~ ‹ˆ¼º+×;Ê~\·´¨| ‹ÖÓâ‹Hf ¸‹PŠ˜¸ˆ‹PŠ˜¹B‰P‹Ê‹Pˆ‹H‹¼A‰H±*ÊfÓîL:ðf‰°¸‹t$ ëf‹”¨| fÓâf ¸ÏN‰ˆ¼‰t$ ·¸¾ ‹ˆ¼º+×;Ê~[·°¼ ‹ÖÓâ‹Hf ¸‹PŠ˜¸ˆ‹PŠ˜¹B‰P‹Ê‹Pˆ‹H‹¼A‰H±*ÊfÓîL:ðf‰°¸‹t$ ëf‹¼ fÓâf ¸σÆýƒù‰ˆ¼~X‹ÖÓâ‹Hf ¸‹PŠ˜¸ˆ‹PŠ˜¹B‰P‹Ê‹Pˆ‹H‹¼A‰H±*ÊfÓîƒÂò‰¼f‰°¸éÓæf °¸ƒÁéðƒþ ‹ˆ¼ºò·¸Â +×;Ê~[·°À ‹ÖÓâ‹Hf ¸‹PŠ˜¸ˆ‹PŠ˜¹B‰P‹Ê‹Pˆ‹H‹¼A‰H±*ÊfÓîL:ðf‰°¸‹t$ ëf‹À fÓâf ¸σÆýƒù ‰ˆ¼~X‹ÖÓâ‹Hf ¸‹PŠ˜¸ˆ‹PŠ˜¹B‰P‹Ê‹Pˆ‹H‹¼A‰H±*ÊfÓîƒÂó‰¼f‰°¸éÓæf °¸ƒÁéê·¸Æ +×;Ê~[·°Ä ‹ÖÓâ‹Hf ¸‹PŠ˜¸ˆ‹PŠ˜¹B‰P‹Ê‹Pˆ‹H‹¼A‰H±*ÊfÓîL:ðf‰°¸‹t$ ëf‹Ä fÓâf ¸σÆõƒù ‰ˆ¼~U‹ÖÓâ‹Hf ¸‹PŠ˜¸ˆ‹PŠ˜¹B‰P‹Ê‹Pˆ‹H‹¼A‰H±*ÊfÓîƒÂ÷‰¼f‰°¸ëÓæf °¸ƒÁ‰ˆ¼‹L$3ö…É‹Ýu ¹Šºë;éu ¹ºë ¹º‹l$‹|$ƒÅO‰l$‰|$…Nûÿÿ_^][ƒÄ à  5‹ˆ¼ƒù S‹\$ U‹l$VW~g‹t$Æÿþÿÿ‹ÖÓâ‹H‰\$f ¸Š˜¸‹Pˆ‹PŠ˜¹B‰P‹Ê‹Pˆ‹H‹¼‹\$A‰H±*ÊfÓîƒÂõ‰¼f‰°¸ë‹T$ÂÿþÿÿÓâf ¸ƒÁ‰ˆ¼‹ˆ¼ƒù ~`sÿ‹ÖÓâ‹H‰\$f ¸Š˜¸‹Pˆ‹PŠ˜¹B‰P‹Ê‹Pˆ‹H‹¼‹\$A‰H±*ÊfÓîƒÂõ‰¼f‰°¸ëSÿÓâf ¸ƒÁ‰ˆ¼‹ˆ¼ƒù ~`uü‹ÖÓâ‹H‰\$f ¸Š˜¸‹Pˆ‹PŠ˜¹B‰P‹Ê‹Pˆ‹H‹¼‹\$A‰H±*ÊfÓîƒÂô‰¼f‰°¸ëUüÓâf ¸ƒÁ‰ˆ¼3ÿ…íŽ£ë ¤$I‹ˆ¼ƒù ¶—~]·´~ ‹ÖÓâ‹Hf ¸Š˜¸‹Pˆ‹PŠ˜¹B‰P‹Ê‹Pˆ‹H‹¼A‰H±*ÊfÓîƒÂó‰¼f‰°¸ëf‹”~ fÓâf ¸ƒÁ‰ˆ¼G;ýŒmÿÿÿ‹\$‹L$IQˆ”èKSˆˆ èƒÄ_^][üT5a5m:‹D$‹ ‹L$V‹°¤f‰ V‹°˜‹T$W‹¸ ˆ>‹¸ G…ɉ¸ u fÿ„”ë@ÿ€°¶’Ifÿ„˜ù”˜s ¶‰ë Á鶉fÿ„ˆˆ ‹ˆœ‹° 3ÒI;ñ”Â_^‹ÂÃQp|¡$?‹ ƒì S‹\$UV3É…ÒW„FëI‹¤·,J‹˜¶4A…í‰L$‹ˆ¼…„·|³º+×;Ê~_·4³‹ÖÓâ‹H‰\$f ¸‹PŠ˜¸ˆ‹PŠ˜¹B‰P‹Ê‹Pˆ‹H‹¼‹\$A‰H±*ÊfÓîL:ðf‰°¸é•f‹³fÓâf ¸Ï逶–·¼“»+ß;ˉ|$‹|$ ‰T$~f·¼—‹×Óâ‹Hf ¸‹PŠ˜¸ˆ‹PŠ˜¹B‰P‹Ê‹Pˆ‹H‹¼A‰H±*ÊfÓï‹L$T ð‰¼‹T$f‰¸¸ëf‹¼—fÓçf ¸¸‹|$ωˆ¼‹<•…ÿ‹\$ „}+4•‹ˆ¼º+×;Ê~T‹ÖÓâ‹Hf ¸‹PŠ˜¸ˆ‹PŠ˜¹B‰P‹Ê‹Pˆ‹H‹¼‹\$ A‰H±*ÊfÓîL:ðf‰°¸ë Óæf °¸ωˆ¼Mýs ¶½ë ‹ÕÁ궺‹L$$·T¹‹ˆ¼¾+ò;ΉT$~f‹T$$·4º‹ÖÓâ‹Hf ¸‹PŠ˜¸ˆ‹PŠ˜¹B‰P‹Ê‹Pˆ‹H‹¼‹\$ A‰H±*ÊfÓî‹L$T ð‰¼f‰°¸ë‹t$$f‹4¾fÓæf °¸ʉˆ¼‹4½…ö„+,½‹ˆ¼º+Ö;Ê~X‹ÕÓâ‹H‰\$f ¸‹PŠ˜¸ˆ‹PŠ˜¹B‰P‹Ê‹Pˆ‹H‹¼‹\$A‰H±*ÊfÓíL2ðf‰¨¸ë Óåf ¨¸Ήˆ¼‹L$;ˆ ‚¿üÿÿ·»‹ˆ¼º+×;Ê~x·³‹ÖÓâ‹H‰\$ f ¸‹PŠ˜¸ˆ‹P‹H‹\$ B‰P‹êйˆ)‹H‹¼A‰H±*ÊfÓîL:ð_‰ˆ¼f‰°¸·“^]‰´[ƒÄ Ãf‹“fÓâf ¸Ï_‰ˆ¼·‹^]‰ˆ´[ƒÄ ÃÎx‹ÄÓD3ÀŠ”fƒ9u @ƒÁƒø |ñƒø …›¸ŠÐëIfƒyü…€fƒ9u5fƒyu=fƒyuGfƒy uQfƒyu[ƒÀƒÁƒø |È‹3Ƀø ”Á‰J,Ë3É@ƒø ”Á‰J,Ë3ɃÀƒø ”Á‰J,Ë3ɃÀƒø ”Á‰J,Ë3ɃÀƒø ”Á‰J,ÃÀ‹3Ƀø ”Á‰J,ÃÉI3ÀV‹ñƒæ ÆÑéÑàJ…ÒðÑè^ÃN‹ˆ¼ƒùSu8‹PŠ˜¸‹Hˆ‹PŠ˜¹B‰P‹Ê‹Pˆÿ@3Éf‰ˆ¸‰ˆ¼[Ãù|4‹H‹PŠ˜¸ˆf¶ˆ¹‹Pf‰ˆ¸‹ˆ¼BƒÁø‰P‰ˆ¼[à S‹¼ƒúS~8‹PŠ˜¸‹Hˆ‹PŠ˜¹B‰P‹Ê‹Pˆÿ@3Éf‰ˆ¸‰ˆ¼[Ã3É;Ñ~‹PŠ˜¸V‹pˆ2ÿ@^f‰ˆ¸‰ˆ¼[Ãm XSVW‹Ù‹úè‹L$…ÉÇ€´t;‹H‹Pˆ‹H‹PA‰Hˆ<‹p‹PF‰pŠËöш ‹p‹PF‹Ë÷щpˆ,ÿ@…Ût!I‹H‹P‰\$Šˆ‹p‹\$FGK‰puâ_^[ÃX‚]‹T$‚”‰‚ ‚| ‰‚0 3ÀŠˆ Ç‚ ‰Š$ Ç‚, Ç‚8 f‰‚¸‰‚¼Ç‚´é* : D `!dbƒì Vt$3ɸ+Ö4B·t4fñÑæ‹Îf‰LD@ƒø~æ3ö…Û|;U·T·…Òt+3Àf‹DT·È@f‰DT3ÀI‹éƒå ÅÑéÑàJ…ÒðÑèf‰·F;ó~Ç]^ƒÄ Ãqgƒì‹D$ SUW‹8‹@‹H ‹3ÒƒÍÿ3À;ʉL$‰l$ ‰–PdžT=~7f9‡t#‹ŽPA‰ŽP‰„Ž\ ‰D$ ˆ”0X‹èëf‰T‡‹L$@;Á|Ƀ¾P}Vƒý}E‹Åë3À‹ŽPA‰ŽP‰„Ž\ fLJˆ”X‹Ž¨I;Ú‰Ž¨t ·Dƒ)†¬ƒ¾P|®‰l$ ‹L$‰i‹†P™+‹ØÑûƒû|S‹ÆèƒÄKƒû}ï‹l$ëI‹†P‹”†\ ‹ž` H‰†Pj‹Æ‰–` è‹–T‹†` ƒÄJ‰–T‹Ê‰œŽ\ ‹ŽTI‰ŽT‰„Ž\ f‹ ‡f Ÿf‰ ¯ŠŒXŠ”X:Ñr¶Êë¶ÉþÁˆŒ.Xf‰l‡f‰lŸ‰®` j‹ÆE苆PƒÄƒøIÿÿÿ‹†T‹–` ‹L$H‰†T‰”†\ ‹Æè‹\$ –< è_][ƒÄÃê&%&¡&Ø+çgò lV‹ð‹Ž †”V苎( †ˆ Vè†0 PèƒÄ ¸ëI¶ˆfƒ¼Ž~ uHƒø}苎¨T@Ê‰Ž¨^Ã0#0/lClq‹D$‹ˆ¼ƒù ~jSV‹t$‹ÖÓâ‹Hf ¸‹PŠ˜¸ˆ‹HŠ˜¹‹PA‰Hˆ‹¼‹X±*ÊfÓî‹L$CƒÂóf‰°¸^‰X‰¼‹T$ [jèYËT$ÓâƒÁ‰ˆ¼‹L$ f ¸‹T$jèYÃs]š] v‹D$‹ˆ¼ºÓâSVf ¸ƒù ~M‹PŠ˜¸‹Hˆ‹HŠ˜¹‹PA‰Hˆ‹¼‹X±*ʾfÓîCƒÂó‰Xf‰°¸‰¼ë ƒÁ‰ˆ¼‹ˆ¼3ÒÓâf ¸ƒù ~J‹PŠ˜¸‹Hˆ‹HŠ˜¹‹PA‰Hˆ‹¼‹X±*Ê3öfÓîCƒÂ÷‰Xf‰°¸‰¼ë ƒÁ‰ˆ¼苈¼‹´+у ƒú çºÓâf ¸ƒù ~M‹PŠ˜¸‹Hˆ‹HŠ˜¹‹PA‰Hˆ‹¼‹X±*ʾfÓîCƒÂó‰Xf‰°¸‰¼ë ƒÁ‰ˆ¼‹ˆ¼3ÒÓâf ¸ƒù ~Z‹PŠ˜¸‹Hˆ‹HŠ˜¹‹PA‰Hˆ‹¼‹X±*Ê3öfÓîCƒÂ÷‰Xf‰°¸‰¼è^Ç€´[ÃÁ‰ˆ¼è^Ç€´[ÃßSÅSàSñ{SU‹l$V‹t$‹Ž„3À…ÉW~S…ív‹ƒx,u‹ÖèŽ Qè–$ RèƒÄ‹Æè‹–¨‹Ž¬ƒÂ ƒÁ ÁêÁé;ÊwëM‹Ñ};úw‹\$…Ût‹|$ WUSVèƒÄéWƒ¾ˆ„½;Ê„µ‹Ž¼ƒù ‹|$ W~[‹ÚÓã‹N‰D$ f ž¸‹^І¸ˆ‹NІ¹‹^A‰Nˆ‹ž¼‹F±*ËfÓê@ƒÃó‰F‹D$ f‰–¸‰ž¼ëÓâf –¸ƒÁ‰Ž¼‹Ž @P‹†( @PAQ‹Æè–ˆ R†”P‹ÆèƒÄ鋎¼ƒù ‹|$ G~U‹ÐÓâ‹Nf –¸‹VŠž¸ˆ‹VŠž¹B‰V‹Ê‹Vˆ‹N‹–¼A‰N±*ÊfÓèƒÂó‰–¼f‰†¸ëÓàf †¸ƒÁ‰Ž¼hh‹ÆèƒÄ‹Öè…ÿ_t ‹Æ^][é^][Ã'I3l?lIqˆv=:RDØÝäDî!ýX€.fileþÿg\zlib-1.2.3\trees.c@comp.id _ÿÿ@feat.00ÿÿ.drectveX.debug$S{.data<a‘ß(#.rdata8 Se-«2À =H JHXHdÐrP€<Šð˜x¥.text “m² .debug$F.textd7$÷ .debug$F.text ÄuŸ“ËÎ .debug$F  .text 3U ¾Ú .debug$F  .text Ø?¾yæ .debug$F .text Ôpñ .debug$F.textm݆¡îü .debug$F.text¡4®vš  .debug$F.textÂÈŽø .debug$F.textÉ`E f' .debug$F.text1V=,6 .debug$F.textó(™xB .debug$F.textmo`ë©L .debug$F.text‚ïm W .debug$F .text!dqk.c! .debug$F"!.text#qU§2m# .debug$F$#.text%ò½Ù™éx% .debug$F&%.text'l 7…¸„' .debug$F('.text) ý‚&“) .debug$F*).text+ñ\¥†n¥+ .debug$F,+.text- |çh°- .debug$F.-Á_static_bl_desc_static_d_desc_static_l_desc_base_dist_base_length__length_code__dist_code_static_dtree_static_ltree_bl_order_extra_blbits_extra_dbits_extra_lbits_tr_static_init_init_block_pqdownheap_gen_bitlen_scan_tree_send_tree_send_all_trees__tr_tally_compress_block_set_data_type_bi_reverse_bi_flush_bi_windup_copy_block__tr_init_gen_codes_build_tree_build_bl_tree__tr_stored_block__tr_align__tr_flush_block/125 1121701591 100666 3164 ` L×ÎÛBÿ@.drectveX\ .debug$S{´@B.textJ/y P`.rdata¡@0@.rdata¤@0@.rdata¨@0@.debug$F«»@B.textÅß P`.debug$Féù@B.text P`.debug$F'7@B.textAO P`.debug$FYi@B.textasÔ P`.debug$Fò@B.text  P`.debug$F$4@B.text > P`.debug$FIY@B.text<cŸ P`.debug$Fåõ@B/DEFAULTLIB:"uuid.lib" /DEFAULTLIB:"uuid.lib" /DEFAULTLIB:"LIBC" /DEFAULTLIB:"OLDNAMES" ; 4x:\zlib-1.2.3\contrib\vstudio\vc7\zlibstat\ioapi.obj8   !Microsoft (R) Optimizing Compiler‹T$ ‹ÂV$3ö3É<u¹ëöÂt¹ë öÂt¹‹T$ …Òt…Ét QRèƒÄ^ËÆ^Ã*= wbr+brbJ ‹D$‹L$‹T$ PQjRèƒÄËD$‹L$‹T$ PQjRèƒÄÃ! ‹D$PèƒÄÃ'&‹D$ƒèt@Ht"HtƒÈÿËL$¸P‹D$PQèƒÄ 3ÀËL$¸P‹D$PQèƒÄ 3ÀËL$3ÀP‹D$PQèƒÄ 3ÀÃ$-?-W-a,‹D$PèƒÄÃ32‹D$‹@ ƒà à 8‹D$ÇÇ@Ç@Ç@ Ç@Ç@Ç@Ç@à   &",)208<=.fileþÿg\zlib-1.2.3\contrib\minizip\ioapi.c@comp.id _ÿÿ@feat.00ÿÿ.drectveX.debug$S{.textJ\ø"ô _fopen .rdataðwu.rdata3Èå¢-.rdataµ¾J.debug$F.textJch_ _fread .debug$F .text Jchp _fwrite .debug$F  .text  ú:'‚ _ftell .debug$F  .textaûW-“ _fseek .debug$F.text ú:'¤ _fclose .debug$F.text £ú7N¶ .debug$F.text<Ãh«×È .debug$FÝ_fopen_file_func??_C@_02GMLFBBN@wb?$AA@??_C@_03HMFOOINA@r?$CLb?$AA@??_C@_02JDPG@rb?$AA@_fread_file_func_fwrite_file_func_ftell_file_func_fseek_file_func_fclose_file_func_ferror_file_func_fill_fopen_filefunc/146 1121701591 100666 2596 ` L×ÎÛB.drectveXÜ .debug$S~4@B.rdata0²@@@.textêâÌ P`.debug$Fô@B/DEFAULTLIB:"uuid.lib" /DEFAULTLIB:"uuid.lib" /DEFAULTLIB:"LIBC" /DEFAULTLIB:"OLDNAMES" > 7x:\zlib-1.2.3\contrib\vstudio\vc7\zlibstat\inftrees.obj8   !Microsoft (R) Optimizing Compiler inflate 1.2.3 Copyright 1995-2005 Mark Adler  #+3;CScsƒ£ÃãÉÄ !1AaÁ  0@`@@ƒì|‹”$ˆ3À…Ò‰D$<‰D$@‰D$D‰D$H‰D$LS‰D$TU‹¬$Œ‰D$\V‰D$dv›·LEfÿDLHLLH@;Ârí‹´$œ‹»‰D$‰\$¤$fƒ|\HuKƒûsò;É\$v‰\$…Ûu9‹„$˜‹f‰\$ÆD$ @ÆD$ ‹L$ ‰ ‹ƒÂ‰‰ ƒÇ^]3À[ƒÄ|þd$fƒ|tHu:fƒ|tJu"fƒ|tLufƒ|tNufƒ|tPuƒÆƒþvÐëFë ƒÆëƒÆëƒÆ9t$s‰t$º‹Â·LDHÒ+Ñx&@ƒøvï…ÒW‹¼$~…ÿtƒût_^]ƒÈÿ[ƒÄ|Ã^]ƒÈÿ[ƒÄ|ÃfÇD$n¸›f‹TlfTLf‹LNfÊf‰Tnf‰LpƒÀƒørÜ‹œ$˜3À…Ûv0fƒ|Et#·TE·LTl‹”$¤f‰J·TEfÿDTlTTl@;ÃrЋǃèºÿÿÿÿt;HtÇD$4ÇD$0‰T$,ë9¸-‰D$4¸-ÇD$,ë‹„$¤‰D$4ÇD$,‰D$0‹„$œ‹‰L$ ‹L$¸Óà‰T$83í3ÛƒÿPÿ‰t$‰D$<‰D$(‰T$@u =°ƒk‹„$¤‰D$$IŠL$‹t$$f‹‹T$,*ˈL$·È;Ê} ÆD$f‰D$ë-~·‹T$0ÑàŠ ‹T$4f‹ˆL$f‰D$ë ÆD$`fÇD$‹L$‹D$<+˺Óâ‹Ë‹ýÓï‹L$ ‰D$D4•ø ¹‹|$+Â+Î…À‰9uö‹T$Jÿ¸Óà…ÅtÑè…Åuú…Àt Hÿ#ÍÈ‹éë3í‹t$$ƒÆfÿLTLfƒ|TL‰t$$u;T$„à‹Œ$”‹Ö··A‰T$;T$† ÿÿÿ‹t$@‹D$8#õ;ð‰t$H„óþÿÿ…Ûu‹\$‹D$ ‹L$D‹|$ˆ‹L$+ˉT$ ¸ Óà;×s tTL·>+Ç…À~‹|$ABƒÆÑà;×rè‹t$H‹T$(¸ÓàЉD$<ƒ¼$‰T$(u ‹Â=°ƒÕ‹Ö‹´$œ‹ˆ ‹ŠD$ˆD‘‹‹L$ +ÈÁù‰T$8f‰LéGþÿÿ‹¼$œŠÂ*Ã…íÆD$@ˆD$fÇD$t]‹t$ d$…Ût ‹L$@‹D$8#Í;Èt‹D$‹73Û‰D$ˆD$‹Ð‹Ë‹ÅÓè‹L$‰ †Jÿ¸Óà…ÅtÑè…Åuú…Àt Hÿ#ÍÈ‹éu«‹T$(‹•‹T$ȉ‹Œ$ _^]‰3À[ƒÄ|Ã_^]¸[ƒÄ|Ãä ì ÷ ê4.fileþÿg\zlib-1.2.3\inftrees.c@comp.id _ÿÿ@feat.00ÿÿ.drectveX.debug$S~.rdata0S ‘Nð!°?p\0z.textê—+›’ .debug$Fœ?dext@?1??inflate_table@@9@9?dbase@?1??inflate_table@@9@9?lext@?1??inflate_table@@9@9?lbase@?1??inflate_table@@9@9_inflate_copyright_inflate_table/170 1121701591 100666 17876 ` L0×ÎÛB¢4°.drectveX” .debug$S}ì@B.rdata¦i@@@.texta P`.debug$Fp€@B.textZŠ P`.debug$Fäô@B.textÌþÊ P`.debug$Fèø@B.text P`.debug$F%5@B.text?\ P`.debug$Fp€@B.textŠ P`.debug$FŸ¯@B.text¹¹*O P`.rdataÏ-@0@.rdataæ-@0@.rdataû-@0@.rdata.@0@.rdata/.@0@.rdataK.@0@.rdataa.@0@.rdata{.@0@.rdata$—.@0@.rdata».@0@.rdataÔ.@0@.rdatañ.@0@.rdata/@0@.rdata/@0@.rdata1/@0@.rdataH/@0@.rdata\/@0@.debug$Fw/‡/@B.textL‘/ P`.debug$FÝ/í/@B.textë÷/â0 P`.debug$F11@B.text01 P`.debug$FJ1Z1@B.textRd1 P`.debug$F¶1Æ1@B.textûÐ1Ë2 P`.debug$Fé2ù2@B.text03 P`.debug$F33C3@B.text;M3 P`.debug$Fˆ4˜4@B/DEFAULTLIB:"uuid.lib" /DEFAULTLIB:"uuid.lib" /DEFAULTLIB:"LIBC" /DEFAULTLIB:"OLDNAMES" = 6x:\zlib-1.2.3\contrib\vstudio\vc7\zlibstat\inflate.obj8   !Microsoft (R) Optimizing Compiler`Psp0 À `  €@ àX ;x8 Ðh( °ˆH ðTã+t4 È d$ ¨„D è\ ˜S|< Øl, ¸ ŒL øR£#r2 Ä b" ¤‚B äZ ”Cz: Ôj* ´ ŠJ ôV@3v6 Ìf& ¬†F ì ^ œc~> Ün. ¼ŽN ü`Qƒq1  a! ¢A âY ’;y9 Òi) ² ‰I òU+u5 Ê e% ª…E ê] šS}= Úm- º M úSÃ#s3 Æ c# ¦ƒC æ[ –C{; Ök+ ¶ ‹K öW@3w7 Îg' ®‡G î _ žc? Þo/ ¾O þ`Psp0 Á ` ¡€@ áX ‘;x8 Ñh( ±ˆH ñTã+t4 É d$ ©„D é\ ™S|< Ùl, ¹ ŒL ùR£#r2 Å b" ¥‚B åZ •Cz: Õj* µ ŠJ õV@3v6 Íf& ­†F í ^ c~> Ýn. ½ŽN ý`Qƒq1 à a! £A ãY “;y9 Ói) ³ ‰I óU+u5 Ë e% «…E ë] ›S}= Ûm- » M ûSÃ#s3 Ç c# §ƒC ç[ —C{; ×k+ · ‹K ÷W@3w7 Ïg' ¯‡G ï _ Ÿc? ßo/ ¿O ÿA@!  @a`10  Á@     ‹T$3É;ÑtO‹B;ÁtH‰H‰J‰J‰JÇB0‰‰H‰H ‰H ‰H(‰H,‰H0‰H8‰H<ˆ0Ç@€‰Hl‰HP‰HL3À¸þÿÿÿÂa‹D$…ÀtJ‹@…ÀtC‹L$ƒùV0‹P<4 ƒþ w%W¿Óç‹L$‰p Ün. ¼ŽN ü`Qƒq1  a! ¢A âY ’;y9 Òi) ² ‰I òU+u5 Ê e% ª…E ê] šS}= Úm- º M úSÃ#s3 Æ c# ¦ƒC æ[ –C{; Ök+ ¶ ‹K öW@3w7 Îg' ®‡G î _ žc? Þo/ ¾O þ`Psp0 Á ` ¡€@ áX ‘;x8 Ñh( ±ˆH ñTã+t4 É d$ ©„D é\ ™S|< Ùl, ¹ ŒL ùR£#r2 Å b" ¥‚B åZ •Cz: Õj* µ ŠJ õV@3v6 Íf& ­†F í ^ c~> Ýn. ½ŽN ý`Qƒq1 à a! £A ãY “;y9 Ói) ³ ‰I óU+u5 Ë e% «…E ë] ›S}= Ûm- » M ûSÃ#s3 Ç c# §ƒC ç[ —C{; ×k+ · ‹K ÷W@3w7 Ïg' ¯‡G ï _ Ÿc? ßo/ ¿O ÿA@!  @a`10  Á@     ‹D$S3Û;į€81…¦ƒ|$8…›UV‹t$;óW„€‹l$;ëtx‹|$ƒÿ|oƒÿj9^ ‰^u ÇF ‰^(9^$uÇF$‹F(h0%jPÿV ƒÄ ;Ãu _^]¸üÿÿÿ[‰F‹Ï‰x$º_Óâ^‰h4‰X0‰X,]Ç@€‰P(3À[Â_^]¸þÿÿÿ[¸úÿÿÿ[ÂSbÇÇ@LÇ@T Ç@PÇ@Xà  ‹D$ƒì SU3í;Å„Y‹X;Ý„N‰hÇ ‰k‰k,‹;ÍVW‰L$t‹pë3ö‹C4‹K(‰D$ ‹ƒè ƒø‰t$‰l$‰L$‡¤ ë ¤$I¶ÿ$•‹C…Àt‹T$‹ýƒç‹ÏÓê+ïljT$éW ƒýsF…öu‹L$ G †:˜9¹:Ë6á3÷3,:>0¥,Ý+É (½ %k "|H€?„;ˆ-Œ”¬F°E´D¸Cinvalid distance too far backinvalid distance codeinvalid literal/length codetoo many length or distance symbolsinvalid distances setinvalid bit length repeatinvalid literal/lengths setinvalid code lengths setinvalid stored block lengthsinvalid block type¼ V‹t$…öt%‹N…Ét‹F$…ÀtQ‹N(QÿЃÄÇF3À^¸þÿÿÿ^Â7O.fileþÿg\zlib-1.2.3\infback.c@comp.id _ÿÿ@feat.00ÿÿ.drectveX.debug$S}.rdata¦Ìô0I€ >.textÇ…«[ _zcfree _zcalloc .debug$F.text»ž×p .debug$F.text¼! óÒ} $L75376$L75375e$L753725.rdata ,Ͻ .rdata °–~æÇ .rdata yÔ*÷ .rdata $;Ïù. h $L75206S.rdata poã;v .rdataÚÜL¦.rdataÄ€I÷Û.rdata—eF $L75001ô.rdata3 «BU$L74959‰.rdata£.e*$L74951i$L74950T$L74949#$L74948$L75533¬$L74916~$L75532|$L75500˜.debug$F.text7œ4ó¹ .debug$FË?order@?1??inflateBack@@9@9?distfix@?1??fixedtables@@9@9?lenfix@?1??fixedtables@@9@9_inflateBackInit_@20_fixedtables_inflateBack@20??_C@_0BO@ECPMAOGG@invalid?5distance?5too?5far?5back?$AA@??_C@_0BG@LBKINIKP@invalid?5distance?5code?$AA@??_C@_0BM@FFFLPBBC@invalid?5literal?1length?5code?$AA@??_C@_0CE@GMIGFPBB@too?5many?5length?5or?5distance?5symb@_inflate_fast??_C@_0BG@GMDFCBGP@invalid?5distances?5set?$AA@??_C@_0BK@BMMPFBBH@invalid?5bit?5length?5repeat?$AA@??_C@_0BM@IIMGAINC@invalid?5literal?1lengths?5set?$AA@??_C@_0BJ@HDEPPGOH@invalid?5code?5lengths?5set?$AA@_inflate_table??_C@_0BN@LGAADGOK@invalid?5stored?5block?5lengths?$AA@??_C@_0BD@PJCBIDD@invalid?5block?5type?$AA@_inflateBackEnd@4/239 1121701590 100666 12466 ` L>ÖÎÛBà ¾.drectveXÄ .debug$Sz @B.rdata– @0@.textbž  P`.debug$F $ @B.textf. ”  P`.debug$F¨ ¸ @B.textM  P`.debug$F} @B.text¦— = P`.debug$F—§@B.textR± P`.debug$F@B.textÊç P`.debug$F@B.textmŒ P`.debug$Fªº@B.text,Äð P`.debug$Fú @B.text)= P`.debug$FGW@B.textÉa* P`.debug$F>N@B.text4XŒ P`.debug$F °@B.textaº P`.debug$F9I@B.text2S P`.debug$F…•@B.textŸ P`.debug$F¸È@B.text*Òü P`.debug$F@B.text8 X P`.debug$F€@B.textIšã P`.debug$F @B.text %E P`.rdata©@0@.rdata¬@@.debug$F­½@B.text#Çê P`.debug$Fô@B.textAO P`.rdataù@0@.rdata@0@.debug$F$@B.text.D P`.debug$FN^@B.text>h¦ P`.rdataÄ@0@.debug$FÌÜ@B.textœæ‚ P`.debug$Fð@B.text$ . P`.debug$F8H@B.textVR¨ P`.debug$F²Â@B.text‰ÌU  P`.debug$F‘ ¡ @B.text« ¼  P`.debug$FÆ Ö @B/DEFAULTLIB:"uuid.lib" /DEFAULTLIB:"uuid.lib" /DEFAULTLIB:"LIBC" /DEFAULTLIB:"OLDNAMES" : 3x:\zlib-1.2.3\contrib\vstudio\vc7\zlibstat\gzio.obj8   !Microsoft (R) Optimizing Compiler‹V‹t$…ötP€~\wuJ‹F…Àu/‹N@‹FHQh@jP‰F èƒÄ=@tÇF8ÿÿÿÿÇF@‹T$‹D$ RPVè^ ¸þÿÿÿ^ )Qb‹F<…ÀtƒÈÿËF…ÀuFÇ‹F@‹NDPh@jQèƒÄ…À‰Fu‹V@ÇF<ŠJ ƒÈÿöÁ t‰F8ËFD‰ÿN‹Š@‰¶ÁÃ,fV‹ð‹Nƒùs`…Ét ‹‹VDŠˆÇ‹V@R‹VD¸@ÓøÑPjRèƒÄ…Àu‹N@öA tÇF8ÿÿÿÿ‹VЋƒø‰V‹VD‰s‰FX^Ë€8…΀x‹…Ä‹NSƒÁþƒÀW‰N‰è‹øèƒÿ‹Ø…’öÃà…‰¿èOuøöÃt"è‹øèÁàø‹ÇO…Àt èƒøÿuïöÃt¤$è…ÀtƒøÿuòöÃtè…ÀtƒøÿuòöÃt¿ëIèOuø‹N<÷ÙÉ_ƒáý[‰N8^Ã_[ÇF8ýÿÿÿ^ÃÇFX^Ã7‘˜¶ÃÊÛñ!MW3ÿ…öu¸þÿÿÿ_ËFP…Àt PèƒÄ‹F…ÀtŠF\‹D$ƒøÿt5ƒylÿu/‹QhJW‹y8‰Qh3Òƒÿ”‰Al_…Ò‰QptÇA8ÇA<ƒÈÿÂR*V‹t$…ö„´€~\w…ªU‹l$W‹|$…ÿ‰.‰~t|›‹F…Àu$‹N@‹FHQh@jP‰F èƒÄ=@uG‰F‹V‹Fd‹Vh‰Fd‹FjÐV‰Vhè‹N‹Vd+Ñ‹Nh‰Vd‹V+Ê…À‰F8‰Nhu‹F…Àu“ëÇF8ÿÿÿÿ‹FLWUPè‹N‰FL‹Ç_]+Á^ ¸þÿÿÿ^ Ju1­0Ê/¸苌$„$ PQT$hRÆ„$èƒÄ…À~,=}%ŠŒ$ÿ„Éu‹Œ$PD$PQèÄÃ3ÀÄÃ8-7Y/m 6‹T$ŠD$jL$ QRˆD$èƒøu¶D$ƒÈÿÂ/,=‹T$‹ÂVp›Š@„Éuù+ÆP‹D$ RPè^Â!/)BSV‹ð3Û…ö„³€~\w…©‰^Wd$‹F¿@+øt$‹F@‹NHPWjQèƒÄ;Çut‹VH‰V ÇF@…ÛuS‹^h‹L$‹FQØV‰^hè‹^h‹N+Ù…ÿ‰F8‰^huƒøûu‰~8…Éu ƒ~8t3Û뻋F8…Àt‚ƒø„yÿÿÿ‹v8‹ÆH÷ØÀ_#Æ^[ÃÈÿ_‰F8^[Ã^¸þÿÿÿ[Ã8f1ÉG‹D$V‹t$P‹ÆèƒÄ…Àu‹N@Qè‹N8ƒÄ‹ÁH÷ØÀ#Á^ GM4LV‹t$W3ÿ;÷tM€~\ruG‹FDWWW‰~8‰~<ÇFlÿÿÿÿ‰~‰è‰FL9~XuVè‹N`‹V@WQR‰~d‰~hèƒÄ _^Â_ƒÈÿ^Â+09TMSaR‹D$…Àt%€x\ru‹H<…Ét¸Â‹P83Ƀú”Á‹ÁÂ3ÀÂ2Y‹D$…Àt €x\ru‹@XÂ3ÀÂ^VW‹ð¿¤$‹Æ%ÿSPèƒÄÁîOué_^Ãd*cVW‹ðè‹øèÁàøèÁàøèƒøÿuÇF8ýÿÿÿÁàÇ_^à  8iV‹t$…öu ¸þÿÿÿ^€~\wu(j‹ÆèƒÄ…Àu‹FLS‹^@è‹Fd‹^@è[è^ÂG0c;cA!InS‹\$…Ûu‹D$ Çþÿÿÿ¡[‹C8…À‹L$ ‰u ¸[ƒøÿUu‹RèƒÄ‹èë‹k…ít€}u‹C8Áà¹+È‹)‹CP…Àt PèƒÄ‹CTPIŠ@„Éuù+‹ЋÅVpŠ@„Éuù+ÆTRèƒÄ…À‰CPu ¡^][‹STd$Š Bˆ@„ÉuöW‹{POŠGG„Àuøf¡f‰Š ‹ÅˆO‹È‹ÿŠ@„Òuù‹{P+Á‹ñOŠOG„Éuø‹ÈÁéó¥‹Èƒáó¤‹CP_^][Â|*{:@x_|p% w¯|Úvãv: s‹D$3É;Átƒx8t‰H8‰H<‹@@PèY‚#ƒìXSL$ U3Û‰L$ ‹L$dƒÍÿ;ËW‰\$ ‹ø„;Ä Vjtè‹ðƒÄ;ó„1SSS‰^ ‰^$‰^(‰^D‰‰^H‰^ ‰^‰^‰^@‰^8‰^<‰^d‰^h‰nlè‰FL‹D$l‰^P‰^XPŠ@:Ëuù+Â@PèƒÄ;ÉFT„Ê‹L$l‹Ð›ŠAˆB:Ãuöˆ^\±r8uˆN\Š> ‹D$U‹l$…íV‹ð„~€}\r…t‹M8ƒùý„`ƒÊÿ;Ê„Uƒùu^3À] SW‹|$…ÿ‹Ø‰E ‰}t<‹Ml;Êt5ˆ‹u‹MhX‹E @N‰E ‹EpA…À‰u‰Ul‰Mh‹ót_[¸^‰E8] ‹E…À„´›‹EX…À… ‹E…ÀuI‹E<…ÀuBÇ‹U@‹EDRh@jPèƒÄ…À‰Eu‹M@ÇE<öA …R‹UD‰U‹Md‹E‹UhȉMd‹MjÑU‰Uhè‹U‹Md+Ê‹Uh‰Md‹M+уø‰E8‰UhuO‹U ‹EL+ÖRVPè‹u ‰EL‹Åè;ELuS‹Åè‹Åè‹E8…À…ÜUèjjjè‰EL‹E8…À…½‹E<…À…²‹E…À…ùþÿÿé¢ÇE8ýÿÿÿé–‹E‹M;Áv‹Á…Àv7‹u‹} ‹È‹ÑÁéó¥‹Êƒáó¤‹u‹U‹M‹|$Øð+Ð+ȉ] ‰u‰U‰M‹E…Àv‹M@QPjSè‹MƒÄ+ȉM‹u‹Ud‹Mh+þ×Ï…ÿ‰Ud‰MhuÇE<‹Ç_[^] ÇE8ÿÿÿÿ‹U ‹EL+ÖRVPè‹M;ù‰ELu‹m8ƒýýtƒýÿu _[^ƒÈÿ] ‹Ç_[^+Á] ^ƒÈÿ] ^¸þÿÿÿ] »Ó§C0Pi\ictT0Z0œ ¦‹L$jD$PQèƒøu¶D$ƒÈÿ ¦$¬UV‹t$…öW‹îtA‹|$…ÿ~9S‹\$›O…ÿ~jVSèƒøuŠF< uæ;îÆ[u…ÿ_^‹Å] _^3À] *¦V ±V‹t$…ö„u‹L$ƒù„h‹F8ƒøÿ„\ƒøý„S€~\wWus…ÉS‹\$u+^d…Û} [_ƒÈÿ^ ‹FD…Àuh@è‹øƒÄ…ÿ‰~DtÚ¹3Àó«…Û~'¤$¸@;Ø}‹ÃP‹FDPVè…Àt¬+Ø…Ûà‹Fd[_^ ƒù‹|$u~h…ÿ}_ƒÈÿ^ ‹FX…Àt3‹V@‹NDjWRÇFlÿÿÿÿÇF‰èƒÄ …À|ˉ~h‰~d‹Ç_^ ‹Fh;ø|+øë Vè…À|©…ÿtf‹FH…Àuh@èƒÄ…À‰FHtŠƒ~lÿt‹Vh‹FpBO…ÀÇFlÿÿÿÿ‰VhtÇF8…ÿ~$¸@;ø}‹ÇP‹FHPVè…ÀŽEÿÿÿ+ø…ÿÜ‹Fh_^ ƒÈÿ^ \w’/ãSR!wh¦‰¶‹D$jjPè ¶».fileþÿg\zlib-1.2.3\gzio.c@comp.id _ÿÿ@feat.00ÿÿ.drectveX.debug$Sz.rdata½ß.textbî}:  _fwrite .debug$F.textfœt†40 _fread _errno.debug$F.textM I‰ï: .debug$F .text ¦ }¡åM_destroy _fclose H V _free .debug$F  .text R4UlŸd .debug$F  .textÊ“‚?tp | † .debug$F.textmûžØã‘ › __chkstk .debug$F.text,ý2ˆ§ .debug$F.text)`ñ‰&± .debug$F.textÉj9…-» .debug$F.text4h›éãÅ _fflush .debug$F.textax#;)Ð _fseek Ü .debug$F.text2Oæ˜ _gzeof@4 .debug$F.textO þì .debug$F.text *­ìì_putLong _fputc .debug$F! .text"8ˆÇ¸ñ_getLong" .debug$F#".text$I¯!ø$ .debug$F%$.text&  àbþ & .rdata'äDx¼'_malloc ) .rdata(3(J.debug$F)&.text*#rįT* b .debug$F+*.text,A:u%_gz_open, _ftell _fprintf .rdata-'©úçl-__fdopen _fopen · É .rdata.{M-Û..debug$F/,.text0ö®¢€ù0 .debug$F10.text2>,[Ú¢2 _sprintf .rdata3 õÛ3.debug$F42.text5œ gqt&65 A .debug$F65.text7$·Ãö·L7 .debug$F87.text9Vôj¥KV9 .debug$F:9.text;‰špa; .debug$F<;.text=Jw'l= .debug$F>=v_gz_magic_gzsetparams@12_deflateParams@12_get_byte_check_header_inflateEnd@4_deflateEnd@4_gzungetc@8_gzwrite@12_crc32@12_deflate@8_gzprintf__vsnprintf_gzputc@8_gzputs@8_do_flush_gzflush@8_gzrewind@4_inflateReset@4_gzdirect@4_gzclose@4_gzerror@8??_C@_02LMMGGCAJ@?3?5?$AA@_strerror??_C@_00CNPNBAHC@?$AA@_z_errmsg_gzclearerr@4_clearerr??_C@_0BF@FJABJDFD@?$CFc?$CFc?$CFc?$CFc?$CFc?$CFc?$CFc?$CFc?$CFc?$CFc?$AA@_inflateInit2_@16_deflateInit2_@32??_C@_05GDHACFMB@1?42?43?$AA@_gzopen@8_gzdopen@8??_C@_07EBNKNFJN@?$DMfd?3?$CFd?$DO?$AA@_gzread@12_inflate@8_gzgetc@4_gzgets@12_gzseek@12_gztell@4/259 1121701590 100666 1235 ` LÖÎÛB¬.drectveX, .debug$S~„@B.data@0À.text P`.debug$F2B@B.text(Lt P`.debug$F’¢@B/DEFAULTLIB:"uuid.lib" /DEFAULTLIB:"uuid.lib" /DEFAULTLIB:"LIBC" /DEFAULTLIB:"OLDNAMES" > 7x:\zlib-1.2.3\contrib\vstudio\vc7\zlibstat\gvmat32c.obj8   !Microsoft (R) Optimizing Compilerè%=À@£Ã ¡…Àu‹D$x4ÿt ‰D$é‰D$é $(.fileþÿg\zlib-1.2.3\contrib\masmx86\gvmat32c.c@comp.id _ÿÿ@feat.00ÿÿ.drectveX.debug$S~.data‹È ª_iIsPPro.textÇŠþç  .debug$F.text(¶Ê¢ , @ .debug$FS_match_init_cpudetect32_longest_match_longest_match_7fff_longest_match_686 /283 1121701590 100666 14216 ` L-ÖÎÛB,….drectveX .debug$S}t@B.rdata¶ñ§ @@@.text   P`.debug$F - @B.text)7 P`.debug$F` p @B.text@z P`.debug$Fº Ê @B.textAÔ P`.debug$F % @B.text:/ i  P`.debug$Fs ƒ @B.text' P`.debug$F´ Ä @B.textdÎ P`.debug$F2 B @B.textLL ˜ P`.debug$FºÊ@B.textÌÔ P`.debug$F °@B.textªºd P`.debug$Fn~@B.texttˆü P`.debug$F @B.text‘*» P`.debug$Fíý@B.textÀ P`.debug$FÇ×@B.text áî P`.debug$Fø@B.text# P`.debug$FUe@B.textšo " P`.debug$Fc"s"@B.text}"•& P`.debug$F ''@B.text’''¹' P`.debug$Fá'ñ'@B.textØû'Ó( P`.debug$F)))@B.text<3)o+ P`.debug$F¡+±+@B.text$»+ß+ P`.debug$Fé+ù+@B/DEFAULTLIB:"uuid.lib" /DEFAULTLIB:"uuid.lib" /DEFAULTLIB:"LIBC" /DEFAULTLIB:"OLDNAMES" = 6x:\zlib-1.2.3\contrib\vstudio\vc7\zlibstat\deflate.obj8   !Microsoft (R) Optimizing Compiler deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly   €€ € € 1.2.3@]LcXcdcpk|kˆk”k k¬k‹D$…ÀSUVW‹|$‹ï„æ‹X…Û„Û‹t$…ö„Ï‹Kƒù„Ãùu ƒ{*…´‹K…Ét‹@0WVPè‹L$‰A0ƒÿ‚‰‹C,úþÿÿ;øv‹è+ý÷‹{8‹Í‹ÑÁéó¥‹Êƒáó¤‹S8‹KX‰kl‰k\¶‰CHÓà¶J3Á#CT‰CH3Òuý‹{H‹KX‹C8¶D‹k4Óç‹KT3Ç#Á‹KD‰CHf‹A‹ú#ý‹k@f‰D}‹KH‹CDf‰HB;ÖvÁ_^]3À[ _^]¸þÿÿÿ[ V ‹D$…Àt‹@…Àtƒxu ‹L$‰H3À¸þÿÿÿÂ)‹D$…Àt0‹H…Ét)‹Ñ‹L$‰Š¼‹@ºÓâ‹L$ J#Ñf‰¸3À ¸þÿÿÿ @‹D$…Àt1‹@…Àt*‹L$‹T$ ‰ˆŒ‹L$‰€‹T$‰ˆ‰P|3À¸þÿÿÿÂA ‹T$B?ÁèJÁéÂD ‹L$…Ét‹I…Étƒy0u ƒyPuRèÂ3&:%V‹p‹ÑW‹xÁêˆ>‹P‹pB‰Pˆ 2‹HA_‰H^Ã'+‹HV‹p‹V;Ñv‹Ñ…ÒtN‹vSW‹x ‹Ê‹ÙÁéó¥‹Ëƒáó¤‹x ‹Hú‰x Q‹X‹x‹HÚ‰X+ú‰x)Q‹@‹H…É_[u‹H‰H^Ãd0U‹l$…íV„4‹u…ö„)‹L$ƒù…ÉŒ‹E …À„ƒ}u ‹E…À…ð‹F=šu ƒù…Ý‹U…Òu¡‰E^¸ûÿÿÿ]ƒø*‹V(SW‰.‰T$‰N(»…Ë9^…)jjjè‰E0‹N‹FÆ‹F‹V@‰FÆ‹‹~‹NG‰~‹ÇÆ‹V‹FB…À‰V‹ú…–‹Vˆ‹~‹NG‰~‹ÇÆ‹VB‰V‹Â‹VÆ‹NA‰N‹Á‹NÆ‹F‹V@‰FÆ‹~‹†„Gƒø ‰~‹Ïu‹Ãë9žˆ};Ã|3À븋Vˆ‹NA‰N‹Á‹NÆ ÿFÇFqéâ‹P$‹H,…Ò”Âþʃâ…É”ÁþÉ#ËÑ‹H…É”ÁþɃáÑ‹H…É”ÁþɃáу8‹N•ÀЈ‹~‹V‹NG‰~ŠR‹Çˆ‹V‹NB‰VŠI‹Â‹Vˆ ‹N‹VA‰NŠR‹Á‹Nˆ‹F‹N‹V@‰FŠIˆ ‹~‹†„Gƒø ‰~‹Ïu‹Ãë9žˆ};Ã|3À븋Vˆ‹^‹N‹VC‰^ŠI ‹Ãˆ ‹~‹FG‰~‹P…Ò‹Ït'Š@‹Vˆ‹N‹VA‰N‹Á‹NŠIˆ ‹F@‰F‹È‹V‹B,…Àt‹FQ‹M0PQè‰E0ÇF ÇFE陋N0‹†ˆƒéÁá Á;Ã}$‹†„;Ã|ƒø}¸ë3Òƒø•ÂÓ‹Âë3ÀÁà È‹Fl…ÀtƒÉ ‹Á3Ò¿÷÷‹ÆÇFq+ÊÏè‹Fl…Àt·M2‹Æè‹M0áÿÿèjjjè‰E0ƒ~E…Í‹F‹H…É„¸‹@‹V ‹N%ÿÿ;Ðsn‹F;F u4‹V‹z,…ÿt;Áv+ÁP‹FÁ‹M0PQè‰E0‹Åè‹F;F ‹Èt2‹V‹R‹~ Š:‹^ˆ‹F‹^ @C‰F‰^ ‹F‹Pâÿÿ‹Ã;Âr’‹F‹P,…Òt‹F;Áv‹V+ÁP‹E0ÑRPè‰E0‹N‹V ;QuÇF ÇFIƒ~I…«‹F‹H…É„–‹~‹F;F u4‹N‹Q,…Òt;Çv‹V+ÇP‹E0×RPè‰E0‹Åè‹F;F ‹øt$‹N ‹V‹R¶ A‰N ‹Nˆ‹NA…Û‰Nu¢ë»‹V‹B,…Àt‹F;Çv‹M0+ÇP‹FÇPQè‰E0…Ûu ‰^ ÇF[ƒ~[…§‹V‹B$…À„’‹~‹F;F u4‹N‹Q,…Òt;Çv‹V+ÇP‹E0×RPè‰E0‹Åè‹F;F ‹øt$‹N ‹V‹R$¶ A‰N ‹Nˆ‹NA…Û‰Nu¢ë»‹V‹B,…Àt‹F;Çv‹M0+ÇP‹FÇPQè‰E0…ÛuÇFgƒ~gub‹V‹B,…ÀtQ‹F‹N ƒÀ;Áv‹Åè‹F‹V H;Êw7ŠM0‹Vˆ ‹^‹VC‰^ŠM1‹Ãˆ ‹~jjGj‰~è‰E0ÇFq‹F…Àt‹Åè‹E…Àu;ÇF(ÿÿÿÿ_[^3À]‹E…À‹\$u$;\$ƒût‹_[^‰U¸ûÿÿÿ]‹\$‹F=š‹Mu…Ét¡_[‰E^¸ûÿÿÿ]Â…Éu‹Nt…Éu…Û„¢=š„—‹†„S @VÿƒÄƒøtƒøuÇFš…À„Xƒø„Oƒøu[;Øu VèƒÄë:jjjVèƒÄƒûu&‹VL‹FDfÇDPþ‹NL‹~DL þ‹ÑÁé3Àó«‹Ê#Ëóª‹Åè‹E…À„çþÿÿƒû…åþÿÿ‹F…À _[^¸]ƒø…‹NŠU0‹Fˆ‹V‹NB‰V‹ÂŠU1ˆ‹NA‰NŠU2‹Á‹Nˆ‹F‹N@‰FŠU3ˆ‹^‹NC‰^ŠU‹Ãˆ‹~‹NG‰~ŠU ‹Çˆ‹V‹NB‰V‹ÂŠU ˆ‹NA‰NŠU ‹Á‹NˆÿFë·M2‹Æè‹M0áÿÿè‹Åè‹F…À~÷؉F‹N_[3À…É^”À]‹E…À…ôýÿÿ_[ÇF(ÿÿÿÿ^3À]¡‰E^¸þÿÿÿ]Âe9¢8ª8++=+K+V«8µ08t8~0Ô8(820ˆ8º0ô8 0?9h9§ Û7ì6!0é+÷+þ0;9L5V‹t$…ö„¶‹F…À„«W‹xƒÿ*t+ƒÿEt&ƒÿIt!ƒÿ[tƒÿgtƒÿqtÿšt _¸þÿÿÿ^‹@…Àt P‹F(PÿV$ƒÄ‹N‹AD…Àt ‹V(PRÿV$ƒÄ‹F‹@@…Àt ‹N(PQÿV$ƒÄ‹V‹B8…Àt P‹F(PÿV$ƒÄ‹N‹V(QRÿV$ƒÄ3Àƒÿq•À_ÇF^Hƒàý¸þÿÿÿ^ÂÌ>UV‹t$…ö„’‹l$ …턆‹F…À‰D$„wSW¹‹ýhÀó¥‹E(jPÿU ‹ØƒÄ …Û„E‹t$‰]¹°‹ûó¥‹K,j‰+‹U(QRÿU ‰C8‹C,‹M(jPQÿU ‹SLj‰C@‹E(RPÿU ‹‹œj‰CD‹U(QRÿU ‹{8ƒÄ0…ÿ‰C„Ü‹K@…ɄыKD…ɄƅÀ„¾‹K,‹T$‹r8Ñá‹éÁéó¥‹Íƒáó¤‹r@‹K,‹{@Ñá‹éÁéó¥‹Íƒáó¤‹rD‹KL‹{DÑá‹éÁéó¥‹Íƒáó¤‹r‹K ‹{‹éÁéó¥‹Íƒáó¤‹z‹J‹s+ÏΉK‹‹œ‹ÑÑêPNщƒ¤‰“˜ƒ”‹ˆ “| _‰ƒ ‰‹$ ‰“0 [^3À]ÂUè_[^¸üÿÿÿ]Â^¸þÿÿÿ]Â>ªC‹CU‹è;év‹é…íu3À]Ã+ʼnC‹C‹@ƒøu‹ ‹S0UQRèëƒøu‹‹K0UPQè‰C0V‹3W‹|$‹Í‹ÑÁéó¥‹Êƒáó¤‹C‹ Å_͉C^‹Å‰ ]Ã-A8tH‹B,‹JLÑà‰B<‹BDSV3öf‰tHþ‹JLL þ‹ÙÁéW‹zD3Àó«‹Ëƒá󪋂„@Áà·ˆ‰Š€·ˆ‰ŠŒ·ˆ‰Š·€_‰B|‰rl‰r\‰rt¸‰rh‰rH^‰Bx‰B`[éA N [ h N‘$M‹N8‹FlSŠU‹l$ Š)ÁÍ:ÓW¸…’ŠQ:P…†ƒÀƒÁŠPŠY@A:ÓuXŠPŠY@A:ÓuLŠPŠY@A:Óu@ŠPŠY@A:Óu4ŠPŠY@A:Óu(ŠPŠY@A:ÓuŠPŠY@A:ÓuŠPŠY@A:Óu;Çrœ+ǃø|‹Nt;Á‰npv _]‹Á[ø_][ÃÀSSU‹l$ ‹E,VW‰D$ë‹D$‹Ut‹]<‹Ml+Ú‹U,”úþÿÿ+Ù;Êro‹}8‹È‹ÑÁé4ó¥‹Êƒáó¤‹up‹Ul‹M\+ð+Ð+ȉup‹uL‰M\‹MD‰Ulq·Jþƒê;Èr+Èë3ÉNf‰ ué‹U@‹ðB·Jþƒê;Èr+Èë3ÉNf‰ u騋E‹H…Ét_‹Mt‹Ul‹}8ÊÏQ‹Ë‹Øè‹Mtȋуăú‰Mtr ‹El‹M84¶‹MX‰EHÓà¶N3Á#ET‰EHús‹U‹B…À… ÿÿÿ_^][üH XQS‹\$ ‹C UƒÀû=ÿÿVWÇD$ÿÿs‰D$‹CtƒøwSè‹CtƒÄ…À„h‹KlÈ‹D$‰Kl‹K\‹SlÇCtt;Ђ–+ЅɉSt‰Cl|‹S8Ñë3Òj+ÁPRSè‹Kl‹‰K\‹p‹V‹HƒÄ;Ñv‹Ñ…ÒtJ‹v‹x ‹Ê‹éÁéó¥‹Íƒáó¤‹x ‹Hú‰x Q‹h‹x‹Hê‰h+ú‰x)Q‹@‹H…Éu‹P‰P‹‹H…É„¤‹S\‹Kl‹C,+Ê-;È‚ÿÿÿ…Ò|‹C8Âë3ÀjQPSè‹Kl‹‰K\‹p‹V‹HƒÄ;Ñv‹Ñ…ÒtJ‹v‹x ‹Ê‹éÁéó¥‹Íƒáó¤‹x ‹Hú‰x Q‹h‹x‹Hê‰h+ú‰x)Q‹@‹H…Éu‹P‰P‹‹H…É…„þÿÿ_^]3À[YË|$…ÿtð‹s\…ö|‹C8Æë3À‹Sl3Ƀÿ”Á+ÖQRPSè‹Cl‰C\‹ƒÄè‹ ‹A…Àu3Àƒÿ•À_^][HƒàYÃ3Àƒÿ”À_^][DYÃ,X^%^Ð^à0]QSU‹l$VW3ÿ‰|$‹\$‹Et=s#Uè‹EtƒÄ=s…Û„õ…À„õƒørO‹EH‹MX‹Ul‹u4Óà‹M8¶L3Á#ET‹MD‰EHf‹A#ò‹U@f‰r‹E4‹Ml‹U@#È·ÇF‰n,‰VX‹W(URÿW ‰F8‹F,‹O(jPQÿW ‹VLj‰F@‹G(RPÿW ‰FDK¸Óàj‰†œ‹O(PQÿW ‹Žœ‰V ‹V8ƒÄ0…Ò‰FtO‹V@…ÒtH‹VD…ÒtA…Àt=‹ÑÑêPHÁ‹L$‰–¤‹T$(W‰†˜‰Ž„‰–ˆÆF$è^[_] ÇFš¡W‰Gè^[_¸üÿÿÿ] [_¸þÿÿÿ] ¸úÿÿÿ] F}U|üp9>< {‹D$‹L$ ‹T$P‹D$QjjjjRPèÂ{$‚.fileþÿg\zlib-1.2.3\deflate.c@comp.id _ÿÿ@feat.00ÿÿ.drectveX.debug$S}.rdata¶ Q¥Y°'8<.text­6@O h .debug$F.text)§·ift .debug$F.text@6Ï=Ûˆ .debug$F .text A…8µm™ .debug$F  .text :A[¸© ¹ .debug$F  .text'a‘Ê .debug$F.textdɼ$K× .debug$F.textL®ÕNæ ñ   .debug$F.textÌ«qŽå" .debug$F.textª>9k0 .debug$F.textt½»TR? .debug$F.text‘Kçͱ_lm_init I .debug$F.textÀ¢ô óU .debug$F.text Ù­ i .debug$F.text {ø\v † .debug$F! .text"š ¾l —" ¥±¿ .debug$F#".text$ ÎÊÎ$ .debug$F%$.text&’Éâð Ü& ì .debug$F'&.text(ذ³ Ùö( .debug$F)(.text*<KÙn>* _zcfree _zcalloc .debug$F+*.text,$Ðjm ¨Zjz Ïäÿ “'® ±ž}D“ðÒ£‡hòþÂi]Wb÷Ëge€q6lçknvÔþà+Ó‰ZzÚÌJÝgoß¹ùùホC¾·Õް`è£ÖÖ~“Ñ¡ÄÂØ8RòßOñg»ÑgW¼¦Ýµ?K6²HÚ+ ØL ¯öJ6`zAÃï`ßUßg¨ïŽn1y¾iFŒ³a˃f¼ Òo%6âhR•w ÌG »¹"/&U¾;ºÅ( ½²’Z´+j³\§ÿ×Â1Ïе‹žÙ,®Þ[°Âd›&òc윣ju “m© œ?6ë…grW‚J¿•z¸â®+±{8¶ ›ŽÒ’ ¾Õå·ïÜ|!ßÛ ÔÒÓ†BâÔñø³ÝhnƒÚ;[&¹öáw°owG·æZˆpjÿÊ;f\ ÿžei®bøÓÿkaEÏlxâ  îÒ ×TƒN³9a&g§÷`ÐMGiIÛwn>JjÑ®ÜZÖÙf ß@ð;Ø7S®¼©Åž»ÞϲGéÿµ0ò½½ŠÂºÊ0“³S¦£´$6к“×Í)WÞT¿gÙ#.zf³¸JaÄh]”+o*7¾ ´¡Ž ÃßZï-A1‚b62ÃS-+ÅldEôw}†§ZVÇ–AOŠÙÈI»ÂÑŠèïúËÙôã Oµ¬M~®µŽ-ƒžÏ˜‡QÂJ#ÙSÓpôx’AïaU×®.æµ7×µ˜–„ƒY˜‚©›Ûú-°šË6©]]wællÿß?AÔžZÍ¢$„•㟌 F²§aw©¾¦áèñçÐóè$ƒÞÃe²ÅÚª®]]ëŸFD(Ìkoiýpv®k19ïZ* ,  m8ó6Fß²]ÆqTpí0ekô÷ó*»¶Â1¢u‘‰4 û¼Ÿº„yÞ©%8ï²<ÿyós¾Hèj}ÅA<*ÞXOyðD~bé‡-OÂÆTÛŠ”@»ƒè#¦ÂÙ8¿ Å 8Lô»!§– Ζ Ì\H1×E‹búnÊSáwT]»ºl £Ö?ˆ—–‘P˜×Þ©ÌÇÒúáì“Ëúõ\×bræykÞµT@Ÿ„OYX#Úp8$›A#=§kýeæZæ|% ËWd8ÐN£®‘⟊!̧3`ý¼*¯á$­îÐ?´-ƒŸl² †«$HÉêSÐ)F~ûhweâöy?/·H$6t 5*ò¼SK³HRpÞey1ï~`þóæç¿Âýþ|‘ÐÕ= ËÌú6Šƒ»‘šxT¼±9e§¨K˜ƒ; ©˜"Éúµ ˆË®O]ï_lôFÍ?ÙmŒÂtCZó#AêÁplÁ€AwØG×6—æ-ŽÅµ¥„„¼ŠAq[»Zh˜èwCÙÙlZO-_~6 œ-'Ý>˜¹S1ƒ b®‹ÑSµ’ÅôÝWôïÄ”§ÂïÕ–Ùöé¼®¨·kÞ1œ*ï*…íykʬHpÓo]ø.*Fáá6Þf ÅcTèT"eóMåó²¤Â©g‘„0& Ÿ)¸®ÅäùŸÞý:ÌóÖ{ýèϼk©€ýZ²™> Ÿ²8„«°$,ñ52F*sw1´ápHõÐkQ6ƒFzw²]cN×úËæáÒ̵Ìù„×àJ–¯ #¶Èp ‰A»„F]#l8Ä?1…(B˜Og©T~ÀúyUËbLÅ8^ô#˜§³Ü–ªTåZ1Oü™bbרSyÎOáIV~úP•-×{ÔÌbŠ-R»–4‘è»ÐÙ ìó~^­ÂeGn‘Hl/ Suè6:© #jT$+e?äy§–¥H¼f‘¤'*нà¼Ëò¡ÐëbÞýÀ#ïæÙ½á¼üЧ ?ƒŠ&~²‘?¹$ÐpøËi;FæBzwý[µkeÜôZ~Å7 Sîv8H÷±® ¸ðŸ¡3Ì?Šrý$“7jÂnÔ„Y¾Fܨ ëÂ˲|…O¸Q;ÑÖ…— áïU dù S“Ø -ž =G\ p£&GÉäw¢)`¬ /›aíÂß«õµiÈò5ÿ˜÷¦&±‘LsZ<#0þzޏMäzàFM8×,9Ž’É;¹ø :<îD? „†>R:À(ôq-Ãv³,šÈõ.­¢7/Àšp÷çXq®Ys™3Ür%“w+OQvrñtE›Õux܉~O¶K }!bÏ|¤t€y“BxÊ zýÊÆ{°.¼l‡D~mÞú8oéúnl†µk[ìwjR1h58ói¯b?mcf«+aQÁé`Ôצeã½ddº"fiàg Ë×H¡INSKyu‘JücÞOË N’·ZL¥Ý˜M˜šÄF¯ðGöN@EÁ$‚DD2ÍAsX@*æIBŒ‹CPhñTg3U>¼uW Ö·VŒÀøS»ª:Râ|PÕ~¾Qè9âZßS [†ífY±‡¤X4‘ë]û)\ZEo^m/­_€5á·q÷àîϱâÙ¥sã\³<ækÙþç2g¸å zä8J&ï äîVž¢ìaô`íäâ/èÓˆíéŠ6«ë½\iêð¸ýÇÒÑüžl—þ©Uÿ,úzØûBÄžùu®\øHéóƒÂò&=„ðWFñ”A ô£+Ëõú•÷ÍÿOö`]xÙW7ºØ‰üÚ9ã>Û¼õqÞ‹Ÿ³ßÒ!õÝåK7ÜØ k×ïf©Ö¶ØïÔ²-Õ¤bÐ3ΠÑjpæÓ]$Òþ^Å'”œÄ~*ÚÆI@ÇÌVWÂû<•â‚ÓÁ•èÀ¨¯MËŸÅÊÆ{ÉÈñ ÉtDÌCm†ÍÓÀÏ-¹Î@–¯‘wüm.B+’(铜>¦–«Td—òê"•Å€à”øÇ¼ŸÏ­~ž–8œ¡yú$oµ˜w™J»1›}Ñóš05‰_KŒ^á Ži‹Ï쀊Û÷B‹‚I‰µ#ƈˆdšƒ¿X‚æ°€ÑÚÜTÌ“„c¦Q…:‡ rÕ† Ðâ©—º ¨Îfªùn¤«|xë®K)¯¬o­%Æ­¬ñ§/ë3¦vUu¤A?·¥Ä)ø óC:¡ªý|£—¾¢Ðsĵç´¾§@¶‰Í‚· ÛͲ;±³bI±Ue‹°h"×»_HºöS¸1œ‘¹´ŠÞ¼ƒà½Ú^Z¿í4˜¾eg¼¸‹È ªî¯µW—b2ðÞ7Ü_k%¹8×ï(´ÅŠO}dà½o‡׸¿ÖJÝØjò3wßàVcXŸWPú0¥èŸúqø¬BÈÀ{ß­§ÇgCru&oÎÍp­•-û·¤?žÐ‡'èÏBs¢¬ ưÉGz>¯2 [ÈŽµg; Ї²i8P/ _ì—âðY…‡—å=ч†e´à:ÝZOÏ?(3w†äêãwXR Øí@h¿Qø¡ø+ðÄŸ—H*0"ZOWžâöoI“õÇ}§@ÕÀümNП5+·#Å–Ÿ *'Gýº| A’ô÷èH¨=X›X?¨#¶1Ó÷¡‰jÏv¨Ê¬á¾„`ÃÒp ^·æY¸©ô<ßL…çÂÑà€~i/Ë{kHwâ ËÇh±s)ÇaL ¸Ùõ˜oDÿÓü~Pfî7ÚVM'¹(@¶Æï°¤£ˆ °Û×g9‘xÒ+ôn“÷&;fšƒˆ?/‘íX“)T`D´1ø ߨMºÏñ¦ìß’þ‰¸.Fg›Tp'ì»HðqÞ/LÉ0€ùÛUçEcœ ?kùǃÓh6ÁrŠyË7]ä®Pá\@ÿTN%˜èösˆ‹®ï7ø@‚'>¼$é!AxU™¯×à‹Ê°\3;¶Yí^ÑåU°~PGÕìÿl!;b F‡Úçé2È‚ŽŽpÔží(±ùQ_Vä‚:1X:ƒ §æn3Á† m¦:µ¤á@½Á†ü/)IJNõ¯óv"2–žŠx¾+˜Ù— KÉôx.®HÀÀýÒ¥fAj^–÷y9*O—–Ÿ]òñ#åkM`~×õŽÑbçë¶Þ_RŽ Â7éµzÙFh¼!¼Ðê1߈Vc0aùÖ"žj𽦽ØÁ¿6n´­S šNrÿ)Î¥†{·táÇÍÙ’¨¾¬*F8#v¥€ufÆØz`þ®Ïr›ÉsÊ"ñ¤WG–ï©9­ýÌ^EîMvc‰ñÎ&DÜèAødQy/ù4“AÚ±&S¿ÖšëéÆù³Œ¡E bðiL¡¾Q›<Û6'„5™’–Pþ..™¹T&üÞèžq]Œwá4Î.6©«IŠEæ? ƒ»v‘àãö\[ýYéI˜>Uñ!‚lDa>Ԫ΋ÆÏ©7~8AÖ]&Ãn³‰v|ÖîÊÄoÖY ±¡áäóy¨K×i˲w«\¡Â¹9Æ~€þ©œå™$ 6 6nQާf†ÂqÚ>,Þo,I¹Ó”ð •渱{I £.±H>ÒC-YnûÃöÛ馑gQ©°ÌzÎ t”a¹fñÞw0–îa,™ QºmÄpjôéc¥5žd•£Ûˆ2yܸ¤àÕé—ÒÙˆ ¶L+~±|½ç¸-¿‘·dj° òó¹qH„¾AÞÚÔ}mÝäëôÔµQƒÓ…Çl˜Vdk¨ÀýbùzŠeÉì\OclÙú=c õ;n ÈLi^Õ`Aä¢gqr<äÑKÔGÒ …ý¥ µk5µ¨úB²˜lÛ»ÉÖ¬¼ù@2ØlãEß\uÜÖ Ï«Ñ=Y&Ù0¬QÞ:È×Q€¿Ða!´ôµV³Ä#Ϻ•™¸½¥(¸ž_ˆÆ Ù²± é$/o|‡XhLÁa«¶f-=vÜAÛq˜Ò ¼ïÕ*q±…‰¶µŸ¿ä¥è¸Ô3xÉ¢ù4– ¨Žá˜j »m=-‘dl—æc\kkQôlab…e0ØòbNl•í¥{‚ôÁõÄWe°ÙÆ·éP‹¾¸êü¹ˆ|bÝßÚ-IŒÓ|óûÔLeM²aX:µQΣ¼tÔ»0âJߥA=ؕפÑÄmÓÖôûCiéj4nÙü­gˆFÚ`¸ÐD-s3åª L_Ý |ÉPq<'Aª¾ É †Whµ% o…³¹fÔ ÎaäŸ^Þù)Ùɘ°Ð˜"Çר´Y³=.´ ·½\;Àºl­í¸ƒ š¿³¶¶â t±ÒšêÕG9Òw¯Û&s܃ãc ”d;„ mj>zjZ¨äÏ “ ÿ ®'}ž±ð“D‡£ÒòhiÂþ÷bW]€egËl6qnkçþÔv‰Ó+àÚzZgÝJÌù¹ßo޾ïù·¾C`°ŽÕÖÖ£è¡Ñ“~8ØÂÄOßòRÑ»gñ¦¼Wg?µÝH²6KØ +Ú¯ L6JöAz`ß`ïègßU1nŽïFi¾yËa³Œ¼fƒ%oÒ Rhâ6Ì w•» G"¹U&/ź;¾²½ (+´Z’\³jÂ×ÿ§µÐÏ1,Ùž‹[Þ®›d°ìcò&uj£œm“ œ ©ë6?rg…W•¿J‚â¸z{±+® ¶8’ÒŽ›åÕ¾ |Üï· Ûß!†ÓÒÔñÔâBhݳøÚƒn¾Íö¹&[o°wá·GwˆZæÿjpf;Ê \ežÿøb®iakÿÓlÏE  âx× ÒîNƒT9³Â§g&aÐ`÷IiGM>nwÛ®ÑjJÙÖZÜ@ß f7Ø;𩼮SÞ»žÅG²Ï0µÿé½½òʺŠS³“0$´£¦ºÐ6ÍדTÞW)#Ùg¿³fz.ÄaJ¸]h*o+”´ ¾7Ã Ž¡Zß-ï1A26b‚+-SÃdlÅ}wôEVZ§†OA–ÇÈÙŠÑ»IúïèŠãôÙˬµO µ®~Mžƒ-އ˜ÏJÂQSÙ#xôpÓaïA’.®×U7µæ˜µ×ƒ„–‚˜Y›©°-úÛ©6Ëšæw]]ÿllÔA?ßÍZž•„$¢ŒŸã§²F ¾©wañèá¦èóÐçÃÞƒ$ÚŲe]]®ªDFŸëokÌ(vpýi91k® *Zï  ,8mßF6óÆ]²ípTqôke0»*ó÷¢1¶‰‘u 4Ÿ¼û„º%©Þy<²ï8sóyÿjèH¾AÅ}XÞ*<ðyOéb~DÂO-‡ÛTÆ”Š»@¦#胿8ÙÂ8 Å !»ôL –§–Î\Ì E×1Hnúb‹wáSʺ»]T£ lˆ?Ö‘–—ÞטPÇÌ©ìáúÒõúË“rb×\kyæ@TµÞYO„ŸX#$8pÚ=#A›eýk§|æZæWË %NÐ8d‘®£ŠŸâ3§Ì!*¼ý`­$᯴?Ð-† ²lÉH$«ÐSêû~F)âewh/?yö6$H· t*5KS¼òRH³yeÞp`~ï1çæóþþý¿ÕБ|ÌË =ƒŠ6úš‘»±¼Tx¨§e9;ƒ˜K"˜© µúɮˈ_ï]OFôlmÙ?ÍtÂŒóZCêA#ÁlpÁØwA€—6×GŽ-極ż„„qAŠhZ»[Cwè˜ZlÙÙ-O 6~_'-œ>ݹ˜ ƒ1S‹®b’µSÑÝôÅÄïôWï§”öÙ–Õ®¼é·¨œ1Þk…*ï*ÊkyíÓpH¬ø]oáF*.fÞ6áÅ TèTcMóe"²óå©Â¤0„‘g)Ÿ &äÅ®¸ýÞŸùÖóÌ:Ïèý{€©k¼™²Zý²Ÿ >«„8,$°5ñ*F21wsHpá´QkÐõzFƒ6c]²wËú×NÒáæù̵Ìàׄ¯–J¶#  pÈ„»A‰#]F8l1?Ä(…gO˜B~T©UyúÀLbË8Ř#ô^³§ª–ÜåTüO1Z×bb™ÎySØIáOPú~V{×-•bÌÔ-Š4–»R»è‘ ÙÐ^~óìGe­lH‘nuS /:6è# ©$Tj?e+–§yä¼H¥¤‘f½Š*'ò˼àëСÀýÞbÙæï#¼á½ §Ðü&Šƒ??‘²~pÐ$¹iËøBæF;[ýwzÜekµÅ~ZôîS 7÷H8v¸ ®±¡ŸðŠ?Ì3“$ýrÂj7„ÔnF¾Y ¨ÜËÂë|²O…Q¸Ñ; —…Ö Uïá ùdØ“S ž- \G=&£päÉG¢w`)/ ¬ía›«ßÂiµõ5òÈ÷˜ÿ±&¦sL‘†„ <À:R=Pe6^X7œ}o5ÚÃ64©1W¿„0•Õ³2Ókê3Ý$kå%©§'ï1þ&-[É#bML" '{ æ™"!$ó*x´(+ºÞ)ü`F(> q-qô,³vÃ.õÈš/7¢­pšÀqXç÷sY®rÜ3™w“%vQO+tñruÕ›E~‰ÜxK¶O} |Ïb!y€t¤xB“z Ê{ÆÊýl¼.°m~D‡o8úÞnúékµ†ljwì[h1Rió85b¯cm?a+«f`éÁQe¦×Ôdd½ãf"ºgàiH×Ë I¡KSNJ‘uyOÞcüN ËLZ·’M˜Ý¥FÄš˜Gð¯E@NöD‚$ÁAÍ2D@XsBIæ*C‹ŒTñhPU3gWu¼>V·Ö SøÀŒR:ª»P|âQ¾~ÕZâ9è[ SßYfí†X¤‡±]ë‘4\)û^oEZ_­/má5€à÷q·â±Ïîãs¥Ùæ<³\çþÙkå¸g2äz ï&J8îä 좞Ví`ôaè/âäéíˆÓë«6Šêi\½ý¸ðüÑÒÇþ—lžÿU©ú,ûØzùžÄBø\®uóéHòƒð„=&ñFWô A”õË+£÷•úöOÿÍÙx]`غ7WÚü‰Û>ã9Þqõ¼ß³Ÿ‹Ýõ!ÒÜ7Kå×k ØÖ©fïÔïØ¶Õ-²Ðb¤Ñ Î3ÓæpjÒ$]Å^þÄœ”'ÆÚ*~Ç@IÂWVÌÕ<ûÁÓ‚¢Àè•ËM¯¨ÊÅŸÈÉ{ÆÉ ñÌDt͆mCÏÀÓι-‘¯–@müw’+B.“é(–¦>œ—dT«•"êò”à€ÅŸ¼Çøž~­Ïœ8–úy¡˜µo$™w›1»JšóÑ}‰50ŒK_Ž á^Ï‹iŠ€ì‹B÷Û‰I‚ˆÆ#µƒšdˆ‚X¿€°æÜÚÑ„“ÌT…Q¦c‡:†Õr ©âР¨ º—ªfΫ¤nù®ëx|¯)K­o¬¬­Æ%§ñ¦3ë/¤uUv¥·?A ø)Ä¡:Có£|ýª¢¾—µÄsдç¶@§¾·‚͉²ÍÛ ³±;±Ib°‹eU»×"hºH_¸Sö¹‘œ1¼ÞŠ´½àƒ¿Z^Ú¾˜4í¸¼geª È‹µ¯îb—W7Þð2%k_Ü×8¹Å´(ï}OŠo½àdׇJÖ¿¸òjØÝàßw3XcVPWŸè¥0úúŸB¬øqß{ÀÈgǧ­urCÍÎo&•­p-?¤·û‡ОÏè'¢sB°Æ ¬zGÉ 2¯>ŽÈ[ ;gµ²‡Ð/P8i—ì_ …Yðâ=å—‡e†‡ÑÝ:à´ÏOZw3(?êä†RXwã@íØ øQ¿hð+ø¡H—ŸÄZ"0*âžWOIoöÇõ“Õ@§}müÀ5ŸÐN#·+Ÿ–Å'* ºýGA |ô’¨Hè÷›X=#¨?X1¶‰¡÷ÓvÏj¬Ê¨¾áÃ`„^ pÒæ·ô©¸YLß<ÑÂç…i~€à{Ë/ÃwHkË ¢s±hÇaÇ)Ù¸ LDo˜õüÓÿîfP~VÚ7¹'M¶@(¤°ïÆ ˆ£Û°9g×+Òx‘“nô;&÷ƒšf‘/?ˆ)“Xí´D`T ø1M¨ß¦ñϺþ’ßìF.¸‰T›gì'pqðH»ÉL/ÞÛù€0cEçUk? œÓƒÇùÁ6hyŠrä]7Ë\áP®NTÿ@öè˜%®‹ˆs7ï‚@ø¼>'!é$™UxA‹àׯ3\°ÊíY¶;UåÑ^GP~°ÿìÕb;!lÚ‡F È2éçpŽŽ‚(ížÔQù±‚äV_:X1:§ ƒ3næ †Áµ:¦m½@á¤ü†ÁI)/¯õNJ2"vóŠž–˜+¾x —ÙxôÉKÀH®.ÒýÀjAf¥÷–^O*9y]Ÿ–—å#ñòMkõ×~`çbÑŽ_Þ¶ë ŽRzµé7hFÙм!¼ˆß1ê0cV"Öùašjž½¦½¿ÁØ­´n6 SrNš¥Î)ÿ·{†Çát’ÙÍ*¬¾¨8F€¥v#ØÆfu`zrÏ®þÊsÉ›W¤ñ"ï–Gý­9©E^ÌvMîÎñ‰cÜD&døAèù/yQA“4S&±ÚëšÖ¿³ùÆé E¡Œðb¡Li<›Q¾„'6Û–’™5..þP&T¹™žèÞüŒ]q4áw©6.ΊI«?æE»ƒ ãà‘v[\öIéYýñU>˜l‚!Ô>aDƋΪ~7©ÏÖA8nÃ&]|v‰³ÄÊîÖYÖoᡱ óäK¨yËi׫w²¹Â¡\~Æ9œ©þ€$™å6 6 ŽQn†f§>ÚqÂ,oÞ,”Ó¹I ð±¸æ•£ I{±.CÒ>HûnY-éÛöÃQg‘¦Ì°©t Îzf¹a”Þñ¸Ã QSV‹ò…ö÷Ðt&ëIöÁt3ÒŠ3Ðâÿ‹•Áè3ÃANu߃þ UW‚‹þÁï3‹ÐÁê¶Ü‹,¶Ò‹•3Ջ؉D$Áë‹,‹Y3Õ%ÿ3… 3Ó‹ÂÁè¶Þ‹,ƒÁ¶À‹…3ŋډT$Áë‹,‹Y3Åâÿ3• 3ÃÁ‹ÐÁê¶Ü‹,¶Ò‹•3Ջ؉D$Áë‹,‹Y3Õ%ÿ3… 3ÓƒÁ‹ÂÁè¶Þ‹,¶À‹…‹Ú3ʼnT$Áë‹,‹Yâÿ3Å‹,• ƒÁ3Å3ËЃÁÁê¶Ò‹•‰D$¶Ü3‹ØÁë‹,‹3Õ%ÿ3… 3Ó‹ÂÁè¶Þ‹,¶À‹…3Å‹ÚÁë‹,‹Y3ʼnT$âÿ3• 3ÃÁ‹Ð¶Ü‹,Áê¶Ò‹•‹Ø3Õ‰D$Áë‹,‹Y%ÿ3Õ‹,… ƒÁ3Õ3Ó‹ÂÁè¶Þ‹,¶À‹…‹Ú3ÅÁë‹,‰T$âÿ‹• 3ŃÁ3Ãî O…êýÿÿƒþrH‹ÖÁê3¶Ü‹,‰D$¶|$‹<½‹Ø3ýÁë‹,%ÿ3ý3<… ƒÁƒîJ‹Çu½…ö_]t"›3ÒŠ3Ðâÿ‹•Áè3ÃANuä^÷Ð[YÃ$ N X j { Œ ™ « ½ Ñ Û í þ   . @ Y g s ƒ ” ž ¬ Â Ó à ò   # 1 B i y ‡ • ¿ ÒSV‹ð‹D$ 3ÛŠ|$W‹Ðâÿ‹øÁç×ÁâÓÁèÐ…ö÷Òt!‹ÿöÁt¶9‹ÂÁè3Ç‹…Áâ3ÓANuáƒþ UAü‚"‹þÁï‹X3Ӌʶދ,Áé¶É‹ 3̓À‹Ú‰T$Áë‹,‹X3Íâÿ3 •3Ë‹ÑÁê¶Ý‹,ƒÀ¶Ò‹•3Õ‹Ù‰L$Áë‹,‹X3Õáÿ33ÓƒÀ‹Ê¶Þ‹,Áé¶É‹ ‹Ú3͉T$Áë‹,‹Xâÿ3Í3 •3˃À‹ÑÁê¶Ý‹,¶Ò‹•‹Ù3ÕÁë‹,‹X‰L$áÿ3Õ‹,ƒÀ3Õ3ӋʃÀÁé‰T$¶É¶Þ‹,‹ 3Í‹ÚâÿÁë‹,‹3Í3 •3Ë‹ÑÁê¶Ò‹•¶Ý3‹ÙÁë‹,‹X3Õ‰L$áÿ33ӋʃÀ¶Þ‹,Áé‹Ú¶É‹ ‰T$âÿ3ÍÁë‹,‹•‹P3Í3Ë3ʃÀ‹ÑÁê¶Ý‹,¶Ò‹•‹Ù3ÕÁë‹,‰L$áÿ‹3Õ3Óƒî O…ãýÿÿƒþrL‹ÎÁé‹x3׃À¶Þ‹,‰T$¶|$‹<½‹Ú3ýÁë‹,âÿ3ý3<•ƒîI‹×u¹ƒÀ…ö]t¶8‹ÊÁé3Ï‹Áâ3Ó@Nuæ÷Ò‹Â%ÿ‹ÊÁáÁ‰T$3ÉŠl$Áà_Áê^[ÁÂÃB n {  ¢ ³ À Ò ä õ   & : D R h ˆ  £ ® ¿ É Õ ë ü   ! ( C M [ l – ¦ ´ à ä 3À…ÉtöÁt3ÑéƒÂ…ÉuðÃUVW‹ð‹û+þ½ ‹ÿ‹73Ò…À‹ËtëI¨t3ÑèƒÁ…Àuñ‰ƒÆMuÙ_^]Ã;"‹D$ ì…Àu‹„$Ä ¹Ç$ ƒ¸í‹Ád$‰ „Ñá@ƒø |õSVW\$ „$Œèœ$ŒD$ è‹„$3ÿ‹L< 3ö…ÉT$ töÁt32ÑéƒÂ…Éuð‰´<ŒƒÇÿ€|Ћœ$öÃt3Ò…ÀŒ$Œt¨t3ÑèƒÁ…Àuñ‹ÂÑû…Ûtm3ÿ¤$‹Œ<Œ3ö…É”$ŒtöÁt32ÑéƒÂ…Éuð‰t< ƒÇÿ€|ÍöÃt3Ò…ÀL$ t¨t3ÑèƒÁ…Àuñ‹ÂÑû…Û‰œ$…1ÿÿÿ‹Œ$_^3Á[Ä J"Z"I@ '‹L$…Éu3À ‹T$ ‹D$è ,.fileþÿg\zlib-1.2.3\crc32.c@comp.id _ÿÿ@feat.00ÿÿ.drectveX.debug$S{.rdata —¨(ã.textôô .debug$F.textÒ&ÌTJ  .debug$F.text&¿ó. .debug$F .text ‰Úàï9 .debug$F  .text ;i5ÏOK .debug$F  .textIÖ…É^ .debug$F.text}qp .debug$Fz_crc_table_get_crc_table@0_crc32_little_crc32_big_gf2_matrix_times_gf2_matrix_square_crc32_combine@12_crc32@12/327 1121701590 100666 1612 ` L ÖÎÛB¸.drectveX| .debug$S~Ô@B.text¡Ró P`.rdata%@0@.debug$F+;@B.textEc P`.debug$Fm}@B.text‡ P`.debug$Fž®@B/DEFAULTLIB:"uuid.lib" /DEFAULTLIB:"uuid.lib" /DEFAULTLIB:"LIBC" /DEFAULTLIB:"OLDNAMES" > 7x:\zlib-1.2.3\contrib\vstudio\vc7\zlibstat\compress.obj8   !Microsoft (R) Optimizing Compilerƒì8‹L$H‹T$<‹D$DS‹\$Dj8‰L$ ‹L$Th‰T$‰D$ ‹QT$R‰D$$ÇD$4ÇD$8ÇD$<è…ÀuBVjD$ Pè‹ðƒþtL$Qè…ö¸ûÿÿÿt‹Æ^[ƒÄ8‹T$D$P‰è^[ƒÄ8ÂPa r • 1.2.3¡ ‹D$‹L$ ‹T$jÿP‹D$ QRPè ‹D$‹È‹ÐÁéÁê ÈD Â.fileþÿg\zlib-1.2.3\compress.c@comp.id _ÿÿ@feat.00ÿÿ.drectveX.debug$S~.text¡ZB'   + .rdata{M-<.debug$F.text`BAVZ .debug$F.text7D|g .debug$F x_compress2@20_deflateEnd@4_deflate@8_deflateInit_@16??_C@_05GDHACFMB@1?42?43?$AA@_compress@16_compressBound@4/351 1121701590 100666 1641 ` LÖÎÛBï.drectveX .debug$S}\@B.textSÙ P`.debug$F,<@B.textF P`.debug$FÕå@B/DEFAULTLIB:"uuid.lib" /DEFAULTLIB:"uuid.lib" /DEFAULTLIB:"LIBC" /DEFAULTLIB:"OLDNAMES" = 6x:\zlib-1.2.3\contrib\vstudio\vc7\zlibstat\adler32.obj8   !Microsoft (R) Optimizing Compiler‹L$S‹\$W‹ùÁïáÿÿƒûu3‹D$¶Êùñÿréñÿùÿñÿrïñÿ‹ÇÁà_ Á[ V‹t$…öu ^_¸[ ƒûs;…Ût›¶ÈFùKuõùñÿréñÿ‹Ç3Ò¾ñÿ÷ö^_[‹ÂÁà Á û°‚θ¯©n^÷ãU‹êÁí ›ë°¸[ëI¶Ê¶VùʶVùʶVùʶVùʶVùʶVùʶVùʶVùʶV ùʶV ùʶV ùʶV ùʶV ùʶVùʶVùÊùƒÆH…wÿÿÿ‹Á3Ò¹ñÿ÷ñ‹Ç¿ñÿ‹Ê3Ò÷÷M‹ú…Fÿÿÿ]…Û„Ãû‚‘‹ÃÁè¶Ê¶VùʶVùʶVùʶVùʶVùʶVùʶVùʶVùʶV ùʶV ùʶV ùʶV ùʶV ùʶVùʶVùʃëùƒÆH…tÿÿÿ…Ût ¶ÈFùKuõ‹Á3Ò¹ñÿ÷ñ‹Ç¾ñÿ‹Ê3Ò÷ö‹ú‹Ç^Áà_ Á[ S  ‹D$ 3Ò¹ñÿ÷ñ‹L$SV‹ñæÿÿW‹Æ»ñÿÁé‹ú¯Ç3Ò÷ó‹D$‹ØÁèãÿÿÈ´ðÿ+Ïþñÿ„ ñÿvîñÿþñÿvîñÿ=âÿv-âÿ=ñÿv-ñÿÁà_ Æ^[ .fileþÿg\zlib-1.2.3\adler32.c@comp.id _ÿÿ@feat.00ÿÿ.drectveX.debug$S}.textS\™~ .debug$F.textãm¤J .debug$F$_adler32@12_adler32_combine@12 /374 1107660406 100666 14893 ` LvŽBÖ/R.text›´PÈ Q P`.data›®@PÀ.debug$SŸ²Ê%þ@B.debug$T· ¶/@BéIFast decoding Code from Chris Andersoninvalid literal/length codeinvalid distance code‹ÿinvalid distance too far back‹ÿ?ÿÿÿÿÿÿÿ?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ?ÿÿÿÿÿÿÿWVUSœƒì@ü‹t$X‹~‹V‹Ðƒê ‰D$,‰T$‹l$\‹N‹^ +é÷Ýëéˉ\$<‰l$(‰L$‹GL‹OP‰D$‰L$ ¸‹OTÓàH‰$¸‹OXÓàH‰D$‹G(‹O0‹W4‰D$4‰L$0‰T$8‹o8‹_<‹t$,‹L$;Îw"ƒÁ +θ +Á|$ó¤‹È3Àóªt$‰t$ë÷Æt3ÀŠF‹ËƒÃÓà èëè‹|$<ƒ=„‰wkPSQRœ‹$4$ œZ3ÐtD3À¢ûGenuu8ùntelu0úineIu(¸¢Áèƒàƒøu÷€uë Çë ÇZY[X뇀ûw 3Àf­ŠË€ÃÓà è‹$‹L$#Õ‹‘ŠÌ*ÜÓí„ÀuÁèª9|$†b9t$wÄéW‹ÐÁêŠÈ¨„ô€át%8ËsŠé3Àf­ŠË€ÃÓà èŠÍ¸ÓàH*Ù#ÅÓíЉT$€ûw 3Àf­ŠË€ÃÓà è‹T$‹L$ #Õ‹‘‹ÐÁêŠÌ*ÜÓíŠÈ¨„²€áte8ËsŠé3Àf­ŠË€ÃÓà èŠÍ¸ÓàH*Ù#ÅÓíÐë‰t$,‹Ç+D$(;‚”‹L$‹÷+òƒéŠˆŠFŠVƒÆˆGˆWƒÇó¤‹t$,éÿÿÿƒúu½9|$(t·O‹L$ŠƒéˆGˆGˆGƒÇóªéèþÿÿ¨@…¸ÓàH#Å‹T$‹‚éºþÿÿ¨@…â¸ÓàH#Å‹T$ ‹‚éÿÿÿ‹È‹D$4÷Ù‹t$8;‚Þʃ|$0u$+Áð‹D$;Áv`+Áó¤‹÷+òëV;ÁvR+Áó¤‹÷+òëH‹D$0;Èv,t$4ð+ñ+È‹D$;Áv.+Áó¤‹t$8‹L$0;Áv+Áó¤‹÷+òëð+ñ‹D$;Áv+Áó¤‹÷+ò‹Èó¤‹t$,éþÿÿ‹ÿwnÅ‹ën$$ãnl$êïÉ‹\$ëÓÁƒý wnõn>ƒÆóþƒÅ ëÇÛà~àÜ‹ƒ¶ÌnÉ+é„ÀuÁèª9|$†9t$wºé‹ÐÁꨄàƒàtÓÁnÈ~Á+è# …ÑÓÁƒý wnõn>ƒÆóþƒÅ ëÇ‹\$ Ûè~èÕ‹ƒ¶Ì‹ØÁë+énɨ„¬ƒàtWÓÁnÈ~Á+è# …Ù‰t$,‹Ç+D$(;©‹Ê‹÷+óƒéŠˆŠFŠVƒÆˆGˆWƒÇó¤‹t$,‹\$é-ÿÿÿIƒûu¸9|$(t²O‹ÊŠƒéˆGˆGˆGƒÇóª‹\$éÿÿÿ‹ÿ¨@…ÞƒàÓÁ~Á# …Ê‹‹éÌþÿÿ‹ÿ¨@…®ƒàÓÁ~Á# …‹D$ Ë‹ˆéÿÿÿ‹ÿ‹È‹D$4÷Ù‹t$8;¢˃|$0u +Áð;ÑvX+Ñó¤‹÷+óëN;ÑvJ+Ñó¤‹÷+óë@‹D$0;Èv(t$4ð+ñ+È;Ñv*+Ñó¤‹t$8‹L$0;Ñv+Ñó¤‹÷+óëð+ñ;Ñv+Ñó¤‹÷+ó‹Êó¤‹t$,‹\$é$þÿÿ¹ºë,¨ t ¹º 빺ë‹t$,¹ºë‹D$X…Ét‰H‹@‰ëƒ=u‹Ý‹D$X‹Ë‹PÁé+ñÁá+Ù‰x ‰Z<‹Ë\$9\$u+ó‹‰\$ó‹Xƒë \$‰0»ÓãKƒ=uÓÁ~Åw#ë‰j8‹\$;Þv +ރà ‰Xë +ó÷ÞƒÆ ‰p‹\$;ßv +ßÉXë +û÷ßljxƒÄ@[]^_Ãà=Iÿ W à  § ÃÓò@W X Y Z [ \]bcklno"q&r*t.u1v4x6y8z:|@}BF€JNƒQ„T†X‡\‰aŠd‹fŒgjor‘t’u“y•|–—‚™†šŠ›Ž‘ž” ˜¡œ¢ž£ ¥£¦¥§ª¨¬©°ª²«´¬¶­¸®¼¯À°Â´ÈµÊ¶Ì·Î¸Ï¹ÑºÔ»Ö¼Ø½ÚÀÞÃåÄëÅíÇîÈïÉðÊñËòÌõÍüÒýÓþÔÿÕÖ×ØÙ ÚÛÜÝÞß$à&á)â,ã/ä1å7æ9ç;éEêGìQîRïSðTñUòX÷[ø]ú_ûaücýfþhÿjmqsvxz|~€ƒ„ ˆ!Ž#’$”%™)›*ž+ -¢.¨/«0­1¯2±4³5µ6·7¹8¼9¾:À;Â>Ç?É@ÊAÌBÎCÐDÒGÖLÙMÛOÝPßQáRäSæTèWìXðYòZõ^÷_ú`üaþbdfg h ijkmnopqr s"t$w)x+y,z.{0|2}4~6‚:ƒ<„@†B‡H‰LŠN‹PSŽUWZ‘]’`“c”f•i–k˜o™twžyŸ} ¢€£„¤†¥‰§Œ¨©’ª•«—­œµž¶¤¸©¹«º¬»®¼°½´¾·¿¼Ç¾ÈÄÊÉËËÌÌÍÎÎÐÏÔÐ×ÑÜÖÞ×âØäÙèÛêÜðÞòß÷àùâûãýåæçéê ë ì íïðòóôõöú!û#ü%þ)ÿ+-/3579 ; ? C E GIKMOQSUY[]_ a!c"e&g'i)m*t.v4y5{78‚9‡:Š;<‘=”A—CšDœFŸG¢H¥I¨J«K®N±O´P·QºT½UÀVÂXÄYÆ[É\ÊaÎbÔdØeÚfßjákämænìoïpñrôs÷túuüvwz| } €‚ƒ„‡#ˆ&‰)Š,‹/24‘7’9“<•>–D—G˜I›LœORžTŸ[ ]£a¤c¥g§i¨oªq«s¬u®x¯z°|±²‚³…´ˆµ‹¶Ž·¹”º˜» ¿£À¥Á©Â«Ä¬Å®Æ°Ç³É¶Ê¹Ë¼Ì¿ÍÁÏÅÐÌÔÎÕÔ×רÚÙÝÚäÛæÜéÝðáòâøäûåþæçè éêëðñò ó$õ&ö,ø.ù3ú5ü7ý9ÿ;=?ACEGI K M O QSUY[]acegik m!o"s#w$y%{'}()*ƒ+…/‡0‰3‹467‘8“9•>—?™AB¡C¦K«L°M²U´V¶X»YÀZÂbÇcÌdÎjÒk×lÜmÞqâräsætévìwîxð}÷~ù‚û†ÿ‡ˆ‰Š ‹ ŒŽ‘’“ •"–$—(˜*™-š0›4ž6 ;¡=¢>¨E©G­J®M°O¶Q·T¼X½Z¾\À^ÁaÂdÃfÅhÆjÇmÈpÏtÐvÑxÓzԀՃօ؇ىÚÛ’â•ã–ä—å˜æ™çšè  inffas32.obj6/Microsoft (R) Macro Assembler Version 6.14.8444 L_test_for_length_base$ L_invalid_distance_too_far L_check_dist_one_mmx L_do_copy1_mmx L_wrap_around_window  L_do_copy1 L_add_bits_to_len  L_do_loop' L_invalid_literal_length_code# invalid_distance_code_msg L_get_length_code_mmx  _inflate_fast  L_init_mmx( L_test_for_second_level_length  L_save_len L_add_bits_to_dist_mmx inflate_fast_mask L_update_next_in L_dodist  L_skip_msg L_get_distance_code" L_wrap_around_window_mmx  L_do_loop_mmx! L_invalid_distance_code& L_test_for_second_level_dist! L_test_for_end_of_block) invalid_literal_length_code_msg*  L_test_for_second_level_dist_mmx L_clip_window_mmx  L_dolen_mmx  L_use_mmx  L_break_loop L_get_length_code L_add_bits_to_dist  L_fixup_out L_get_dist_code_mmx  L_clip_window,››$$$00001) invalid_literal_length_code_msg# invalid_distance_code_msg& invalid_distance_too_far_msg inflate_fast_mask inflate_fast_entry  L_align_long  L_is_aligned  L_check_mmx  L_use_mmx L_dont_use_mmx L_check_mmx_pop  L_do_loop L_get_length_code L_dolen  L_while_test L_test_for_length_base L_add_bits_to_len  L_save_len L_decode_distance L_get_distance_code L_dodist L_add_bits_to_dist L_check_window L_check_dist_one( L_test_for_second_level_length& L_test_for_second_level_dist  L_clip_window L_wrap_around_window L_contiguous_in_window  L_do_copy1  L_init_mmx  L_do_loop_mmx L_get_length_code_mmx  L_dolen_mmx L_while_test_mmx$ L_test_for_length_base_mmx L_decode_distance_mmx L_get_dist_code_mmx  L_dodist_mmx L_add_bits_to_dist_mmx L_check_window_mmx L_check_dist_one_mmx, "L_test_for_second_level_length_mmx*  L_test_for_second_level_dist_mmx L_clip_window_mmx" L_wrap_around_window_mmx$ L_contiguous_in_window_mmx L_do_copy1_mmx! L_invalid_distance_code! L_test_for_end_of_block' L_invalid_literal_length_code$ L_invalid_distance_too_far L_update_stream_state  L_skip_msg  L_break_loop L_update_next_in L_buf_not_used  L_update_hold L_last_is_smaller  L_fixup_out L_end_is_smaller L_done  L_check_mmx L_decode_distance_mmx L_dont_use_mmx  L_is_aligned L_check_window L_contiguous_in_window L_buf_not_used L_update_stream_state L_decode_distance  L_while_test inflate_fast_use_mmx, "L_test_for_second_level_length_mmx L_check_dist_one L_end_is_smaller L_check_window_mmx L_while_test_mmx  L_update_hold$ L_test_for_length_base_mmx  L_dodist_mmx  L_align_long inflate_fast_entry L_dolen L_last_is_smaller L_check_mmx_pop L_done$ L_contiguous_in_window_mmx& invalid_distance_too_far_msgU Y w {  ¡ ½ Á × Û ÷ û   * . ? C h l ! ‘! ® ² Ç" Ë" Ý# á# $ $ % !% ? C \& `& x' |' Œ( ( ¢) ¦) Á* Å* å+ é+ þ, , !- %- I. M. l p —/ ›/ Ã0 Ç0 à1 ä1 ÷2 û2 3 3 $4 (4 A5 E5 _6 c6 v7 z7 •8 ™8 Æ Ê Ü à   , 0 T X q9 u9 : “: §; «; ¿< Ã< Ö2 Ú2 ë= ï= > >  $ 54 94 R? V? e@ i@ }  Ÿ £ ¼$ À$ ÒA ÖA ï) ó) ' ' "5 &5 @B DB ZC ^C v# z#  - ¤- È8 Ì8 á å D D # ' 9" =" O+ S+ h! l! ‰1 1  E ¤E ¼F ÀF âG æG  7  7 " H & H : % > % \ I ` I z  ~  š J ž J È / Ì / ô 0 ø 0  *  * 5 K 9 K [  _  u , y , ˜ . œ . » ¿ ä  è  L  L + ( / ( A 3 E 3 Y & ] & u M y M N “ N ¨ O ¬ O Å 6 É 6 Ü P à P ø Q ü Q  <  < % G ) G F = J = ` ; d ; x B | B ’ D – D ´ M ¸ M Î L Ò L ï A ó A @  @ $  (  D J H J r C v C Ž P ’ P ª I ® I È E Ì E ä N è N ý F F #H 'H ;: ?: S9 W9 q? u? „O ˆO ¡> ¥> ¼Q ÀQ ÎK ÒK ô ø òñ òñ.fileþÿginffas32.asm@comp.idü ÿÿ.text› Q.data.debug$Sþ.debug$T L  ,„ >0 ^ sd $$$00001 ›È.bfeP.lfQe.ef›e8™ §Î   ו æ ûe  X " @® Vt aœ €Ò ‹I ¢û L_dodistõ ³é ¾è ÒU ë” ù¦ ¼ .² Fð g yº …; ð œj ®$ Áp Í áÜ ï Â Ú Þ (G 7Q L_dolenv G„ TÖ f6 ut †Q Ê ®ß É ß/ ì] ÿÌ "… =Þ S4 bO pf ‚… L_done’ “invalid_distance_code_msg_inflate_fastinflate_fast_maskinvalid_literal_length_code_msginflate_fast_use_mmxinvalid_distance_too_far_msgL_test_for_length_baseL_invalid_distance_too_farL_check_dist_one_mmxL_do_copy1_mmxL_wrap_around_windowL_do_copy1L_add_bits_to_lenL_do_loopL_invalid_literal_length_codeL_get_length_code_mmxL_init_mmxL_test_for_second_level_lengthL_save_lenL_add_bits_to_dist_mmxL_update_next_inL_skip_msgL_get_distance_codeL_wrap_around_window_mmxL_do_loop_mmxL_invalid_distance_codeL_test_for_second_level_distL_test_for_end_of_blockL_test_for_second_level_dist_mmxL_clip_window_mmxL_dolen_mmxL_use_mmxL_break_loopL_get_length_codeL_add_bits_to_distL_fixup_outL_get_dist_code_mmxL_clip_windowinflate_fast_entryL_align_longL_is_alignedL_check_mmxL_dont_use_mmxL_check_mmx_popL_while_testL_decode_distanceL_check_windowL_check_dist_oneL_contiguous_in_windowL_while_test_mmxL_test_for_length_base_mmxL_decode_distance_mmxL_dodist_mmxL_check_window_mmxL_test_for_second_level_length_mmxL_contiguous_in_window_mmxL_update_stream_stateL_buf_not_usedL_update_holdL_last_is_smallerL_end_is_smaller /401 1107701386 100666 10241 ` L‰.B~i.text´¸] 0`.data@0À.debug$S|æb”@B.debug$T€T*@B‹T$UWVSƒì4‹ê‹U|‹]x9ŒwÁêB‹½‰T$0‹Et;Çs‹ø‰\$(‹u8‹Ml‰t$$‰|$ñ‰t$ f‹f‹\3ÿÆf‰T$‰4$‹u,î+Îw3ɉL$,‹U@‰T$ ‹Upf‹l$‹D$L‰T$‹T$$‹ú|$(‹t$ O‰|$ëNƒD$0„Ñf98t%ÿf‹F;ȃºÿL$0uãé¯f;,uÞéã‹|$%ÿf‹F;ȃƒl$0v¬f98„¬%ÿf‹F;ȃmf98„€%ÿf‹F;ȃRf98„T%ÿf‹F;ȃ7f98„(%ÿf‹F;ȃf98„ü%ÿf‹F;ȃf98„Ð%ÿf‹F;ȃæf98„¤%ÿf‹F;ȃËf98„u%ÿf‹F;ȃ°f98„F%ÿf‹F;ȃ•f98„%ÿf‹F;ȃzf98„è%ÿf‹F;ȃ_f98t}%ÿf‹F;ȃHf98tz%ÿf‹F;ȃ1f98ts%ÿf‹F;ȃf98tl%ÿf‹F;ȃf98te%ÿf‹F;ȃìƒl$0‡Yþÿÿéþÿÿf;,…yÿÿÿƒD$0éf;,u€ƒD$0éf;,u‡ƒD$0éõf;,uŽƒD$0éåf;,u•ƒD$0éÕf;,…ÿÿÿƒD$0éÁf;,…ßþÿÿƒD$0é­f;,…°þÿÿƒD$0é™f;,…þÿÿƒD$0 é…f;,…RþÿÿƒD$0 ëtf;,…&þÿÿƒD$0 ëcf;,…úýÿÿƒD$0 ëRf;,…ÎýÿÿƒD$0 ëAf;,…¢ýÿÿƒD$0ë0f;,…výÿÿƒD$0ëf;,…JýÿÿƒD$0ë‹|$$f;,8…ýÿÿ‹ú‹t$ ø‹V3Wt- Òt¾ëQf Òt¾ëEâÿÿÿt¾ë6¾ë/ƒÇƒÆ¹?ó§tƒî‹Wü3 ÒuFf Òu FâÿÿÿuF+t$ ;t$(w‹t$ ‹L$,‹T$$éŒüÿÿ‰t$(‰D$;t$s"‹L$ ‹T$$ÎòN‰t$f‹Yÿ‹t$ ‹L$,é\üÿÿ‹\$‹l$H‹L$(‰]p‹Et;Èw‹ÁƒÄ4[^_]à GVMat32 optimised assembly code written 1996-98 by Gilles Vollant SœX‹È5PœX3ÁtQœœY‹Á5 PœX3Át¸¢[øë÷¸ëðUWVSƒì$‹T$8‹L$<‹Bx‹šŒ;ËB4‹Z||ÁëKÁã ؉$‹‚‹Zt;Ø|‹Ø‰\$‹r8‰t$‹jl|5‰|$ ‹Ç÷؃à‰D$‹B,-+è3í‹Bx‰D$ð‰t$·‰\$·\8ÿ‰\$ ‹z@‹$ë#Ê· O;͆àêˆÔ·D1ÿ;ÃuÝ‹D$·;D$uω$‹t$‹|$ ñ‹D$ºøþÿÿ¼8´0‹23:u‹D23D:uƒÂuéëqƒÂ©ÿÿuƒÂÁè,ƒÒ:‹|$ +Ç=}L‹T$8‹\$;Ët$‹z@‹\$ ‹$éNÿÿÿ‹\$‰D$‰Jp;Ã}-‹t$ð‰t$·\8ÿ‹z@‰\$ ‹$é!ÿÿÿ‹T$8ÇD$‰Jp‹T$8‹\$‹Bt;؋ÃÄ$[^_]à asm686 with masm, optimised assembly code from Brian Raiter, written 1998     %),. 0!2$6'9(<)@+D-F.J0M2R3X5]7`=c>i@kAmBoDsGvHzK}L‚M†NŠPŽQR”S˜T™VX f¥g«i¯j±m¶nºp¼qÂsÆtÈuÍyÑzÓ{Ø~Üá‚å„ç†íŒòŽô‘ø’þž¡4¤O§jª…­ °»³Ö¶ñ¹ ¼#¿:ÂQÅhÈË„̈ÍŠÎЕћҠâ´åÄèÔëäîôñô÷0úDýUfwˆ ™ ª»¿ÃÉËÏ Ñ"Ô#×%Ù(Û)Ý*â+ä-ç.é0î1ð3ö4ø5ý6ÿ89= > ?@BDEFHI!J"L%M'N(P.Q0R1U5X9Y;[?\C]G^LaPcTdXeZf^gbhdifkglkmopsqwr|v€w„xˆy‹zŽ{|’}”‚—„˜…™†š‡›ˆáâãäæë ì í î ï ñóôõö÷øúÿ $%(),- ! " # &*.179<? A!D)E*H+J,M0S1V2X3Z4\5`9c:g;j<n=rBtCvDyE}J€K…L‡M‰N‹SŽT’X”Y˜_›`Ÿa¤b¨c«g®h°²‚¶ƒ¸„¾…Ćʇψщӊ׋یßá‘ä˜è™ìšî›òœ÷þž¯° ± ²³´µ¶·¸!¹&º(»+¼.½0¾3Ã6Ä:Å<ÆAÇCÌGÍKÎMÏOÐSÑVÒZÓ]ÔbÛfÜjÝmÞoßqàuáwâ{ã€äƒå‡æŠçë“ì›ížó¢ô¦õ©ö«÷­ø¯ý²þ³ÿ´µ¶ñ,O:\updasm\contrib\masmx86\gvmat32.obj4  Microsoft (R) Macro Assembler8åå_longest_match_686LastMatchGoodLookaheadLessLimitPositiveLookupLoopLoopEntryLoopCmpsLeaveLoopCmps4LeaveLoopCmpsLenLowerLongerMatchLenMaximumLeaveNowLookaheadRet2>>_cpudetect32exitcpudetectend_cpu_is_386is_old_4869áá_longest_match_7fffnoshrnolookaheadnicematchnodistnormalbeg0add16normalbeg0rcontlabnorollnormalbeg2norollcontloop3jnbexitloopshort1beginloop2do16rcontloop0rcontloop1rcontloop2rcontloop3rcontloop4rcontloop5rcontloop6rcontloop7rcontloop8rcontloop9rcontloop10rcontloop11rcontloop12rcontloop13rcontloop14rcontloop15normalbeg2dc11normalbeg2dc12normalbeg2dc13normalbeg2dc14normalbeg2dc15normalbeg2dc10normalbeg2dc9normalbeg2dc8normalbeg2dc7normalbeg2dc6normalbeg2dc5normalbeg2dc4normalbeg2dc3normalbeg2dc2normalbeg2dc1normalbeg2dc0normalbeg2iseqeq1rr eq1eq11begincomparetrfintrfinvalnewbestlenexitloopminexloInfoAuthor ” ®" ²" Ç# Ë# à$ ä$ ù% ý% & & $' (' 8( <( R) V) k* o* + ƒ+ –, š, ¬- °- À. Ä. ø ü / / )0 -0 C1 G1 y } ˜2 œ2 ©3 ­3 É4 Í4 Û5 ß5 ö6 ú6 7 7 &8 *8 B9 F9 W: [: t; x; Š< Ž< š= ž= °> ´> Æ? Ê? Ü@ à@ òA öA B B C "C 4D 8D JE NE `F dF vG zG H ‘H ¤I ¨I »J ¿J ÒK ÖK éL íL M M N N 4O 8O NP RP hQ lQ ‚R †R œS  S µT ¹T ÎU ÒU çV ëV W W X X 2Y 6Y KZ OZ d[ h[ }\ \ –] š] ¬^ °^ ¼_ À_ Í` Ñ` Üa àa ìb ðb c c d d )e -e ?f Cf Sg Wg fh jh òñž}\.fileþÿgO:\updasm\contrib\masmx86\gvmat32.asm@comp.id ÿÿ.text].data.debug$S|”.debug$TT á¸.bfeŽ.lf»e.efáeá > .bfáe(.lf!e.efeU% åà .bfeª.lfe.efe­8DF\T‹b°mÊLoopCmpsw†!LenLower.”b LeaveNowž«¯¸ÆÕnoshrà2nodistoõ «±Í0Ø:çLído16ôWþbm4xOƒjŽ…™ ¤»¯ÖºñÅ Ñ#Ý:éQõh  ´+Ä:ÔIäXôguƒ0‘DŸU­f»wɈיåªó»iseqÉeq1rräeq1ðeq11ÿþtrfin1trfinval5 Lexitloop|minexlo”œ!_longest_match_7fff_cpudetect32_longest_match_686LastMatchGoodLookaheadLessLimitPositiveLookupLoopLoopEntryLeaveLoopCmps4LeaveLoopCmpsLongerMatchLenMaximumLookaheadRetexitcpudetectend_cpu_is_386is_old_486nolookaheadnicematchnormalbeg0add16normalbeg0rcontlabnorollnormalbeg2norollcontloop3jnbexitloopshort1beginloop2rcontloop0rcontloop1rcontloop2rcontloop3rcontloop4rcontloop5rcontloop6rcontloop7rcontloop8rcontloop9rcontloop10rcontloop11rcontloop12rcontloop13rcontloop14rcontloop15normalbeg2dc11normalbeg2dc12normalbeg2dc13normalbeg2dc14normalbeg2dc15normalbeg2dc10normalbeg2dc9normalbeg2dc8normalbeg2dc7normalbeg2dc6normalbeg2dc5normalbeg2dc4normalbeg2dc3normalbeg2dc2normalbeg2dc1normalbeg2dc0normalbeg2begincomparenewbestlenInfoAuthor nestopia-1.51.1/palettes/000077500000000000000000000000001411157722000152425ustar00rootroot00000000000000nestopia-1.51.1/palettes/BMFFINR2.pal000066400000000000000000000003001411157722000170760ustar00rootroot00000000000000RRR€Š,~JNPD& .2& H¤¤¤8Î4ì^ÜŒ°šLp6LTltl,^„ÿÿÿLœÿ|xÿ¦dÿÚZÿðTÀðjVÖ†º¤vÀFÌ.Èf4¾:::ÿÿÿ¶ÚÿÈÊÿÚÂÿð¾ÿü¼îúÂÀòÌ¢æÚ’ÌæŽ¸î¢®ê¾®èâ°°°nestopia-1.51.1/palettes/BMFFINR3.pal000066400000000000000000000003001411157722000170770ustar00rootroot00000000000000hhh™ªQš~iŽ~Q7NZP@a¹¹¹ \×P5ð‰à» ³Î aÀ+•Mao‹˜ “K›ÿÿÿc´ÿ›‘ÿÓwÿïjÿùhÀù}lí›-½½|ÚKèG5å‘?ÙÝ```ÿÿÿ¬çÿÕÍÿíºÿø°ÿþ°ìý½µùÒŽèë|»ó‚™÷¢ŠõÐ’ôñ¾¾¾nestopia-1.51.1/palettes/CXA2025AS-1536.pal000066400000000000000000000030001411157722000174750ustar00rootroot00000000000000XXX#Œ›-…]Rzz_5* 9?<"2]¡¡¡Sî<þ`(䩘ÔAÒ,ªDl^-s}xRi©ÿÿÿ¥þ^‰þµrþþeöþgþw<þ“IJyÊ:ÕJѤ¿þBBBÿÿÿ Ùþ½ÌþáÂþþ¼ûþ½ÐþÅ©þÑŽéÞ†Ç钨ìÙ‘äþ¬¬¬U=: 7K%K8:DF8 # zv/q9#XŽtu†Jˆ(s4VA6LOI ;BðÁ»fq¶…cÔ§XÕÅUº×[Úi[Äv-¥…‚e“)USS~„?+(ðÁ»¶ ¹ÃšÅÒ•ÆÞ”»æ–¨ç“Þ¢Шs­sµ®}®¬­¥¤¤}7O/5 C?(' (  ,40&q”f Fn2‚6!{I[Z2\*P=:Q#cnhZFµä¥E‘®\{Ãui¼Š^šœdmžr=‘‡z`° L¼);¶R9¦ƒ%9µä¥†Á©¸±š°¯£«¡«®Ž«´y¦½hœÆ`‘Îc‰Ópтʗx›l66%)7 6%& (opW +\q5nI VY-[N,8:!EKF 88³³‘Ei—[Z¬tNª‰H›Md\4jxy^†JŒ9†@7wp$%³³‘„””ŽŽœ˜ˆ›¡†‘©ˆªŽj¤”Zš›R S†£] o~šƒvv]@@c] ql+T20.   ":~²@¨43ÅM"¾ajie3Q)56G QS@LwÈÇÿZ„ÿxvÿ’dÿ¨Yö²WÀ¬^„—kTxy9^Œ?J—_A™“F’Î--KÈÇÿ™«ÿ¦¥ÿ±ÿº™ÿ¿˜ì¼›Ó³ ¾¦¦²›®µ“³Ã´Ù‘±ó†…º;/?8LJ&9-,  ve|)s-DX tcLb"O!2.9 ?=5D¼¥ÄOdºmV؆JÕœD»¨F‘¦Nc’[4siZvE|3:zZ<3;   <`žRQ³kE±€?—ŒAnŠJA|Weg Ms8y$.wJ/nw   v…Ÿ¨Šy§“wœ—x‹—{x‘h‡ˆ`}atko|p‹gggnestopia-1.51.1/palettes/Composite Direct (FBX).pal000066400000000000000000000003001411157722000216070ustar00rootroot00000000000000eee}Ž6‚V]ZO81=A;.U¯¯¯NÈG/ãkד®ž^™2{K[g&z‚z>nŠÿÿÿd©ÿމÿ¶vÿàoÿïlÄð€jؘ,¹´ ƒË [Ö?JÑ~MÇËLLLÿÿÿÇåÿÙÙÿéÑÿùÎÿÿÌñÿÔËøß±íê¤Öô¤Åø¸¾öÓ¿ññ¹¹¹nestopia-1.51.1/palettes/NES Classic (FBX-FS).pal000066400000000000000000000003001411157722000207470ustar00rootroot00000000000000`a_ƒ•4uQ^VL7# : KLB1T©ª¨K¿GØcʈ©“ FŠ-oR\q• „H kŽûûûf™ø‰tù«XøÕWïÞ_©ÜYÇ¢$§¾u×`ãO<ÖVÉÌAB@ûûû¾ÔúÉÇù×¾úè¸ùõºåóÊÂßͧÙàœÉëžÀí¸µôǹêé«««nestopia-1.51.1/palettes/NES_Classic-FBX.pal000066400000000000000000000003001411157722000204340ustar00rootroot00000000000000```ƒž8|V b[S :# 5 A E>1T©©©K¿Jäi ÒŽ²žL2sQ\j} uGfûûûf™ø‰xþ²bÿÞcÿëi³ã‡XÈŸ"§±sÂ]ÐO6ÅPÅÌ@@@ûûû¿ÔúÍËþÙÂÿì¾ÿúÂë÷ÊÃãͧÙÞœÈæžÀ渵íǹæê¸¸¸nestopia-1.51.1/palettes/Nostalgia-FBX.pal000066400000000000000000000003001411157722000202670ustar00rootroot00000000000000eee}Ž6‚V]ZO81=A;.U¯¯¯NÈG/ãkד®ž^—2{K[g&z‚z>nŠÿÿÿd©ÿމÿ¶vÿàoÿïlÄð€jؘ,¹´ ƒË [Ö?JÑ~MÇËLLLÿÿÿÇåÿÙÙÿéÑÿùÎÿÿÌñÿÔËøß±íê¤Öô¤Åø¸¾öÓ¿ññ¹¹¹nestopia-1.51.1/palettes/Original Hardware (FBX).pal000066400000000000000000000003001411157722000217340ustar00rootroot00000000000000jmj}‚;}V]ZO 8 1=@;.U¹¼¹NÈG/ãuד­ž$^–8{P[g&zxBnŠÿÿÿi®ÿ—˜ÿ¶‡ÿâxÿòyÇõoÝ©2¼· ˆÐ`ÛIOÖ‡PÊÎQTQÿÿÿÌêÿÞâÿîÚÿú×ýý×öýÜÐúè¶òñ©Ûû©Êÿ½ÃûØÄöö¾Á¾nestopia-1.51.1/palettes/PVM Style (FBX).pal000066400000000000000000000003001411157722000201750ustar00rootroot00000000000000iidt(}>mVW^S;$*0:?;0P¹¹´S¹M,ÚzȘœ#D >Uem,y}BxŠÿÿÿi¨ÿš–ÿŠúê}úó‡´ñ˜læ³'×ÈßdåUem,y}BxŠÿÿÿi¨ÿ–‘ÿ²Šúê}úó{ÇòŽYæ­'×ÈßdåK؆MÏÒRRRÿÿÿ¼ßÿÒÒÿáÈÿïÇÿÿÃáÿÊÆòÚ­ëã Òí¢¼ô´µñζìñ¿¿¿nestopia-1.51.1/palettes/YUV-V3.pal000066400000000000000000000003001411157722000167020ustar00rootroot00000000000000fff*ˆ§;¤\~n@lV35 HRL>[­­­_ÙB@ÿu'þ Ì·{µ1 ™Nkm8‡ “ŒGz ÿÿÿd°ÿ’ÿÆvÿòjÿÿnÌÿpêž"¼¾ˆØ\ä0Eà‚HÍÞOOOÿÿÿÀßÿÓÒÿèÈÿúÂÿÿÄêÿÌÅ÷Ø¥äå”Ïï–½ô«³ó̵ëò¸¸¸nestopia-1.51.1/palettes/hybrid.pal000066400000000000000000000003001411157722000172120ustar00rootroot00000000000000llm†œ>qizZ/.AI; 6Y¶µ¶ ^Û31êv æ© ¶Â Y·,¢Jqk†”„:vŠýýýN±ýuŒýÀ~ýërý÷n»öy`ê—0Õ¸"€Ì QØCPä‹%×ÓbbcýýýµâýÌÓýÛÉýúÆýýÅãýÅ»ùØ«óä ÚõŸ´ñ·´÷Ì«õï¿¿Ànestopia-1.51.1/palettes/nescap.pal000066400000000000000000000003001411157722000172020ustar00rootroot00000000000000dce€8‚V]ZO 81=A:/U¯­¯KÊG*çkÛ–°Ÿ[–0{HZf#xx=lŒÿÿÿ`¦ÿ„ÿ´sÿâlÿòhÃï~aØ•'º³ÈWÔ=GÏ~KÅÍLKMÿÿÿÂàÿÕÒÿãËÿ÷ÈÿþÆîþÎÆö×®éäŸÓíÀò²¹ñ̺ííº¹»nestopia-1.51.1/palettes/ntsc.pal000066400000000000000000000030001411157722000167000ustar00rootroot00000000000000\\\![o+ m?TJ.H ;&'287 .6§§§%S¥A@Âb0¿~)œ+f‹6,yH[\:l ur7fqþÿÿs¥ü’ÿµÿÓwóãy¹á†zÍ™G­¯-ŠÀ0mÉP^Ɔ`¹ÅEEEþÿÿÄÙýÑÐÿàÉÿìÅúóÇâòÌÇêÔ±ÝÝ¥Îå¦Áè´»ç̼âç°°°U=: 7K%K8:DF8 # zv/q9#XŽtu†Jˆ(s4VA6LOI ;BðÁ»fq¶…cÔ§XÕÅUº×[Úi[Äv-¥…‚e“)USS~„?+(ðÁ»¶ ¹ÃšÅÒ•ÆÞ”»æ–¨ç“Þ¢Шs­sµ®}®¬­¥¤¤}7O/5 C?(' (  ,40&q”f Fn2‚6!{I[Z2\*P=:Q#cnhZFµä¥E‘®\{Ãui¼Š^šœdmžr=‘‡z`° L¼);¶R9¦ƒ%9µä¥†Á©¸±š°¯£«¡«®Ž«´y¦½hœÆ`‘Îc‰Ópтʗx›l66%)7 6%& (opW +\q5nI VY-[N,8:!EKF 88³³‘Ei—[Z¬tNª‰H›Md\4jxy^†JŒ9†@7wp$%³³‘„””ŽŽœ˜ˆ›¡†‘©ˆªŽj¤”Zš›R S†£] o~šƒvv]@@c] ql+T20.   ":~²@¨43ÅM"¾ajie3Q)56G QS@LwÈÇÿZ„ÿxvÿ’dÿ¨Yö²WÀ¬^„—kTxy9^Œ?J—_A™“F’Î--KÈÇÿ™«ÿ¦¥ÿ±ÿº™ÿ¿˜ì¼›Ó³ ¾¦¦²›®µ“³Ã´Ù‘±ó†…º;/?8LJ&9-,  ve|)s-DX tcLb"O!2.9 ?=5D¼¥ÄOdºmV؆JÕœD»¨F‘¦Nc’[4siZvE|3:zZ<3;   <`žRQ³kE±€?—ŒAnŠJA|Weg Ms8y$.wJ/nw   v…Ÿ¨Šy§“wœ—x‹—{x‘h‡ˆ`}atko|p‹gggnestopia-1.51.1/projects/000077500000000000000000000000001411157722000152525ustar00rootroot00000000000000nestopia-1.51.1/projects/core.vcproj000066400000000000000000001623621411157722000174410ustar00rootroot00000000000000 nestopia-1.51.1/projects/core.vcxproj000066400000000000000000001416221411157722000176250ustar00rootroot00000000000000 Debug Win32 Release Win32 {CCC3A09C-0F7A-4E12-8594-11F2C60D71DA} Core Win32Proj StaticLibrary NotSet true StaticLibrary NotSet <_ProjectFileVersion>10.0.30319.1 $(SolutionDir)debugout\ debug\core\ $(SolutionDir)releaseout\ release\core\ AllRules.ruleset AllRules.ruleset /vmb /J %(AdditionalOptions) Disabled true NST_DEBUG;%(PreprocessorDefinitions) true true EnableFastChecks true MultiThreadedDebug Default true Precise true false true false Level4 ProgramDatabase FastCall false true false $(SolutionDir)..\lib\emucoredebug.lib true /vmb /J %(AdditionalOptions) Full AnySuitable true Speed true NDEBUG;_SECURE_SCL=0;%(PreprocessorDefinitions) true MultiThreaded false true NotSet Precise true true false AssemblyAndSourceCode $(SolutionDir)Release\Core\Asm\ Level4 FastCall true false $(SolutionDir)..\lib\emucore.lib true nestopia-1.51.1/projects/core.vcxproj.filters000066400000000000000000002126501411157722000212740ustar00rootroot00000000000000 {b355513c-0a44-4b8a-bd2e-e6c58ed616b1} {8c88ca9e-ae43-4c00-9abd-1a84ab83b2be} {2a5c4b59-8138-4e72-bc55-5d56b5bb4397} {efa1a91d-b937-42f2-8425-8c0c062f610c} {bed4c530-d8c7-4010-aa7b-a98603f6b8ee} {0147b3b3-220e-44d1-9700-7ebaddfcbc56} {5a75e4c8-5f01-4ad6-bb5e-5414f77c59cf} {6a86ab7f-2634-4e57-b61f-2d1de4be9b71} {77bd0d24-84dd-4806-8f84-4c27eac59c7d} {aecea58e-db9d-43b4-8460-2ce6a006a029} {fb11b05b-f38a-43e7-be3b-38e60bed92b9} Api Api Api Api Api Api Api Api Api Api Api Api Api Api Api Api Api VsSystem VsSystem VsSystem VsSystem VideoFilters VideoFilters VideoFilters VideoFilters VideoFilters VideoFilters\nes_ntsc VideoFilters\nes_ntsc VideoFilters\nes_ntsc Input Input Input Input Input Input Input Input Input Input Input Input Input Input Input Input Input Input Input Input Input Input Input Input Input Input Board Board Board Board Board Board Board Board Board Board Board Board Board Board Board Board Board Board Board Board Board Board Board Board Board\Custom Board\Custom Board\Custom Board\Custom Board\Custom Board\Custom Board\Custom Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Btl Board\Btl Board\Btl Board\Btl Board\Btl Board\Btl Board\Btl Board\Btl Board\Btl Board\Btl Board\Btl Board\Btl Board\Btl Board\Btl Board\Btl Board\Unl Board\Unl Board\Unl Board\Unl Board\Unl Board\Unl Board\Unl Board\Unl Board\Unl Board\Unl Board\Unl VideoFilters Board Board Board Board Board Api Api Api Api Api Api Api Api Api Api Api Api Api Api Api VsSystem VsSystem VsSystem VsSystem VideoFilters VideoFilters VideoFilters VideoFilters VideoFilters VideoFilters Input Input Input Input Input Input Input Input Input Input Input Input Input Input Input Input Input Input Input Input Input Input Input Input Input Board Board Board Board Board Board Board Board Board Board Board Board Board Board Board\Custom Board\Custom Board\Custom Board\Custom Board\Custom Board\Custom Board\Custom Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\3rdparty Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Bmc Board\Btl Board\Btl Board\Btl Board\Btl Board\Btl Board\Btl Board\Btl Board\Btl Board\Btl Board\Btl Board\Btl Board\Btl Board\Btl Board\Btl Board\Btl Board\Unl Board\Unl Board\Unl Board\Unl Board\Unl Board\Unl Board\Unl Board\Unl Board\Unl Board\Unl Board\Unl VideoFilters Board Board Board Board VideoFilters VideoFilters VideoFilters VideoFilters\nes_ntsc nestopia-1.51.1/projects/language.vcproj000066400000000000000000000101621411157722000202620ustar00rootroot00000000000000 nestopia-1.51.1/projects/language.vcxproj000066400000000000000000000154301411157722000204550ustar00rootroot00000000000000 Debug Win32 Release Win32 {C456E741-CF7A-455E-884B-B0F9F86E7C86} Language Win32Proj DynamicLibrary Unicode true DynamicLibrary Unicode <_ProjectFileVersion>10.0.30319.1 $(SolutionDir)debugout\language\ debug\language\ true $(SolutionDir)releaseout\language\ release\language\ false AllRules.ruleset AllRules.ruleset Disabled WIN32;_DEBUG;_WINDOWS;_USRDLL;LANGUAGE_EXPORTS;%(PreprocessorDefinitions) true true Default false MultiThreadedDebug Level4 ProgramDatabase false $(OutDir)english.nlg true true Windows true false MachineX86 Full AnySuitable true Size true WIN32;NDEBUG;_WINDOWS;_USRDLL;LANGUAGE_EXPORTS;%(PreprocessorDefinitions) true MultiThreadedDLL false true /J false Level4 false $(OutDir)english.nlg true false Windows true true true false MachineX86 {ccc3a09c-0f7a-4e12-8594-11f2c60d71da} false nestopia-1.51.1/projects/nestopia.sln000066400000000000000000000034541411157722000176200ustar00rootroot00000000000000 Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win32", "win32.vcxproj", "{7557C437-7013-4A87-B7C5-EA50699FC7B4}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core", "core.vcxproj", "{CCC3A09C-0F7A-4E12-8594-11F2C60D71DA}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "language", "language.vcxproj", "{C456E741-CF7A-455E-884B-B0F9F86E7C86}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {7557C437-7013-4A87-B7C5-EA50699FC7B4}.Debug|Win32.ActiveCfg = Debug|Win32 {7557C437-7013-4A87-B7C5-EA50699FC7B4}.Debug|Win32.Build.0 = Debug|Win32 {7557C437-7013-4A87-B7C5-EA50699FC7B4}.Release|Win32.ActiveCfg = Release|Win32 {7557C437-7013-4A87-B7C5-EA50699FC7B4}.Release|Win32.Build.0 = Release|Win32 {CCC3A09C-0F7A-4E12-8594-11F2C60D71DA}.Debug|Win32.ActiveCfg = Debug|Win32 {CCC3A09C-0F7A-4E12-8594-11F2C60D71DA}.Debug|Win32.Build.0 = Debug|Win32 {CCC3A09C-0F7A-4E12-8594-11F2C60D71DA}.Release|Win32.ActiveCfg = Release|Win32 {CCC3A09C-0F7A-4E12-8594-11F2C60D71DA}.Release|Win32.Build.0 = Release|Win32 {C456E741-CF7A-455E-884B-B0F9F86E7C86}.Debug|Win32.ActiveCfg = Debug|Win32 {C456E741-CF7A-455E-884B-B0F9F86E7C86}.Debug|Win32.Build.0 = Debug|Win32 {C456E741-CF7A-455E-884B-B0F9F86E7C86}.Release|Win32.ActiveCfg = Release|Win32 {C456E741-CF7A-455E-884B-B0F9F86E7C86}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution AMDCaProjectFile = EndGlobalSection EndGlobal nestopia-1.51.1/projects/win32.vcproj000066400000000000000000000750521411157722000174520ustar00rootroot00000000000000 nestopia-1.51.1/projects/win32.vcxproj000066400000000000000000000725361411157722000176460ustar00rootroot00000000000000 Debug Win32 Release Win32 {7557C437-7013-4A87-B7C5-EA50699FC7B4} Win32 Win32Proj Application Unicode true Application false Unicode <_ProjectFileVersion>10.0.30319.1 $(SolutionDir)debugout\ debug\win32\ true $(SolutionDir)releaseout\ release\win32\ false true AllRules.ruleset AllRules.ruleset $(DXSDK_DIR)Include;$(IncludePath) $(DXSDK_DIR)Lib\x86;$(LibraryPath) Nestopia Nestopia $(DXSDK_DIR)Include;$(IncludePath) $(DXSDK_DIR)Lib\x86;$(LibraryPath) /vmb /J %(AdditionalOptions) Disabled true C:\Program Files (x86)\Microsoft DirectX SDK (February 2010)\Include;%(AdditionalIncludeDirectories) NST_DEBUG;%(PreprocessorDefinitions) true true EnableFastChecks true MultiThreadedDebug true true Precise true false Level4 ProgramDatabase FastCall false false libcmtd.lib;unicows.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib $(OutDir)nestopia.exe $(DXSDK_DIR)Lib\x86;$(SolutionDir)..\lib;%(AdditionalLibraryDirectories) false libc;%(IgnoreSpecificDefaultLibraries) %(DelayLoadDLLs) true Windows false false MachineX86 true false /vmb /J %(AdditionalOptions) Full AnySuitable true Size true C:\Program Files (x86)\Microsoft DirectX SDK (February 2010)\Include;%(AdditionalIncludeDirectories) NDEBUG;_SECURE_SCL=0;%(PreprocessorDefinitions) true MultiThreaded false true NotSet Precise false false AssemblyAndSourceCode $(SolutionDir)release\win32\asm\ Level4 FastCall false false libcmt.lib;unicows.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib NotSet $(OutDir)nestopia.exe $(DXSDK_DIR)Lib\x86;$(SolutionDir)..\lib;%(AdditionalLibraryDirectories) %(AdditionalManifestDependencies) false libc;%(IgnoreSpecificDefaultLibraries) %(DelayLoadDLLs) false Windows true true false false MachineX86 copy /Y "%(FullPath)" "$(OutDir)" $(OutDir)%(Filename)%(Extension);%(Outputs) copy /Y "%(FullPath)" "$(OutDir)" $(OutDir)%(Filename)%(Extension);%(Outputs) copy /Y "%(FullPath)" "$(OutDir)" $(OutDir)%(Filename)%(Extension);%(Outputs) copy /Y "%(FullPath)" "$(OutDir)" $(OutDir)%(Filename)%(Extension);%(Outputs) copy /Y "%(FullPath)" "$(OutDir)" $(OutDir)%(Filename)%(Extension);%(Outputs) copy /Y "%(FullPath)" "$(OutDir)" $(OutDir)%(Filename)%(Extension);%(Outputs) copy /Y "%(FullPath)" "$(OutDir)" $(OutDir)%(Filename)%(Extension);%(Outputs) copy /Y "%(FullPath)" "$(OutDir)" $(OutDir)%(Filename)%(Extension);%(Outputs) {ccc3a09c-0f7a-4e12-8594-11f2c60d71da} false {c456e741-cf7a-455e-884b-b0f9f86e7c86} false nestopia-1.51.1/projects/win32.vcxproj.filters000066400000000000000000001004061411157722000213010ustar00rootroot00000000000000 {2d81b45d-7461-4e5c-917e-457b41457ae3} {6d4e4558-89e9-453d-9a80-83db682ffde9} {f393692b-7552-4aa0-a1be-49f0c188cf75} {334be6f9-507f-47fa-bf02-4318336c3e69} {7bf1491a-6084-4487-b589-18392facebab} {53193409-c8cc-4e84-b279-0e4da7e4fb1d} {a786ba23-27ba-408c-bd60-f6c4c1fbfb63} {a0830cb9-81d7-4a38-8f01-d1375e3b5cdc} {a58d41c6-b08c-4654-aa9c-35cc256c2953} {ce05fea4-48d6-4cba-93eb-229da45cdf2f} {e29ff767-efb2-4cb9-9638-26cc59d3cd98} {1ae99660-58e6-4d49-ba00-417410822ab6} {fbbef7c2-71e0-48b1-a79c-edc216199440} {c0f2da02-3927-45ca-a0cc-fc55d2b3db98} {302294f8-7408-4eac-ab06-13c71d2d9986} {53575f00-929e-4e7a-b8cf-5ffb07995a07} Application Application Application Application Application Collection Window Window Window Window Window Window Window Window Window Window Window Window Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Controls Window\Controls Window\Controls Window\Controls Window\Controls Window\Controls Window\Controls Window\Controls Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers IO IO IO IO IO IO Resource Resource Resource Resource Resource Resource Resource Resource Resource System System System System System System System System System String DirectX DirectX DirectX Application Application Application Application Application Collection Collection Collection Window Window Window Window Window Window Window Window Window Window Window Window Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Dialogs Window\Controls Window\Controls Window\Controls Window\Controls Window\Controls Window\Controls Window\Controls Window\Controls Window\Controls Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers Managers IO IO IO IO IO IO Object Object Object Object Resource Resource Resource Resource Resource Resource Resource Resource Resource Resource System System System System System System System System System String DirectX DirectX DirectX DirectX Collection Window Resource\Bitmaps Resource\Bitmaps Resource\Icons Resource\Icons Resource\Icons Resource\Icons Resource\Icons Resource\Icons Resource\Icons Resource\Icons Resource\Icons Resource\Icons Resource\Icons Resource\Icons Resource\Icons Resource\Files Resource\Files Resource\Files Resource Resource\Files Resource\Files Resource\Files Resource\Files nestopia-1.51.1/readme.html000066400000000000000000001076551411157722000155620ustar00rootroot00000000000000 Nestopia Documentation

Nestopia Documentation

version 1.40
last updated 8 June, 2008

Site: http://nestopia.sourceforge.net/
Mail: martin-freij at home.se


This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA


Table of Contents

For recent changes refer to the changelog.txt file.


Introduction

Nestopia is an open source NES/Famicom emulator written in standard C++, focused on delivering as accurate emulation as possible. Development began in mid 2002, initially released for the Windows platform a year later. It has since been ported to other platforms, including Linux and Mac OS X. See credits section for the list of authors involved.

Back to Top


Features

Boards:

  • ACCLAIM-AOROM
  • ACCLAIM-MC-ACC
  • ACCLAIM-TLROM
  • AGCI-47516
  • AGCI-50282
  • AVE-74*161
  • AVE-NINA-01
  • AVE-NINA-02
  • AVE-NINA-03
  • AVE-NINA-06
  • AVE-NINA-07
  • AVE-MB-91
  • BANDAI-74*161/161/32
  • BANDAI-CNROM
  • BANDAI-FCG-1
  • BANDAI-FCG-2
  • BANDAI-GNROM
  • BANDAI-JUMP2
  • BANDAI-LZ93D50+24C01
  • BANDAI-LZ93D50+24C02
  • BANDAI-NROM-128
  • BANDAI-NROM-256
  • BANDAI-PT-554
  • BMC-190IN1
  • BMC-42IN1RESETSWITCH
  • BMC-64IN1NOREPEAT
  • BMC-70IN1
  • BMC-70IN1B
  • BMC-8157
  • BMC-A65AS
  • BMC-BS-5
  • BMC-D1038
  • BMC-FK23C
  • BMC-GHOSTBUSTERS63IN1
  • BMC-GS-2004
  • BMC-GS-2013
  • BMC-NOVELDIAMOND9999999IN1
  • BMC-SUPER24IN1SC03
  • BMC-SUPERHIK8IN1
  • BMC-SUPERVISION16IN1
  • BMC-T-262
  • BMC-WS
  • BTL-MARIO1-MALEE2
  • CAMERICA-ALGN
  • CAMERICA-ALGQ
  • CAMERICA-BF9093
  • CAMERICA-BF9096
  • CAMERICA-BF9097
  • CAMERICA-GAMEGENIE
  • COLORDREAMS-74*377
  • DREAMTECH01
  • HVC-AMROM
  • HVC-AN1ROM
  • HVC-ANROM
  • HVC-AOROM
  • HVC-BNROM
  • HVC-CNROM
  • HVC-CPROM
  • HVC-DE1ROM
  • HVC-DEROM
  • HVC-DRROM
  • HVC-EKROM
  • HVC-ELROM
  • HVC-ETROM
  • HVC-EWROM
  • HVC-FAMILYBASIC
  • HVC-FJROM
  • HVC-FKROM
  • HVC-GNROM
  • HVC-HKROM
  • HVC-HROM
  • HVC-JLROM
  • HVC-JSROM
  • HVC-MHROM
  • HVC-NROM
  • HVC-NROM-128
  • HVC-NROM-256
  • HVC-NTBROM
  • HVC-PEEOROM
  • HVC-PNROM
  • HVC-RROM
  • HVC-RROM-128
  • HVC-SAROM
  • HVC-SBROM
  • HVC-SC1ROM
  • HVC-SCROM
  • HVC-SEROM
  • HVC-SF1ROM
  • HVC-SFROM
  • HVC-SGROM
  • HVC-SH1ROM
  • HVC-SHROM
  • HVC-SJROM
  • HVC-SKROM
  • HVC-SL1ROM
  • HVC-SL2ROM
  • HVC-SL3ROM
  • HVC-SLROM
  • HVC-SLRROM
  • HVC-SNROM
  • HVC-SOROM
  • HVC-SROM
  • HVC-STROM
  • HVC-SUROM
  • HVC-SXROM
  • HVC-TBROM
  • HVC-TEROM
  • HVC-TFROM
  • HVC-TGROM
  • HVC-TKROM
  • HVC-TKSROM
  • HVC-TL1ROM
  • HVC-TL2ROM
  • HVC-TLROM
  • HVC-TLSROM
  • HVC-TNROM
  • HVC-TQROM
  • HVC-TR1ROM
  • HVC-TSROM
  • HVC-TVROM
  • HVC-UN1ROM
  • HVC-UNROM
  • HVC-UOROM
  • IREM-74*161/161/21/138
  • IREM-BNROM
  • IREM-G101
  • IREM-G101-A
  • IREM-G101-B
  • IREM-HOLYDIVER
  • IREM-NROM-128
  • IREM-NROM-256
  • IREM-UNROM
  • JALECO-JF-01
  • JALECO-JF-02
  • JALECO-JF-03
  • JALECO-JF-04
  • JALECO-JF-05
  • JALECO-JF-06
  • JALECO-JF-07
  • JALECO-JF-08
  • JALECO-JF-09
  • JALECO-JF-10
  • JALECO-JF-11
  • JALECO-JF-12
  • JALECO-JF-13
  • JALECO-JF-14
  • JALECO-JF-15
  • JALECO-JF-16
  • JALECO-JF-17
  • JALECO-JF-18
  • JALECO-JF-19
  • JALECO-JF-20
  • JALECO-JF-21
  • JALECO-JF-22
  • JALECO-JF-23
  • JALECO-JF-24
  • JALECO-JF-25
  • JALECO-JF-26
  • JALECO-JF-27
  • JALECO-JF-28
  • JALECO-JF-29
  • JALECO-JF-30
  • JALECO-JF-31
  • JALECO-JF-32
  • JALECO-JF-33
  • JALECO-JF-34
  • JALECO-JF-35
  • JALECO-JF-36
  • JALECO-JF-37
  • JALECO-JF-38
  • JALECO-JF-39
  • JALECO-JF-40
  • JALECO-JF-41
  • KONAMI-74*139/74
  • KONAMI-CNROM
  • KONAMI-NROM-128
  • KONAMI-SLROM
  • KONAMI-TLROM
  • KONAMI-UNROM
  • KONAMI-VRC-1
  • KONAMI-VRC-2
  • KONAMI-VRC-3
  • KONAMI-VRC-4
  • KONAMI-VRC-6
  • KONAMI-VRC-7
  • MLT-ACTION52
  • MLT-CALTRON6IN1
  • MLT-MAXI15
  • NAMCOT-163
  • NAMCOT-3301
  • NAMCOT-3302
  • NAMCOT-3303
  • NAMCOT-3305
  • NAMCOT-3311
  • NAMCOT-3401
  • NAMCOT-3405
  • NAMCOT-3406
  • NAMCOT-3407
  • NAMCOT-3411
  • NAMCOT-3413
  • NAMCOT-3414
  • NAMCOT-3415
  • NAMCOT-3416
  • NAMCOT-3417
  • NAMCOT-3425
  • NAMCOT-3433
  • NAMCOT-3443
  • NAMCOT-3446
  • NAMCOT-3451
  • NES-AMROM
  • NES-AN1ROM
  • NES-ANROM
  • NES-AOROM
  • NES-B4
  • NES-BNROM
  • NES-BTR
  • NES-CNROM
  • NES-CPROM
  • NES-DE1ROM
  • NES-DEROM
  • NES-DRROM
  • NES-EKROM
  • NES-ELROM
  • NES-ETROM
  • NES-EVENT
  • NES-EWROM
  • NES-FJROM
  • NES-FKROM
  • NES-GNROM
  • NES-HKROM
  • NES-HROM
  • NES-JLROM
  • NES-JSROM
  • NES-MHROM
  • NES-NROM
  • NES-NROM-128
  • NES-NROM-256
  • NES-NTBROM
  • NES-PEEOROM
  • NES-PNROM
  • NES-QJ
  • NES-RROM
  • NES-RROM-128
  • NES-SAROM
  • NES-SBROM
  • NES-SC1ROM
  • NES-SCROM
  • NES-SEROM
  • NES-SF1ROM
  • NES-SFROM
  • NES-SGROM
  • NES-SH1ROM
  • NES-SHROM
  • NES-SJROM
  • NES-SKROM
  • NES-SL1ROM
  • NES-SL2ROM
  • NES-SL3ROM
  • NES-SLROM
  • NES-SLRROM
  • NES-SNROM
  • NES-SOROM
  • NES-SROM
  • NES-STROM
  • NES-SUROM
  • NES-SXROM
  • NES-TBROM
  • NES-TEROM
  • NES-TFROM
  • NES-TGROM
  • NES-TKROM
  • NES-TKSROM
  • NES-TL1ROM
  • NES-TL2ROM
  • NES-TLROM
  • NES-TLSROM
  • NES-TNROM
  • NES-TQROM
  • NES-TR1ROM
  • NES-TSROM
  • NES-TVROM
  • NES-UN1ROM
  • NES-UNROM
  • NES-UOROM
  • NES-WH
  • NTDEC-N715062
  • PAL-MH
  • PAL-ZZ
  • SACHEN-8259A
  • SACHEN-8259B
  • SACHEN-8259C
  • SACHEN-8259D
  • SACHEN-CNROM
  • SETA-NROM-128
  • SUNSOFT-1
  • SUNSOFT-2
  • SUNSOFT-3
  • SUNSOFT-4
  • SUNSOFT-5B
  • SUNSOFT-FME-7
  • SUNSOFT-NROM-256
  • TAITO-74*139/74
  • TAITO-74*161/161/32
  • TAITO-CNROM
  • TAITO-NROM-128
  • TAITO-NROM-256
  • TAITO-TC0190FMC
  • TAITO-TC0190FMC+PAL16R4
  • TAITO-UNROM
  • TAITO-X1-005
  • TAITO-X1-017
  • TENGEN-800002
  • TENGEN-800003
  • TENGEN-800004
  • TENGEN-800008
  • TENGEN-800030
  • TENGEN-800032
  • TENGEN-800037
  • TENGEN-800042
  • UNL-22211
  • UNL-603-5052
  • UNL-8237
  • UNL-A9746
  • UNL-AX5705
  • UNL-CC-21
  • UNL-EDU2000
  • UNL-H2288
  • UNL-KOF97
  • UNL-KS7032
  • UNL-N625092
  • UNL-SA-0036
  • UNL-SA-0037
  • UNL-SA-016-1M
  • UNL-SA-72007
  • UNL-SA-72008
  • UNL-SA-NROM
  • UNL-SACHEN-74LS374N
  • UNL-SACHEN-8259A
  • UNL-SACHEN-8259B
  • UNL-SACHEN-8259C
  • UNL-SACHEN-8259D
  • UNL-SHERO
  • UNL-SL1632
  • UNL-SMB2J
  • UNL-T-230
  • UNL-TC-U01-1.5M
  • UNL-TEK90
  • UNL-TF1201
  • VIRGIN-SNROM

iNES Mappers:

  • 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
  • 17, 18, 19,*21, 22,*23, 24,*25, 26, 27, 32, 33, 34, 36,
  • 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
  • 51, 52, 53, 54, 55, 56, 57, 58, 60, 61, 62, 63, 64, 65,
  • 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
  • 80, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
  • 96, 97, 99, 103, 104, 105, 106, 107, 108, 112, 113, 114,
  • 115, 116, 117, 118, 119, 120, 121, 123, 126, 132, 133, 134,
  • 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147,
  • 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
  • 163, 164, 165, 166, 167, 170, 171, 172, 173, 175, 176, 177,
  • 178, 179, 180, 182, 183, 184,*185, 186, 187, 188, 189, 191,
  • 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203,
  • 204, 205, 206, 207, 208, 209, 211, 212, 213, 214, 215, 216,
  • 217, 219, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230,
  • 231, 232, 233, 234, 235, 236, 238, 240, 241, 242, 243, 244,
  • 245, 246, 249, 250, 252, 254, 255

    * only supported if PIN wiring info is available through a database or ROM set.

External Sound Chips:

  • Konami VRC6
  • Konami VRC7
  • MMC5
  • Namcot 163
  • RP2C33
  • Sunsoft 5B

Controllers:

  • Arkanoid (1)
  • Crazy Climber Sticks
  • Doremikko Keyboard
  • Exciting Boxing Bop Bag
  • Family BASIC Keyboard
  • Family Computer Robot / R.O.B.
  • Family Trainer / Family Fun Fitness / Power Pad
  • Hori Track (1)
  • Hyper Shot
  • Light Gun (1)
  • Mahjong Controller
  • Oeka Kids Tablet (1)
  • Pachinko Controller (2)
  • Party Tap
  • Pokkun Moguraa
  • Power Glove (1)
  • Standard Pad
  • Subor Keyboard + Mouse
  • Top Rider Bike

    (1) Using the mouse
    (2) Using the mouse wheel

Other Peripherals/Systems:

  • Bandai Karaoke Studio
  • Barcode Battler
  • Data Recorder
  • Datach Joint ROM System
  • Famicom Disk System
  • Game Genie & Pro Action Rocky
  • Turbo File
  • VS System

Image File Formats:

  • ROM images backed by XML descriptor (.zip)
  • UNIF (.unf)
  • iNES (.nes)
  • FDS with/without headers (.fds)

Extras:

  • Savestates / Saveslots
  • PNG/JPEG/BMP File Screenshots
  • Movie/AVI File Recording
  • WAVE File Recording
  • ZIP/RAR/7zip Archive Support
  • On-the-fly IPS Patching
  • Netplay
  • NSF Player
  • Video Filters including NTSC video emulation
  • Real-time Rewinding
  • Cheat Searching
  • Databases of cartridge info
  • File Launcher
  • Palette Editor
  • iNES File Header Editor

Recognized VS System Games:

Name Dip Switch Info
Battle City partial
Castlevania full
Clu Clu Land partial
Dr. Mario full
Duck Hunt full
Excitebike full
Freedom Force partial
Golf full
Goonies full
Gradius full
Gumshoe full
Hogan's Alley full
Ice Climber full
Lady Golf full
Mach Rider partial
Mach Rider - Fighting Course partial
Mighty Bomb Jack partial
Ninja Jajamaru Kun partial
Pinball partial
Platoon partial
Raid on Bungeling Bay partial
RBI Baseball full
Sky Kid full
Slalom full
Soccer full
Star Luster partial
Stroke and Match Golf full
Super Mario Bros full
Super Xevious partial
Tetris partial
TKO Boxing partial
Top Gun full

Games with Sound Sample Support:

Game File Archive Name Number of Samples
Family Trainer - Aerobics Studio ftaerobi 8
Moero!! Pro Yakyuu moepro 16
Moero!! Pro Yakyuu '88 - Ketteiban moepro88 20
Moe Pro! '90 - Kandou Hen
Moe Pro! - Saikyou Hen
Shin Moero!! Pro Yakyuu
Moero!! Pro Tennis mptennis 19
Terao no Dosukoi Oozumou terao 6

Samples must be in MS Wave format and use indexed naming convention, i.e. 00.wav, 01.wav and so on.
The compression format may be zip, rar or 7zip. The archives must be placed in the directory specified
in the Paths Settings (defaulted to .\samples).

Mappers/Boards with DIP switches:

  • 57, 60, 83, 90, 105, 150, 209, 211, 230, 233, 236
  • UNIF Boards: 8157, BS-5, FK23C, StreetHeroes
  • Family BASIC, Playbox BASIC, VS System

Back to Top


System Requirements

Minimum
Processor Pentium III +800 MHz or comparable AMD
Video Direct3D 9.0 compatible graphic card
OS Windows 98/Me/2000/XP (*)
Software DirectX 9.0c or later

(*) Win98/Me users need to obtain the Unicode Layer DLL (unicows.dll) from Microsoft's site and place it in the same directory as Nestopia. It can be downloaded from here.

Recommended
Processor Pentium 4 +1400 MHz or comparable AMD
Video Direct3D 9.0 compatible graphic card
Sound DirectSound 8.1 compatible sound card
OS Windows XP
Software DirectX 9.0c or later

Back to Top


Troubleshooting

If you experience slow performance with Nestopia, here are a couple of things you can try to speed it up:

  • Lower the screen resolution and/or pixel bit-depth (video dialog).
  • Disable video filtering effects (video dialog).
  • Change the NES screen memory location (video dialog)
  • Enable triple-buffering (timing dialog).
  • Enable auto-frame-skipping (timing dialog).
  • Disable vsync (timing dialog).
  • Disable the rewinder (timing dialog).
  • Change the application priority to "above normal" or "high" (preferences dialog).
  • Lower the sound frequency and/or sample bit-depth or disable sound output completely (sound dialog).
  • If your video driver has an option for vsync, make sure it's set to be application-controlled.

If you have trouble running a particular game, possible reasons could be:

  • It's a bad dump.
  • The image comes with incorrect or insufficient emulation information.
  • Does it work on the actual hardware? If not, it's not supposed to work on Nestopia either.
  • It has been hacked solely for the purpose of making it run on another emulator.
  • Wrong region setting, try switching to/from PAL.
  • Proper controller(s) connected? For instance, it could be a keyboard-only program or a game that only responds to the secondary controller.
  • Is the 'no sprite limit' option enabled? Try disabling it, some games might depend on this hardware limitation.
  • The database may have an error in it. Try turning it off temporarily.
  • It's unsupported by Nestopia.

Misc:

  • If the gridlines are not drawn properly in the launcher dialog, follow this link.

Back to Top


Credits

Author Contribution
[yang] Image file database
Alexander Roshal UnRAR
Andrea Mazzoleni ScaleX filters
Bootgod Cartridges info
Brad Taylor PPU and APU technical documents
CaH4e3 Mapper info
Chris Covell General info
Christophe Thibault Kaillera
Derek Liauw Kie Fa 2xSaI filter
Enri Famicom peripherals info
FireBug Mapper documents
Gilles Vollant UnZIP library
Goroh Various technical documents
hap D7756C info
Hellsbane Testing
Igor Pavlov 7-Zip
Jean-loup Gailly zlib
Jeremy Chadwick NES technical document
John West 65xx/85xx technical document
Kevin Horton Mapper technical documents
Ki CPU and APU info
Loopy PPU info
MAME dev. team VS System info
Marat Fayzullin NES technical document
Mark Adler zlib
Mark Knibbs Various info
Marko Mäkelä 65xx/85xx technical document
Matthew Conte APU info
Maxim Stepin hqx filters
NewRisingSun NTSC info
Norix Mapper, FDS sound and Famicom peripherals info
Pongbashi Famicom, cartridges, and sound sample info
Quietust PPU info
Richard Hoelscher Famicom four-player adapter technical document
Shay Green (aka blargg) nes_ntsc, APU and PPU info
The Mad Dumper Mapper info
Xodnizel Mapper info

Translations

Author Language
Benjamin Siskoo French
Gubei Vadim Russian
Martin Polish
Nekokabu Japanese
nhlay Chinese (traditional)
Vecna Italian
yoyo Chinese (simplified)

Ports

Author Platform
Arbee Linux
Daemoncollector Mac OS X
Richard Bannister Mac OS X (alt. license)


Back to Top


Nestopia is Copyright © 2003-2008 by Martin Freij.

NES is either a trademark or registered trademark of Nintendo of America Inc.
Famicom is either a trademark or registered trademark of Nintendo Co., LTD.
All other trademarks are property of their respective owners.
Nestopia is not affiliated with or endorsed by any of the companies mentioned.

nestopia-1.51.1/schemadb.xsd000066400000000000000000001015371411157722000157160ustar00rootroot00000000000000 nestopia-1.51.1/schemaromset.xsd000066400000000000000000001015211411157722000166330ustar00rootroot00000000000000 nestopia-1.51.1/source/000077500000000000000000000000001411157722000147215ustar00rootroot00000000000000nestopia-1.51.1/source/7zip/000077500000000000000000000000001411157722000156125ustar00rootroot00000000000000nestopia-1.51.1/source/7zip/IArchive.h000066400000000000000000000103351411157722000174570ustar00rootroot00000000000000// IArchive.h #ifndef __IARCHIVE_H #define __IARCHIVE_H #include "IStream.h" #include "IProgress.h" #include "PropID.h" // MIDL_INTERFACE("23170F69-40C1-278A-0000-000600xx0000") #define ARCHIVE_INTERFACE_SUB(i, base, x) \ DEFINE_GUID(IID_ ## i, \ 0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x06, 0x00, x, 0x00, 0x00); \ struct i: public base #define ARCHIVE_INTERFACE(i, x) ARCHIVE_INTERFACE_SUB(i, IUnknown, x) namespace NFileTimeType { enum EEnum { kWindows, kUnix, kDOS }; } namespace NArchive { enum { kName = 0, kClassID, kExtension, kAddExtension, kUpdate, kKeepName, kStartSignature, kFinishSignature, kAssociate }; namespace NExtract { namespace NAskMode { enum { kExtract = 0, kTest, kSkip }; } namespace NOperationResult { enum { kOK = 0, kUnSupportedMethod, kDataError, kCRCError }; } } namespace NUpdate { namespace NOperationResult { enum { kOK = 0, kError }; } } } ARCHIVE_INTERFACE(IArchiveOpenCallback, 0x10) { STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes) PURE; STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes) PURE; }; ARCHIVE_INTERFACE_SUB(IArchiveExtractCallback, IProgress, 0x20) { STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) PURE; // GetStream OUT: S_OK - OK, S_FALSE - skeep this file STDMETHOD(PrepareOperation)(Int32 askExtractMode) PURE; STDMETHOD(SetOperationResult)(Int32 resultEOperationResult) PURE; }; ARCHIVE_INTERFACE(IArchiveOpenVolumeCallback, 0x30) { STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value) PURE; STDMETHOD(GetStream)(const wchar_t *name, IInStream **inStream) PURE; }; ARCHIVE_INTERFACE(IInArchiveGetStream, 0x40) { STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream) PURE; }; ARCHIVE_INTERFACE(IArchiveOpenSetSubArchiveName, 0x50) { STDMETHOD(SetSubArchiveName)(const wchar_t *name) PURE; }; ARCHIVE_INTERFACE(IInArchive, 0x60) { STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openArchiveCallback) PURE; STDMETHOD(Close)() PURE; STDMETHOD(GetNumberOfItems)(UInt32 *numItems) PURE; STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) PURE; STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) PURE; // indices must be sorted // numItems = 0xFFFFFFFF means all files // testMode != 0 means "test files operation" STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value) PURE; STDMETHOD(GetNumberOfProperties)(UInt32 *numProperties) PURE; STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) PURE; STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProperties) PURE; STDMETHOD(GetArchivePropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) PURE; }; ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback, IProgress, 0x80) { STDMETHOD(GetUpdateItemInfo)(UInt32 index, Int32 *newData, // 1 - new data, 0 - old data Int32 *newProperties, // 1 - new properties, 0 - old properties UInt32 *indexInArchive // -1 if there is no in archive, or if doesn't matter ) PURE; STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) PURE; STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **inStream) PURE; STDMETHOD(SetOperationResult)(Int32 operationResult) PURE; }; ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback2, IArchiveUpdateCallback, 0x82) { STDMETHOD(GetVolumeSize)(UInt32 index, UInt64 *size) PURE; STDMETHOD(GetVolumeStream)(UInt32 index, ISequentialOutStream **volumeStream) PURE; }; ARCHIVE_INTERFACE(IOutArchive, 0xA0) { STDMETHOD(UpdateItems)(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback) PURE; STDMETHOD(GetFileTimeType)(UInt32 *type) PURE; }; ARCHIVE_INTERFACE(ISetProperties, 0x03) { STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties) PURE; }; #endif nestopia-1.51.1/source/7zip/IProgress.h000066400000000000000000000014641411157722000177050ustar00rootroot00000000000000// Interface/IProgress.h #ifndef __IPROGRESS_H #define __IPROGRESS_H #include "MyUnknown.h" #include "Types.h" // {23170F69-40C1-278A-0000-000000050000} DEFINE_GUID(IID_IProgress, 0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00); MIDL_INTERFACE("23170F69-40C1-278A-0000-000000050000") IProgress: public IUnknown { STDMETHOD(SetTotal)(UInt64 total) PURE; STDMETHOD(SetCompleted)(const UInt64 *completeValue) PURE; }; /* // {23170F69-40C1-278A-0000-000000050002} DEFINE_GUID(IID_IProgress2, 0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02); MIDL_INTERFACE("23170F69-40C1-278A-0000-000000050002") IProgress2: public IUnknown { public: STDMETHOD(SetTotal)(const UInt64 *total) PURE; STDMETHOD(SetCompleted)(const UInt64 *completeValue) PURE; }; */ #endif nestopia-1.51.1/source/7zip/IStream.h000066400000000000000000000032311411157722000173260ustar00rootroot00000000000000// IStream.h #ifndef __ISTREAM_H #define __ISTREAM_H #include "MyUnknown.h" #include "Types.h" // "23170F69-40C1-278A-0000-000300xx0000" #define STREAM_INTERFACE_SUB(i, b, x) \ DEFINE_GUID(IID_ ## i, \ 0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x03, 0x00, x, 0x00, 0x00); \ struct i: public b #define STREAM_INTERFACE(i, x) STREAM_INTERFACE_SUB(i, IUnknown, x) STREAM_INTERFACE(ISequentialInStream, 0x01) { STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize) PURE; /* Out: if size != 0, return_value = S_OK and (*processedSize == 0), then there are no more bytes in stream. if (size > 0) && there are bytes in stream, this function must read at least 1 byte. This function is allowed to read less than number of remaining bytes in stream. You must call Read function in loop, if you need exact amount of data */ }; STREAM_INTERFACE(ISequentialOutStream, 0x02) { STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize) PURE; /* if (size > 0) this function must write at least 1 byte. This function is allowed to write less than "size". You must call Write function in loop, if you need to write exact amount of data */ }; STREAM_INTERFACE_SUB(IInStream, ISequentialInStream, 0x03) { STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) PURE; }; STREAM_INTERFACE_SUB(IOutStream, ISequentialOutStream, 0x04) { STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) PURE; STDMETHOD(SetSize)(Int64 newSize) PURE; }; STREAM_INTERFACE(IStreamGetSize, 0x06) { STDMETHOD(GetSize)(UInt64 *size) PURE; }; STREAM_INTERFACE(IOutStreamFlush, 0x07) { STDMETHOD(Flush)() PURE; }; #endif nestopia-1.51.1/source/7zip/MyUnknown.h000066400000000000000000000004421411157722000177300ustar00rootroot00000000000000// MyUnknown.h #ifndef __MYUNKNOWN_H #define __MYUNKNOWN_H #ifdef _WIN32 #ifdef _WIN32_WCE #if (_WIN32_WCE > 300) #include #else #define MIDL_INTERFACE(x) struct #endif #else #include #endif #include #else #include "MyWindows.h" #endif #endif nestopia-1.51.1/source/7zip/PropID.h000066400000000000000000000013441411157722000171220ustar00rootroot00000000000000// Interface/PropID.h #ifndef __INTERFACE_PROPID_H #define __INTERFACE_PROPID_H enum { kpidNoProperty = 0, kpidHandlerItemIndex = 2, kpidPath, kpidName, kpidExtension, kpidIsFolder, kpidSize, kpidPackedSize, kpidAttributes, kpidCreationTime, kpidLastAccessTime, kpidLastWriteTime, kpidSolid, kpidCommented, kpidEncrypted, kpidSplitBefore, kpidSplitAfter, kpidDictionarySize, kpidCRC, kpidType, kpidIsAnti, kpidMethod, kpidHostOS, kpidFileSystem, kpidUser, kpidGroup, kpidBlock, kpidComment, kpidPosition, kpidTotalSize = 0x1100, kpidFreeSpace, kpidClusterSize, kpidVolumeName, kpidLocalName = 0x1200, kpidProvider, kpidUserDefined = 0x10000 }; #endif nestopia-1.51.1/source/7zip/Types.h000066400000000000000000000005471411157722000170750ustar00rootroot00000000000000// Common/Types.h #ifndef __COMMON_TYPES_H #define __COMMON_TYPES_H typedef unsigned char Byte; typedef short Int16; typedef unsigned short UInt16; typedef int Int32; typedef unsigned int UInt32; #ifdef _MSC_VER typedef __int64 Int64; typedef unsigned __int64 UInt64; #else typedef long long int Int64; typedef unsigned long long int UInt64; #endif #endif nestopia-1.51.1/source/7zip/readme.txt000066400000000000000000000150061411157722000176120ustar00rootroot000000000000007-Zip 4.27 Sources ------------------ 7-Zip is a file archiver for Windows 95/98/ME/NT/2000/2003/XP. 7-Zip Copyright (C) 1999-2005 Igor Pavlov. License Info ------------ Most of 7-Zip source code is under GNU LGPL. Files in folders 7zip/Compress/Rar20 7zip/Compress/Rar29 7zip/Compress/Rar29/Original are licensed under "unRAR license + GNU LGPL" license. Source code files in all other folders of this package are under GNU LGPL. "unRAR license + GNU LGPL" means that you must follow GNU LGPL in all aspects while it is in agreement with unRAR license. But you can not break unRAR license rules. It means that unRAR license is main license in that pair. You can find unRAR license in file unrarLicense.txt You can find GNU LGPL license in file copying.txt GNU LGPL information: --------------------- This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA unRAR license + GNU LGPL Notes ------------------------------ Please check main restriction from unRar license: 2. The unRAR sources may be used in any software to handle RAR archives without limitations free of charge, but cannot be used to re-create the RAR compression algorithm, which is proprietary. Distribution of modified unRAR sources in separate form or as a part of other software is permitted, provided that it is clearly stated in the documentation and source comments that the code may not be used to develop a RAR (WinRAR) compatible archiver. In brief it means: 1) You can compile and use compiled files under GNU LGPL rules, since unRAR license almost has no restrictions for compiled files. You can link these compiled files to LGPL programs. 2) You can fix bugs in source code and use compiled fixed version. 3) You can not use unRAR sources to re-create the RAR compression algorithm. 7zip\Compress\Rar29\Original folder contains files that are modified versions of original unRAR source code files. License notes ------------- You can support development of 7-Zip by registering. 7-Zip is free software distributed under the GNU LGPL. If you need license with other conditions, write to http://www.7-zip.org/support.html --- Also this package contains files from LZMA SDK you can download LZMA SDK from this page: http://www.7-zip.org/sdk.html read about addtional licenses for LZMA SDK in file DOC/lzma.txt How to compile -------------- To compile sources you need Visual C++ 6.0. For compiling some files you also need new Platform SDK from Microsoft' Site: http://www.microsoft.com/msdownload/platformsdk/sdkupdate/psdk-full.htm or http://www.microsoft.com/msdownload/platformsdk/sdkupdate/XPSP2FULLInstall.htm or http://www.microsoft.com/msdownload/platformsdk/sdkupdate/ If you use MSVC6, specify SDK directories at top of directories lists: Tools / Options / Directories - Include files - Library files To compile 7-Zip for AMD64 and IA64 you need: Windows Server 2003 SP1 Platform SDK from microsoft.com Compiling under Unix/Linux -------------------------- Check this site for Posix/Linux version: http://sourceforge.net/projects/p7zip/ Notes: ------ 7-Zip consists of COM modules (DLL files). But 7-Zip doesn't use standard COM interfaces for creating objects. Look at 7zip\UI\Client7z folder for example of using DLL files of 7-Zip. Some DLL files can use other DLL files from 7-Zip. If you don't like it, you must use standalone version of DLL. To compile standalone version of DLL you must include all used parts to project and define some defs. For example, 7zip\Bundles\Format7z is a standalone version of 7z.dll that works with 7z format. So you can use such DLL in your project without additional DLL files. Description of 7-Zip sources package ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DOC Documentation --- 7zFormat.txt - 7z format description copying.txt - GNU LGPL license unRarLicense.txt - License for unRAR part of source code history.txt - Sources history Methods.txt - Compression method IDs readme.txt - Readme file lzma.txt - LZMA SDK description 7zip.nsi - installer script for NSIS Common Common modules Windows Win32 wrappers 7zip ------- Common Common modules for 7-zip Archive 7-Zip Archive Format Plugins -------- Common 7z Arj BZip2 Cab Cpio GZip Rar Rpm Split Tar Zip Bundle Modules that are bundles of other modules ------ Alone 7za.exe: Standalone version of 7z SFXCon 7zCon.sfx: Console 7z SFX module SFXWin 7z.sfx: Windows 7z SFX module SFXSetup 7zS.sfx: Windows 7z SFX module for Installers Format7z 7za.dll: Standalone version of 7z.dll UI -- Agent Intermediary modules for FAR plugin and Explorer plugin Console 7z.exe Console version Explorer Explorer plugin Resource Resources Far FAR plugin Client7z Test application for 7za.dll Compress -------- BZip2 BZip2 compressor Original Download BZip2 compression sources from http://sources.redhat.com/bzip2/index.html to that folder. Branch Branch converter ByteSwap Byte Swap converter Copy Copy coder Deflate Implode Arj LZMA PPMd Dmitry Shkarin's PPMdH with small changes. LZ Lempel - Ziv MT Multi Thread Match finder BinTree Match Finder based on Binary Tree Patricia Match Finder based on Patricia algoritm HashChain Match Finder based on Hash Chains Crypto Crypto modules ------ 7zAES Cipher for 7z AES AES Cipher Rar20 Cipher for Rar 2.0 RarAES Cipher for Rar 3.0 Zip Cipher for Zip FileManager File Manager --- Igor Pavlov http://www.7-zip.org --- End of document nestopia-1.51.1/source/core/000077500000000000000000000000001411157722000156515ustar00rootroot00000000000000nestopia-1.51.1/source/core/NstApu.cpp000066400000000000000000001675351411157722000176100ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstCpu.hpp" #include "NstState.hpp" #include "api/NstApiSound.hpp" #include "NstSoundRenderer.inl" namespace Nes { namespace Core { const dword Apu::Cycles::frameClocks[3][4] = { { CPU_RP2A03_CC * 29830UL, CPU_RP2A03_CC, CPU_RP2A03_CC, CPU_RP2A03_CC * (29830UL - 2), }, { CPU_RP2A07_CC * 33254UL, CPU_RP2A07_CC, CPU_RP2A07_CC, CPU_RP2A07_CC * (33254UL - 2) }, { CPU_DENDY_CC * 29830UL, CPU_DENDY_CC, CPU_DENDY_CC, CPU_DENDY_CC * (29830UL - 2), } }; const dword Apu::Cycles::oscillatorClocks[3][2][4] = { { { CPU_RP2A03_CC * (7459UL - 1), CPU_RP2A03_CC * 7456UL, CPU_RP2A03_CC * 7458UL, CPU_RP2A03_CC * 7458UL }, { CPU_RP2A03_CC * 7458UL, CPU_RP2A03_CC * 7456UL, CPU_RP2A03_CC * 7458UL, CPU_RP2A03_CC * (7458UL + 7452) } }, { { CPU_RP2A07_CC * (8315UL - 1), CPU_RP2A07_CC * 8314UL, CPU_RP2A07_CC * 8312UL, CPU_RP2A07_CC * 8314UL }, { CPU_RP2A07_CC * 8314UL, CPU_RP2A07_CC * 8314UL, CPU_RP2A07_CC * 8312UL, CPU_RP2A07_CC * (8314UL + 8312) } }, { { CPU_DENDY_CC * (7459UL - 1), CPU_DENDY_CC * 7456UL, CPU_DENDY_CC * 7458UL, CPU_DENDY_CC * 7458UL }, { CPU_DENDY_CC * 7458UL, CPU_DENDY_CC * 7456UL, CPU_DENDY_CC * 7458UL, CPU_DENDY_CC * (7458UL + 7452) } } }; const byte Apu::Channel::LengthCounter::lut[32] = { 0x0A, 0xFE, 0x14, 0x02, 0x28, 0x04, 0x50, 0x06, 0xA0, 0x08, 0x3C, 0x0A, 0x0E, 0x0C, 0x1A, 0x0E, 0x0C, 0x10, 0x18, 0x12, 0x30, 0x14, 0x60, 0x16, 0xC0, 0x18, 0x48, 0x1A, 0x10, 0x1C, 0x20, 0x1E }; const word Apu::Noise::lut[3][16] = { { 0x004, 0x008, 0x010, 0x020, 0x040, 0x060, 0x080, 0x0A0, 0x0CA, 0x0FE, 0x17C, 0x1FC, 0x2FA, 0x3F8, 0x7F2, 0xFE4 }, { 0x004, 0x007, 0x00E, 0x01E, 0x03C, 0x058, 0x076, 0x094, 0x0BC, 0x0EC, 0x162, 0x1D8, 0x2C4, 0x3B0, 0x762, 0xEC2 }, { 0x004, 0x008, 0x010, 0x020, 0x040, 0x060, 0x080, 0x0A0, 0x0CA, 0x0FE, 0x17C, 0x1FC, 0x2FA, 0x3F8, 0x7F2, 0xFE4 } }; const word Apu::Dmc::lut[3][16] = { { 0x1AC * CPU_RP2A03_CC, 0x17C * CPU_RP2A03_CC, 0x154 * CPU_RP2A03_CC, 0x140 * CPU_RP2A03_CC, 0x11E * CPU_RP2A03_CC, 0x0FE * CPU_RP2A03_CC, 0x0E2 * CPU_RP2A03_CC, 0x0D6 * CPU_RP2A03_CC, 0x0BE * CPU_RP2A03_CC, 0x0A0 * CPU_RP2A03_CC, 0x08E * CPU_RP2A03_CC, 0x080 * CPU_RP2A03_CC, 0x06A * CPU_RP2A03_CC, 0x054 * CPU_RP2A03_CC, 0x048 * CPU_RP2A03_CC, 0x036 * CPU_RP2A03_CC }, { 0x18E * CPU_RP2A07_CC, 0x162 * CPU_RP2A07_CC, 0x13C * CPU_RP2A07_CC, 0x12A * CPU_RP2A07_CC, 0x114 * CPU_RP2A07_CC, 0x0EC * CPU_RP2A07_CC, 0x0D2 * CPU_RP2A07_CC, 0x0C6 * CPU_RP2A07_CC, 0x0B0 * CPU_RP2A07_CC, 0x094 * CPU_RP2A07_CC, 0x084 * CPU_RP2A07_CC, 0x076 * CPU_RP2A07_CC, 0x062 * CPU_RP2A07_CC, 0x04E * CPU_RP2A07_CC, 0x042 * CPU_RP2A07_CC, 0x032 * CPU_RP2A07_CC }, { 0x1AC * CPU_DENDY_CC, 0x17C * CPU_DENDY_CC, 0x154 * CPU_DENDY_CC, 0x140 * CPU_DENDY_CC, 0x11E * CPU_DENDY_CC, 0x0FE * CPU_DENDY_CC, 0x0E2 * CPU_DENDY_CC, 0x0D6 * CPU_DENDY_CC, 0x0BE * CPU_DENDY_CC, 0x0A0 * CPU_DENDY_CC, 0x08E * CPU_DENDY_CC, 0x080 * CPU_DENDY_CC, 0x06A * CPU_DENDY_CC, 0x054 * CPU_DENDY_CC, 0x048 * CPU_DENDY_CC, 0x036 * CPU_DENDY_CC } }; #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Apu::Apu(Cpu& c) : cpu (c), extChannel (NULL), buffer (16) { NST_COMPILE_ASSERT( CPU_RP2A03 == 0 && CPU_RP2A07 == 1 && CPU_DENDY == 2 ); PowerOff(); } void Apu::PowerOff() { Reset( false, true ); } void Apu::Reset(bool hard) { Reset( true, hard ); } void Apu::Reset(const bool on,const bool hard) { if (on) UpdateSettings(); updater = &Apu::SyncOff; cycles.Reset( extChannel, cpu.GetModel() ); synchronizer.Resync( settings.speed, cpu ); for (uint i=0; i < 2; ++i) square[i].Reset(); triangle.Reset(); noise.Reset( cpu.GetModel() ); dmc.Reset( cpu.GetModel() ); dcBlocker.Reset(); stream = NULL; buffer.Reset( settings.bits ); if (on) { cpu.Map( 0x4000 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4000 ); cpu.Map( 0x4001 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4001 ); cpu.Map( 0x4002 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4002 ); cpu.Map( 0x4003 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4003 ); cpu.Map( 0x4004 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4000 ); cpu.Map( 0x4005 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4001 ); cpu.Map( 0x4006 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4002 ); cpu.Map( 0x4007 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4003 ); cpu.Map( 0x4008 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4008 ); cpu.Map( 0x400A ).Set( this, &Apu::Peek_40xx, &Apu::Poke_400A ); cpu.Map( 0x400B ).Set( this, &Apu::Peek_40xx, &Apu::Poke_400B ); cpu.Map( 0x400C ).Set( this, &Apu::Peek_40xx, &Apu::Poke_400C ); cpu.Map( 0x400E ).Set( this, &Apu::Peek_40xx, &Apu::Poke_400E ); cpu.Map( 0x400F ).Set( this, &Apu::Peek_40xx, &Apu::Poke_400F ); cpu.Map( 0x4010 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4010 ); cpu.Map( 0x4011 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4011 ); cpu.Map( 0x4012 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4012 ); cpu.Map( 0x4013 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4013 ); cpu.Map( 0x4015 ).Set( this, &Apu::Peek_4015, &Apu::Poke_4015 ); if (cpu.GetApu().IsGenie()) { NES_DO_POKE(4000,0x4000,0x30); NES_DO_POKE(4001,0x4001,0xF9); NES_DO_POKE(400C,0x400C,0x30); NES_DO_POKE(400E,0x400E,0x0E); NES_DO_POKE(400F,0x400F,0x04); NES_DO_POKE(4015,0x4015,0x09); } if (hard) { ctrl = STATUS_FRAME_IRQ_ENABLE; } if (ctrl == STATUS_FRAME_IRQ_ENABLE) cycles.frameIrqClock = (cycles.frameCounter / cycles.fixed) - cpu.GetClock(); if (extChannel) extChannel->Reset(); } else { ctrl = STATUS_FRAME_IRQ_ENABLE; } } Result Apu::SetSampleRate(const dword rate) { if (settings.rate == rate) return RESULT_NOP; if (!rate) return RESULT_ERR_INVALID_PARAM; if (rate < 11025 || rate > 96000) return RESULT_ERR_UNSUPPORTED; settings.rate = rate; UpdateSettings(); return RESULT_OK; } Result Apu::SetSampleBits(const uint bits) { if (settings.bits == bits) return RESULT_NOP; if (!bits) return RESULT_ERR_INVALID_PARAM; if (bits != 8 && bits != 16) return RESULT_ERR_UNSUPPORTED; settings.bits = bits; UpdateSettings(); return RESULT_OK; } Result Apu::SetVolume(const uint channels,const uint volume) { if (volume > 100) return RESULT_ERR_INVALID_PARAM; bool updated = false; for (uint i=0; i < MAX_CHANNELS; ++i) { if (channels & (1U << i)) { if (settings.volumes[i] != volume) { settings.volumes[i] = volume; updated = true; } } } if (!updated) return RESULT_NOP; UpdateSettings(); return RESULT_OK; } uint Apu::GetVolume(const uint channel) const { for (uint i=0; i < MAX_CHANNELS; ++i) { if (channel & (1U << i)) return settings.volumes[i]; } return 0; } uint Apu::GetCtrl() { return ctrl; } Result Apu::SetSpeed(const uint speed) { if (settings.speed == speed) return RESULT_NOP; if ((speed > 0 && speed < 30) || speed > 240) return RESULT_ERR_UNSUPPORTED; settings.speed = speed; UpdateSettings(); return RESULT_OK; } void Apu::Mute(const bool mute) { if (settings.muted != mute) { settings.muted = mute; UpdateSettings(); } } void Apu::SetAutoTranspose(const bool transpose) { if (settings.transpose != transpose) { settings.transpose = transpose; UpdateSettings(); } } void Apu::SetGenie(const bool genie) { if (settings.genie != genie) { settings.genie = genie; UpdateSettings(); } } void Apu::EnableStereo(const bool enable) { if (settings.stereo != enable) { settings.stereo = enable; UpdateSettings(); } } void Apu::UpdateSettings() { cycles.Update( settings.rate, settings.speed, cpu ); synchronizer.Reset( settings.speed, settings.rate, cpu ); dcBlocker.Reset(); buffer.Reset( settings.bits ); Cycle rate; uint fixed; CalculateOscillatorClock( rate, fixed ); square[0].UpdateSettings ( settings.muted ? 0 : settings.volumes[ Channel::APU_SQUARE1 ], rate, fixed ); square[1].UpdateSettings ( settings.muted ? 0 : settings.volumes[ Channel::APU_SQUARE2 ], rate, fixed ); triangle.UpdateSettings ( settings.muted ? 0 : settings.volumes[ Channel::APU_TRIANGLE ], rate, fixed ); noise.UpdateSettings ( settings.muted ? 0 : settings.volumes[ Channel::APU_NOISE ], rate, fixed ); dmc.UpdateSettings ( settings.muted ? 0 : settings.volumes[ Channel::APU_DPCM ] ); UpdateVolumes(); } void Apu::UpdateVolumes() { settings.audible = (extChannel && extChannel->UpdateSettings()) || ( uint(settings.volumes[ Channel::APU_SQUARE1 ]) | uint(settings.volumes[ Channel::APU_SQUARE2 ]) | uint(settings.volumes[ Channel::APU_TRIANGLE ]) | uint(settings.volumes[ Channel::APU_NOISE ]) | uint(settings.volumes[ Channel::APU_DPCM ]) ); } void Apu::Resync(const dword rate) { cycles.Update( rate, settings.speed, cpu ); ClearBuffers( false ); } void Apu::CalculateOscillatorClock(Cycle& rate,uint& fixed) const { dword sampleRate = settings.rate; if (settings.transpose && settings.speed) sampleRate = sampleRate * cpu.GetFps() / settings.speed; uint multiplier = 0; const qaword clockBase = cpu.GetClockBase(); while (++multiplier < 0x1000 && clockBase * (multiplier+1) / sampleRate <= 0x7FFFF && clockBase * multiplier % sampleRate); rate = clockBase * multiplier / sampleRate; fixed = cpu.GetClockDivider() * cpu.GetClock() * multiplier; } void Apu::SaveState(State::Saver& state,const dword baseChunk) const { state.Begin( baseChunk ); { Cycle clock = cycles.frameCounter / cycles.fixed; NST_VERIFY( clock >= cpu.GetCycles() ); if (clock > cpu.GetCycles()) clock = (clock - cpu.GetCycles()) / cpu.GetClock(); else clock = 0; NST_VERIFY( cycles.frameCounter == (cpu.GetCycles() + clock * cpu.GetClock()) * cycles.fixed ); const byte data[4] = { ctrl, clock & 0xFF, clock >> 8, cycles.frameDivider }; state.Begin( AsciiId<'F','R','M'>::V ).Write( data ).End(); } if (cycles.frameIrqClock != Cpu::CYCLE_MAX) { Cycle clock = cycles.frameIrqClock; NST_VERIFY( clock >= cpu.GetCycles() ); if (clock > cpu.GetCycles()) clock = (clock - cpu.GetCycles()) / cpu.GetClock(); else clock = 0; NST_VERIFY( cycles.frameIrqClock == cpu.GetCycles() + clock * cpu.GetClock() ); const byte data[3] = { clock & 0xFF, clock >> 8, cycles.frameIrqRepeat % 3 }; state.Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End(); } if (cycles.extCounter != Cpu::CYCLE_MAX) { Cycle clock = cycles.extCounter / cycles.fixed; NST_VERIFY( clock >= cpu.GetCycles() || clock == 0 ); if (clock > cpu.GetCycles()) { clock = (clock - cpu.GetCycles()) / cpu.GetClock(); NST_VERIFY( cycles.extCounter == (cpu.GetCycles() + clock * cpu.GetClock()) * cycles.fixed ); } else { clock = 0; } state.Begin( AsciiId<'E','X','T'>::V ).Write16( clock ).End(); } square[0].SaveState( state, AsciiId<'S','Q','0'>::V ); square[1].SaveState( state, AsciiId<'S','Q','1'>::V ); triangle.SaveState( state, AsciiId<'T','R','I'>::V ); noise.SaveState( state, AsciiId<'N','O','I'>::V ); dmc.SaveState( state, AsciiId<'D','M','C'>::V, cpu, cycles.dmcClock ); dcBlocker.SaveState( state, AsciiId<'D','C','B'>::V ); { const byte data[4] = { cycles.rateCounter & 0xFFU, cycles.rateCounter >> 8, cycles.rateCounter >> 16, cycles.rateCounter >> 24, }; state.Begin( AsciiId<'S','0','0'>::V ).Write( data ).End(); } state.End(); } void Apu::LoadState(State::Loader& state) { cycles.frameIrqClock = Cpu::CYCLE_MAX; cycles.frameIrqRepeat = 0; while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'F','R','M'>::V: { State::Loader::Data<4> data( state ); ctrl = data[0] & STATUS_BITS; cycles.rateCounter = cycles.fixed * cpu.GetCycles(); cycles.frameCounter = cycles.fixed * ( cpu.GetCycles() + (data[1] | data[2] << 8) * cpu.GetClock() ); cycles.frameDivider = data[3] & 0x3; break; } case AsciiId<'I','R','Q'>::V: { State::Loader::Data<3> data( state ); cycles.frameIrqClock = cpu.GetCycles() + ( (data[0] | data[1] << 8) * cpu.GetClock() ); cycles.frameIrqRepeat = (data[2] & 0x3) % 3; break; } case AsciiId<'E','X','T'>::V: NST_VERIFY( cycles.extCounter != Cpu::CYCLE_MAX ); if (cycles.extCounter != Cpu::CYCLE_MAX) { cycles.extCounter = cycles.fixed * ( cpu.GetCycles() + state.Read16() * cpu.GetClock() ); } break; case AsciiId<'S','Q','0'>::V: square[0].LoadState( state ); break; case AsciiId<'S','Q','1'>::V: square[1].LoadState( state ); break; case AsciiId<'T','R','I'>::V: triangle.LoadState( state ); break; case AsciiId<'N','O','I'>::V: noise.LoadState( state, cpu.GetModel() ); break; case AsciiId<'D','M','C'>::V: dmc.LoadState( state, cpu, cpu.GetModel(), cycles.dmcClock ); break; case AsciiId<'D','C','B'>::V: dcBlocker.LoadState( state ); break; case AsciiId<'S','0','0'>::V: { State::Loader::Data<4> data( state ); cycles.rateCounter = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); break; } } state.End(); } if (ctrl != STATUS_FRAME_IRQ_ENABLE) { cycles.frameIrqClock = Cpu::CYCLE_MAX; cycles.frameIrqRepeat = 0; } else if (cycles.frameIrqClock == Cpu::CYCLE_MAX) { cycles.frameIrqClock = (cycles.frameCounter / cycles.fixed) + (3 - cycles.frameDivider) * (Cycles::frameClocks[cpu.GetModel()][0] / 4); cycles.frameIrqRepeat = 0; } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void NST_FASTCALL Apu::SyncOn(const Cycle target) { NST_ASSERT( (stream && settings.audible) && (cycles.rate && cycles.fixed) && (cycles.extCounter == Cpu::CYCLE_MAX) ); if (cycles.rateCounter < target) { Cycle rateCounter = cycles.rateCounter; const Cycle rate = cycles.rate; do { buffer << GetSample(); if (cycles.frameCounter <= rateCounter) ClockFrameCounter(); rateCounter += rate; } while (rateCounter < target); cycles.rateCounter = rateCounter; } if (cycles.frameCounter < target) { ClockFrameCounter(); NST_ASSERT( cycles.frameCounter >= target ); } } void NST_FASTCALL Apu::SyncOnExt(const Cycle target) { NST_ASSERT( (stream && settings.audible) && (cycles.rate && cycles.fixed) && extChannel ); Cycle extCounter = cycles.extCounter; if (cycles.rateCounter < target) { Cycle rateCounter = cycles.rateCounter; do { buffer << GetSample(); if (extCounter <= rateCounter) extCounter = extChannel->Clock( extCounter, cycles.fixed, rateCounter ); if (cycles.frameCounter <= rateCounter) ClockFrameCounter(); rateCounter += cycles.rate; } while (rateCounter < target); cycles.rateCounter = rateCounter; } if (extCounter <= target) { cycles.extCounter = extChannel->Clock( extCounter, cycles.fixed, target ); NST_ASSERT( cycles.extCounter > target ); } else { cycles.extCounter = extCounter; } if (cycles.frameCounter < target) { ClockFrameCounter(); NST_ASSERT( cycles.frameCounter >= target ); } } void NST_FASTCALL Apu::SyncOff(const Cycle target) { NST_ASSERT( !(stream && settings.audible) && cycles.fixed ); cycles.rateCounter = target; while (cycles.frameCounter < target) ClockFrameCounter(); NST_ASSERT( cycles.extCounter == Cpu::CYCLE_MAX || extChannel ); if (cycles.extCounter <= target) { cycles.extCounter = extChannel->Clock( cycles.extCounter, cycles.fixed, target ); NST_ASSERT( cycles.extCounter > target ); } } void Apu::BeginFrame(Sound::Output* output) { stream = output; updater = (output && settings.audible ? (cycles.extCounter == Cpu::CYCLE_MAX ? &Apu::SyncOn : &Apu::SyncOnExt) : &Apu::SyncOff); } inline void Apu::Update(const Cycle target) { NST_ASSERT( cycles.fixed ); (*this.*updater)( target * cycles.fixed ); } void Apu::Update() { Update( cpu.Update() ); } void Apu::UpdateLatency() { Update( cpu.Update() + 1 ); } bool Apu::UpdateDelta() { const Cycle elapsed = cpu.Update(); const bool delta = cycles.frameCounter != elapsed * cycles.fixed; Update( elapsed + 1 ); return delta; } template void Apu::FlushSound() { NST_ASSERT( (stream && settings.audible) && (cycles.rate && cycles.fixed) ); for (uint i=0; i < 2; ++i) { if (stream->length[i] && stream->samples[i]) { Sound::Buffer::Block block( stream->length[i] ); buffer >> block; Sound::Buffer::Renderer output( stream->samples[i], stream->length[i], buffer.history ); if (output << block) { const Cycle target = cpu.GetCycles() * cycles.fixed; if (cycles.rateCounter < target) { Cycle rateCounter = cycles.rateCounter; do { output << GetSample(); if (cycles.frameCounter <= rateCounter) ClockFrameCounter(); if (cycles.extCounter <= rateCounter) cycles.extCounter = extChannel->Clock( cycles.extCounter, cycles.fixed, rateCounter ); rateCounter += cycles.rate; } while (rateCounter < target && output); cycles.rateCounter = rateCounter; } if (output) { if (cycles.frameCounter < target) ClockFrameCounter(); if (cycles.extCounter <= target) cycles.extCounter = extChannel->Clock( cycles.extCounter, cycles.fixed, target ); do { output << GetSample(); } while (output); } } } } } void Apu::EndFrame() { NST_ASSERT( (stream && settings.audible) == (updater != &Apu::SyncOff) ); if (updater != &Apu::SyncOff) { dword streamed = 0; if (Sound::Output::lockCallback( *stream )) { streamed = stream->length[0] + stream->length[1]; if (settings.bits == 16) { if (!settings.stereo) FlushSound(); else FlushSound(); } else { if (!settings.stereo) FlushSound(); else FlushSound(); } Sound::Output::unlockCallback( *stream ); } if (const dword rate = synchronizer.Clock( streamed, settings.rate, cpu )) Resync( rate ); } Update( cpu.GetCycles() ); Cycle frame = cpu.GetFrameCycles(); NST_ASSERT ( cycles.dmcClock >= frame && cycles.frameIrqClock >= frame ); cycles.dmcClock -= frame; if (cycles.frameIrqClock != Cpu::CYCLE_MAX) cycles.frameIrqClock -= frame; frame *= cycles.fixed; NST_ASSERT ( cycles.rateCounter >= frame && cycles.frameCounter >= frame && cycles.extCounter >= frame ); cycles.rateCounter -= frame; cycles.frameCounter -= frame; if (cycles.extCounter != Cpu::CYCLE_MAX) cycles.extCounter -= frame; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Apu::Settings::Settings() : rate(44100), bits(16), speed(0), muted(false), transpose(false), stereo(false), audible(true) { for (uint i=0; i < MAX_CHANNELS; ++i) volumes[i] = Channel::DEFAULT_VOLUME; } Apu::Cycles::Cycles() : fixed(1), rate(1) {} void Apu::Cycles::Reset(const bool extChannel,const CpuModel model) { rateCounter = 0; frameDivider = 0; frameIrqClock = Cpu::CYCLE_MAX; frameIrqRepeat = 0; dmcClock = Dmc::GetResetFrequency( model ); frameCounter = frameClocks[model][0] * fixed; extCounter = (extChannel ? 0UL : Cpu::CYCLE_MAX); } void Apu::Cycles::Update(dword sampleRate,const uint speed,const Cpu& cpu) { frameCounter /= fixed; rateCounter /= fixed; if (extCounter != Cpu::CYCLE_MAX) extCounter /= fixed; if (speed) sampleRate = sampleRate * cpu.GetFps() / speed; uint multiplier = 0; const qaword clockBase = cpu.GetClockBase(); while (++multiplier < 512 && clockBase * multiplier % sampleRate); rate = clockBase * multiplier / sampleRate; fixed = cpu.GetClockDivider() * multiplier; frameCounter *= fixed; rateCounter *= fixed; if (extCounter != Cpu::CYCLE_MAX) extCounter *= fixed; } Apu::Synchronizer::Synchronizer() : rate(0) {} void Apu::Synchronizer::Resync(uint speed,const Cpu& cpu) { duty = 0; streamed = 0; if (speed == 0 || speed == cpu.GetFps()) sync = 4; else sync = 0; } void Apu::Synchronizer::Reset(uint speed,dword sampleRate,const Cpu& cpu) { rate = sampleRate; Resync( speed, cpu ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NST_SINGLE_CALL dword Apu::Synchronizer::Clock(const dword output,const dword sampleRate,const Cpu& cpu) { /*if (sync) { if (duty >= 60*4) streamed += output; if (duty < 60*12) { duty++; } else { duty = 60*4; dword actualRate = streamed / (60*8) * cpu.GetFps(); const dword limit = sampleRate / 21; if (actualRate <= sampleRate-limit) { actualRate = sampleRate-limit; sync--; } else if (actualRate >= sampleRate+limit) { actualRate = sampleRate+limit; sync--; } else { sync = (sync > 2 ? sync - 2 : 0); } actualRate = actualRate * 9999 / 10000; streamed = 0; if (rate != actualRate) { rate = actualRate; return actualRate; } } }*/ return 0; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Apu::Channel::LengthCounter::LengthCounter() { Reset(); } void Apu::Channel::LengthCounter::Reset() { enabled = 0; count = 0; } void Apu::Channel::LengthCounter::LoadState(State::Loader& state) { const uint data = state.Read8(); enabled = (data == 0xFF ? 0U : ~0U); count = data & enabled; } void Apu::Channel::LengthCounter::SaveState(State::Saver& state,const dword chunk) const { NST_VERIFY( count < 0xFF ); state.Begin( chunk ).Write8( enabled ? count : 0xFF ).End(); } Apu::Channel::Envelope::Envelope() : outputVolume(OUTPUT_MUL) { Reset(); } void Apu::Channel::Envelope::Reset() { output = 0; regs[0] = 0x0; regs[1] = 0x10; count = 0; reset = false; } void Apu::Channel::Envelope::SetOutputVolume(uint v) { outputVolume = v; UpdateOutput(); } void Apu::Channel::Envelope::SaveState(State::Saver& state,const dword chunk) const { const byte data[3] = { count, regs[0] | (reset ? 0x80U : 0x00U), regs[1] }; state.Begin( chunk ).Write( data ).End(); } void Apu::Channel::Envelope::LoadState(State::Loader& state) { State::Loader::Data<3> data( state ); count = data[0] & 0x0F; reset = data[1] >> 7; regs[0] = data[1] & 0x0F; regs[1] = data[2]; UpdateOutput(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Apu::Channel::Envelope::UpdateOutput() { output = (regs[regs[1] >> 4 & 1U] & 0xFUL) * outputVolume; } void Apu::Channel::Envelope::Clock() { if (!reset) { if (count) { count--; return; } if (regs[0] | (regs[1] & 0x20U)) regs[0] = (regs[0] - 1U) & 0xF; } else { reset = false; regs[0] = 0xF; } count = regs[1] & 0x0FU; UpdateOutput(); } void Apu::Channel::Envelope::Write(const uint data) { regs[1] = data; UpdateOutput(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Apu::Channel::DcBlocker::DcBlocker() { Reset(); } void Apu::Channel::DcBlocker::Reset() { acc = 0; prev = 0; next = 0; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif Apu::Channel::Sample Apu::Channel::DcBlocker::Apply(Sample sample) { acc -= prev; prev = signed_shl(sample,15); acc += prev - next * POLE; next = signed_shr(acc,15); return next; } void Apu::Channel::DcBlocker::SaveState(State::Saver& state,const dword chunk) const { state.Begin( chunk ); { const byte data[12] = { acc & 0xFFU, acc >> 8, acc >> 16, acc >> 24, prev & 0xFFU, prev >> 8, prev >> 16, prev >> 24, next & 0xFFU, next >> 8, next >> 16, next >> 24, }; state.Begin( AsciiId<'S','0','0'>::V ).Write( data ).End(); } state.End(); } void Apu::Channel::DcBlocker::LoadState(State::Loader& state) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'S','0','0'>::V: { State::Loader::Data<12> data( state ); acc = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); prev = data[4] | (data[5] << 8) | (data[6] << 16) | (data[7] << 24); next = data[8] | (data[9] << 8) | (data[10] << 16) | (data[11] << 24); break; } } state.End(); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Apu::Channel::Channel(Apu& a) : apu(a) {} Apu::Channel::~Channel() { if (apu.extChannel == this) { apu.extChannel = NULL; apu.UpdateVolumes(); } } void Apu::Channel::Connect(bool audible) { NST_ASSERT( apu.extChannel == NULL ); if (audible) apu.settings.audible = true; else apu.UpdateVolumes(); apu.extChannel = this; } void Apu::Channel::GetOscillatorClock(Cycle& rate,uint& fixed) const { apu.CalculateOscillatorClock( rate, fixed ); } uint Apu::Channel::GetVolume(uint channel) const { NST_ASSERT( channel < MAX_CHANNELS ); return apu.settings.volumes[channel]; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif Cycle Apu::Channel::GetCpuClockBase() const { return apu.cpu.GetClockBase(); } uint Apu::Channel::GetCpuClockDivider() const { return apu.cpu.GetClockDivider(); } Cycle Apu::Channel::GetCpuClock(uint clock) const { return apu.cpu.GetClock(clock); } dword Apu::Channel::GetSampleRate() const { return apu.settings.rate; } bool Apu::Channel::IsMuted() const { return apu.settings.muted; } void Apu::Channel::Update() const { apu.Update(); } Cycle Apu::Channel::Clock(Cycle,Cycle,Cycle) { return Cpu::CYCLE_MAX; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Apu::Oscillator::Oscillator() : rate(1), fixed(1) {} void Apu::Oscillator::Reset() { active = false; timer = RESET_CYCLES * fixed; frequency = fixed; amp = 0; } inline void Apu::Oscillator::ClearAmp() { amp = 0; } void Apu::Oscillator::UpdateSettings(dword r,uint f) { NST_ASSERT( r && f ); frequency = frequency / fixed * f; timer = timer / fixed * f; fixed = f; rate = r; } void Apu::Square::Reset() { Oscillator::Reset(); frequency = fixed * 2; step = 0; duty = 0; envelope.Reset(); lengthCounter.Reset(); validFrequency = false; sweepRate = 0; sweepCount = 1; sweepReload = false; sweepIncrease = ~0U; sweepShift = 0; waveLength = 0; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif inline bool Apu::Square::CanOutput() const { return lengthCounter.GetCount() && envelope.Volume() && validFrequency; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Apu::Square::UpdateSettings(uint v,dword r,uint f) { Oscillator::UpdateSettings( r, f ); envelope.SetOutputVolume( (v * Channel::OUTPUT_MUL + Channel::DEFAULT_VOLUME/2) / Channel::DEFAULT_VOLUME ); active = CanOutput(); } void Apu::Square::SaveState(State::Saver& state,const dword chunk) const { state.Begin( chunk ); { byte data[4]; data[0] = waveLength & 0xFFU; data[1] = (waveLength >> 8) | (duty ? duty << (2+3) : 2U << 3); // for version compatibility data[2] = (sweepCount - 1U) << 4; if (sweepRate) data[2] |= 0x08U | (sweepRate - 1); if (sweepReload) data[2] |= 0x80U; data[3] = sweepShift; if (!sweepIncrease) data[3] |= 0x08U; state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End(); } lengthCounter.SaveState( state, AsciiId<'L','E','N'>::V ); envelope.SaveState( state, AsciiId<'E','N','V'>::V ); { const byte data[13] = { step, timer & 0xFFU, timer >> 8, timer >> 16, timer >> 24, frequency & 0xFFU, frequency >> 8, frequency >> 16, frequency >> 24, amp & 0xFFU, amp >> 8, amp >> 16, amp >> 24, }; state.Begin( AsciiId<'S','0','0'>::V ).Write( data ).End(); } state.End(); } void Apu::Square::LoadState(State::Loader& state) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: { State::Loader::Data<4> data( state ); waveLength = data[0] | (data[1] << 8 & 0x0700); // for version compatibility switch (data[1] >> 3 & 0xF) { case 4: duty = 1; break; case 8: duty = 2; break; case 12: duty = 3; break; default: duty = 0; break; } if (data[2] & 0x08) sweepRate = (data[2] & 0x07) + 1; else sweepRate = 0; sweepCount = (data[2] >> 4 & 0x07) + 1; sweepReload = data[2] >> 7; sweepShift = data[3] & 0x07; sweepIncrease = (data[3] & 0x08) ? 0U : ~0U; step = 0; timer = 0; break; } case AsciiId<'L','E','N'>::V: lengthCounter.LoadState( state ); break; case AsciiId<'E','N','V'>::V: envelope.LoadState( state ); UpdateFrequency(); break; case AsciiId<'S','0','0'>::V: { State::Loader::Data<13> data( state ); step = data[0]; timer = data[1] | (data[2] << 8) | (data[3] << 16) | (data[4] << 24); frequency = data[5] | (data[6] << 8) | (data[7] << 16) | (data[8] << 24); amp = data[9] | (data[10] << 8) | (data[11] << 16) | (data[12] << 24); break; } } state.End(); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NST_SINGLE_CALL void Apu::Square::Disable(const bool disable) { active &= lengthCounter.Disable( disable ); } void Apu::Square::UpdateFrequency() { if (waveLength >= MIN_FRQ && waveLength + (sweepIncrease & waveLength >> sweepShift) <= MAX_FRQ) { frequency = (waveLength + 1UL) * 2 * fixed; validFrequency = true; active = lengthCounter.GetCount() && envelope.Volume(); } else { validFrequency = false; active = false; } } NST_SINGLE_CALL void Apu::Square::WriteReg0(const uint data) { envelope.Write( data ); duty = data >> REG0_DUTY_SHIFT; active = CanOutput(); } NST_SINGLE_CALL void Apu::Square::WriteReg1(const uint data) { sweepIncrease = (data & REG1_SWEEP_DECREASE) ? 0U : ~0U; sweepShift = data & REG1_SWEEP_SHIFT; sweepRate = 0; if ((data & (REG1_SWEEP_ENABLED|REG1_SWEEP_SHIFT)) > REG1_SWEEP_ENABLED) { sweepRate = ((data & REG1_SWEEP_RATE) >> REG1_SWEEP_RATE_SHIFT) + 1; sweepReload = true; } UpdateFrequency(); } NST_SINGLE_CALL void Apu::Square::WriteReg2(const uint data) { waveLength = (waveLength & uint(REG3_WAVELENGTH_HIGH)) | (data & REG3_WAVELENGTH_LOW); UpdateFrequency(); } NST_SINGLE_CALL void Apu::Square::WriteReg3(const uint data,const Cycle frameCounterDelta) { step = 0; envelope.ResetClock(); lengthCounter.Write( data, frameCounterDelta ); waveLength = (data << 8 & REG3_WAVELENGTH_HIGH) | (waveLength & uint(REG3_WAVELENGTH_LOW)); UpdateFrequency(); } NST_SINGLE_CALL void Apu::Square::ClockEnvelope() { envelope.Clock(); active = CanOutput(); } NST_SINGLE_CALL void Apu::Square::ClockSweep(const uint complement) { if (!envelope.Looping() && lengthCounter.Clock()) active = false; if (sweepRate && !--sweepCount) { sweepCount = sweepRate; if (waveLength >= MIN_FRQ) { const uint shifted = waveLength >> sweepShift; if (!sweepIncrease) { waveLength += complement - shifted; UpdateFrequency(); } else if (waveLength + shifted <= MAX_FRQ) { waveLength += shifted; UpdateFrequency(); } } } if (sweepReload) { sweepReload = false; sweepCount = sweepRate; } } inline uint Apu::Square::GetLengthCounter() const { return lengthCounter.GetCount(); } dword Apu::Square::GetSample() { NST_VERIFY( bool(active) == CanOutput() && timer >= 0 ); dword sum = timer; timer -= idword(rate); if (active) { static const byte forms[4][8] = { {0x1F,0x00,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F}, {0x1F,0x00,0x00,0x1F,0x1F,0x1F,0x1F,0x1F}, {0x1F,0x00,0x00,0x00,0x00,0x1F,0x1F,0x1F}, {0x00,0x1F,0x1F,0x00,0x00,0x00,0x00,0x00} }; const byte* const NST_RESTRICT form = forms[duty]; if (timer >= 0) { amp = envelope.Volume() >> form[step]; } else { sum >>= form[step]; do { sum += NST_MIN(-timer,frequency) >> form[step = (step + 1) & 0x7]; timer += idword(frequency); } while (timer < 0); NST_VERIFY( !envelope.Volume() || sum <= 0xFFFFFFFF / envelope.Volume() + rate/2 ); amp = (sum * envelope.Volume() + rate/2) / rate; } } else { if (timer < 0) { const uint count = (-timer + frequency - 1) / frequency; step = (step + count) & 0x7; timer += idword(count * frequency); } if (amp < Channel::OUTPUT_DECAY) { return 0; } else { amp -= Channel::OUTPUT_DECAY; } } return amp; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Apu::Triangle::Triangle() : outputVolume(0) {} void Apu::Triangle::Reset() { Oscillator::Reset(); step = 0x7; status = STATUS_COUNTING; waveLength = 0; //linearCtrl = 0; linearCounter = 0; lengthCounter.Reset(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif inline bool Apu::Triangle::CanOutput() const { return lengthCounter.GetCount() && linearCounter && waveLength >= MIN_FRQ && outputVolume; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Apu::Triangle::UpdateSettings(uint v,dword r,uint f) { Oscillator::UpdateSettings( r, f ); outputVolume = (v * Channel::OUTPUT_MUL + Channel::DEFAULT_VOLUME/2) / Channel::DEFAULT_VOLUME; active = CanOutput(); } void Apu::Triangle::SaveState(State::Saver& state,const dword chunk) const { state.Begin( chunk ); { const byte data[4] = { waveLength & 0xFFU, waveLength >> 8, linearCounter | (uint(status) << 7), linearCtrl }; state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End(); } lengthCounter.SaveState( state, AsciiId<'L','E','N'>::V ); { const byte data[9] = { step, timer & 0xFFU, timer >> 8, timer >> 16, timer >> 24, amp & 0xFFU, amp >> 8, amp >> 16, amp >> 24, }; state.Begin( AsciiId<'S','0','0'>::V ).Write( data ).End(); } state.End(); } void Apu::Triangle::LoadState(State::Loader& state) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: { State::Loader::Data<4> data( state ); waveLength = data[0] | (data[1] << 8 & 0x0700); linearCounter = data[2] & 0x7F; status = static_cast(data[2] >> 7); linearCtrl = data[3]; frequency = (waveLength + 1UL) * fixed; timer = 0; step = 0; break; } case AsciiId<'L','E','N'>::V: lengthCounter.LoadState( state ); break; case AsciiId<'S','0','0'>::V: { State::Loader::Data<9> data( state ); step = data[0]; timer = data[1] | (data[2] << 8) | (data[3] << 16) | (data[4] << 24); amp = data[5] | (data[6] << 8) | (data[7] << 16) | (data[8] << 24); break; } } state.End(); } active = CanOutput(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NST_SINGLE_CALL void Apu::Triangle::Disable(const bool disable) { active &= lengthCounter.Disable( disable ); } NST_SINGLE_CALL void Apu::Triangle::WriteReg0(const uint data) { linearCtrl = data; } NST_SINGLE_CALL void Apu::Triangle::WriteReg2(const uint data) { waveLength = (waveLength & uint(REG3_WAVE_LENGTH_HIGH)) | (data & REG2_WAVE_LENGTH_LOW); frequency = (waveLength + 1UL) * fixed; active = CanOutput(); } NST_SINGLE_CALL void Apu::Triangle::WriteReg3(const uint data,const Cycle frameCounterDelta) { waveLength = (data << 8 & REG3_WAVE_LENGTH_HIGH) | (waveLength & uint(REG2_WAVE_LENGTH_LOW)); frequency = (waveLength + 1UL) * fixed; status = STATUS_RELOAD; lengthCounter.Write( data, frameCounterDelta ); active = CanOutput(); } NST_SINGLE_CALL void Apu::Triangle::ClockLinearCounter() { if (status == STATUS_COUNTING) { if (linearCounter && !--linearCounter) active = false; } else { if (!(linearCtrl & uint(REG0_LINEAR_COUNTER_START))) status = STATUS_COUNTING; linearCounter = linearCtrl & uint(REG0_LINEAR_COUNTER_LOAD); active = CanOutput(); } } NST_SINGLE_CALL void Apu::Triangle::ClockLengthCounter() { if (!(linearCtrl & uint(REG0_LINEAR_COUNTER_START)) && lengthCounter.Clock()) active = false; } NST_SINGLE_CALL dword Apu::Triangle::GetSample() { NST_VERIFY( bool(active) == CanOutput() && timer >= 0 ); if (active) { static const byte pyramid[32] = { 0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7, 0x8,0x9,0xA,0xB,0xC,0xD,0xE,0xF, 0xF,0xE,0xD,0xC,0xB,0xA,0x9,0x8, 0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0 }; dword sum = timer; timer -= idword(rate); if (timer >= 0) { amp = pyramid[step] * outputVolume * 3; } else { sum *= pyramid[step]; do { sum += NST_MIN(-timer,frequency) * pyramid[step = (step + 1) & 0x1F]; timer += idword(frequency); } while (timer < 0); NST_VERIFY( !outputVolume || sum <= 0xFFFFFFFF / outputVolume + rate/2 ); amp = (sum * outputVolume + rate/2) / rate * 3; } } /*else if (amp < Channel::OUTPUT_DECAY) { return 0; } else { amp -= Channel::OUTPUT_DECAY; step &= STEP_CHECK; }*/ return amp; } inline uint Apu::Triangle::GetLengthCounter() const { return lengthCounter.GetCount(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Apu::Noise::Reset(const CpuModel model) { Oscillator::Reset(); frequency = lut[model][0] * dword(fixed); bits = 1; shifter = 13; envelope.Reset(); lengthCounter.Reset(); } uint Apu::Noise::GetFrequencyIndex() const { for (uint v=frequency/fixed, i=0; i < 16; ++i) { if (v == lut[0][i] || v == lut[1][i]) return i; } return 0; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif inline bool Apu::Noise::CanOutput() const { return lengthCounter.GetCount() && envelope.Volume(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Apu::Noise::UpdateSettings(uint v,dword r,uint f) { Oscillator::UpdateSettings( r, f ); envelope.SetOutputVolume( (v * Channel::OUTPUT_MUL + Channel::DEFAULT_VOLUME/2) / Channel::DEFAULT_VOLUME ); active = CanOutput(); } void Apu::Noise::SaveState(State::Saver& state,const dword chunk) const { state.Begin( chunk ); state.Begin( AsciiId<'R','E','G'>::V ).Write8( (shifter == 8 ? 0x10 : 0x00) | GetFrequencyIndex() ).End(); lengthCounter.SaveState( state, AsciiId<'L','E','N'>::V ); envelope.SaveState( state, AsciiId<'E','N','V'>::V ); { const byte data[6] = { bits & 0xFFU, bits >> 8, timer & 0xFFU, timer >> 8, timer >> 16, timer >> 24 }; state.Begin( AsciiId<'S','0','0'>::V ).Write( data ).End(); } state.End(); } void Apu::Noise::LoadState(State::Loader& state,const CpuModel model) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: { const uint data = state.Read8(); frequency = lut[model][data & 0x0F] * dword(fixed); shifter = (data & 0x10) ? 8 : 13; timer = 0; bits = 1; break; } case AsciiId<'L','E','N'>::V: lengthCounter.LoadState( state ); break; case AsciiId<'E','N','V'>::V: envelope.LoadState( state ); break; case AsciiId<'S','0','0'>::V: { State::Loader::Data<6> data( state ); bits = data[0] | (data[1] << 8); timer = data[2] | (data[3] << 8) | (data[4] << 16) | (data[5] << 24); break; } } state.End(); } active = CanOutput(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NST_SINGLE_CALL void Apu::Noise::Disable(const bool disable) { active &= lengthCounter.Disable( disable ); } NST_SINGLE_CALL void Apu::Noise::WriteReg0(const uint data) { envelope.Write( data ); active = CanOutput(); } NST_SINGLE_CALL void Apu::Noise::WriteReg2(const uint data,const CpuModel model) { frequency = lut[model][data & REG2_FREQUENCY] * dword(fixed); shifter = (data & REG2_93BIT_MODE) ? 8 : 13; } NST_SINGLE_CALL void Apu::Noise::WriteReg3(const uint data,const Cycle frameCounterDelta) { envelope.ResetClock(); lengthCounter.Write( data, frameCounterDelta ); active = CanOutput(); } NST_SINGLE_CALL void Apu::Noise::ClockEnvelope() { envelope.Clock(); active = CanOutput(); } NST_SINGLE_CALL void Apu::Noise::ClockLengthCounter() { if (!envelope.Looping() && lengthCounter.Clock()) active = false; } NST_SINGLE_CALL dword Apu::Noise::GetSample() { NST_VERIFY( bool(active) == CanOutput() && timer >= 0 ); dword sum = timer; timer -= idword(rate); if (active) { if (timer >= 0) { if (!(bits & 0x4000)) return envelope.Volume() * 2; } else { if (bits & 0x4000) sum = 0; do { bits = (bits << 1) | ((bits >> 14 ^ bits >> shifter) & 0x1); if (!(bits & 0x4000)) sum += NST_MIN(-timer,frequency); timer += idword(frequency); } while (timer < 0); NST_VERIFY( !envelope.Volume() || sum <= 0xFFFFFFFF / envelope.Volume() + rate/2 ); return (sum * envelope.Volume() + rate/2) / rate * 2; } } else while (timer < 0) { bits = (bits << 1) | ((bits >> 14 ^ bits >> shifter) & 0x1); timer += idword(frequency); } return 0; } inline uint Apu::Noise::GetLengthCounter() const { return lengthCounter.GetCount(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Apu::Dmc::Dmc() : outputVolume(0) { frequency = GetResetFrequency( CPU_RP2A03 ); } void Apu::Dmc::Reset(const CpuModel model) { curSample = 0; linSample = 0; frequency = GetResetFrequency( model ); regs.ctrl = 0; regs.lengthCounter = 1; regs.address = 0xC000; out.active = false; out.shifter = 0; out.dac = 0; out.buffer = 0x00; dma.lengthCounter = 0; dma.buffered = false; dma.address = 0xC000; dma.buffer = 0x00; } Cycle Apu::Dmc::GetResetFrequency(CpuModel model) { return lut[model][0]; } void Apu::Dmc::UpdateSettings(uint v) { v = (v * Channel::OUTPUT_MUL + Channel::DEFAULT_VOLUME/2) / Channel::DEFAULT_VOLUME; if (outputVolume) linSample /= outputVolume; if (outputVolume) curSample /= outputVolume; linSample *= v; curSample *= v; outputVolume = v; if (!v) out.active = false; } inline void Apu::Dmc::ClearAmp() { curSample = 0; linSample = 0; } void Apu::Dmc::SaveState(State::Saver& state,const dword chunk,const Cpu& cpu,const Cycle dmcMcClock) const { NST_VERIFY( dmcMcClock >= cpu.GetCycles() ); dword dmcClock = dmcMcClock; if (dmcClock > cpu.GetCycles()) dmcClock = (dmcClock - cpu.GetCycles()) / cpu.GetClock(); else dmcClock = 0; NST_VERIFY( dmcClock <= 0x1FFF && dmcMcClock == cpu.GetCycles() + dmcClock * cpu.GetClock() ); state.Begin( chunk ); { const byte data[12] = { dmcClock & 0xFF, dmcClock >> 8, ( ( ( regs.ctrl & REG0_FREQUENCY ) ) | ( ( regs.ctrl & REG0_LOOP ) ? 0x10U : 0U ) | ( ( regs.ctrl & REG0_IRQ_ENABLE ) ? 0x20U : 0U ) | ( ( dma.lengthCounter ) ? 0x40U : 0U ) ), (regs.address - 0xC000U) >> 6, (regs.lengthCounter - 1U) >> 4, (dma.address >> 0 & 0xFFU), (dma.address >> 8 & 0x7FU) | (dma.buffered ? 0x80 : 0x00), dma.lengthCounter ? (dma.lengthCounter - 1U) >> 4 : 0, dma.buffer, 7 - out.shifter, out.buffer, out.dac, }; state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End(); } { const byte data[4] = { linSample & 0xFFU, linSample >> 8, dma.lengthCounter & 0xFFU, dma.lengthCounter >> 8, }; state.Begin( AsciiId<'S','0','0'>::V ).Write( data ).End(); } state.End(); } void Apu::Dmc::LoadState(State::Loader& state,const Cpu& cpu,const CpuModel model,Cycle& dmcClock) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: { State::Loader::Data<12> data( state ); dmcClock = cpu.GetCycles() + ((data[0] | data[1] << 8) * cpu.GetClock()); regs.ctrl = ( ( ( data[2] & 0x10 ) ? REG0_LOOP : 0U ) | ( ( data[2] & 0x20 ) ? REG0_IRQ_ENABLE : 0U ) | ( ( data[2] & REG0_FREQUENCY ) ) ); frequency = lut[model][regs.ctrl & REG0_FREQUENCY]; regs.address = 0xC000 | (data[3] << 6); regs.lengthCounter = (data[4] << 4) + 1; dma.address = 0x8000 | data[5] | (data[6] << 8 & 0x7F00); dma.buffered = data[6] >> 7; dma.lengthCounter = (data[2] & 0x40) ? (data[7] << 4) + 1 : 0; dma.buffer = data[8]; out.shifter = 7 - (data[9] & 0x7); out.buffer = data[10]; out.dac = data[11] & 0x7F; curSample = out.dac * outputVolume; linSample = curSample; out.active = dma.buffered && outputVolume; break; } case AsciiId<'S','0','0'>::V: { State::Loader::Data<4> data( state ); linSample = data[0] | (data[1] << 8); dma.lengthCounter = data[2] | (data[3] << 8); break; } } state.End(); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NST_SINGLE_CALL void Apu::Dmc::Disable(const bool disable,Cpu& cpu) { cpu.ClearIRQ( Cpu::IRQ_DMC ); if (disable) { dma.lengthCounter = 0; } else if (!dma.lengthCounter) { dma.lengthCounter = regs.lengthCounter; dma.address = regs.address; if (!dma.buffered) DoDMA( cpu, cpu.GetCycles() ); } } NST_SINGLE_CALL dword Apu::Dmc::GetSample() { if (curSample != linSample) { const uint step = outputVolume * INP_STEP; if (curSample + step - linSample <= step*2) { linSample = curSample; } else if (curSample > linSample) { linSample += step; } else { linSample -= step; } } return linSample; } void Apu::Dmc::DoDMA(Cpu& cpu,const Cycle clock,const uint readAddress) { NST_VERIFY( !dma.buffered && (!readAddress || !cpu.IsWriteCycle(clock)) ); if (!readAddress) { cpu.StealCycles( cpu.GetClock(cpu.IsWriteCycle(clock) ? 2 : 3) ); } else if (cpu.GetCycles() != clock) { cpu.StealCycles( cpu.GetClock(3) ); } else { NST_DEBUG_MSG("DMA/Read conflict!"); cpu.StealCycles( cpu.GetClock(1) ); /* According to dmc_dma_during_read4/dma_2007_read, DMC DMA during read causes * 2-3 extra $2007 reads before the real read. The nesdev wiki states that this * also happens when polling $2002 for vblank. */ if ((readAddress & 0xF000) != 0x4000) { cpu.Peek( readAddress ); cpu.Peek( readAddress ); } cpu.StealCycles( cpu.GetClock(1) ); cpu.Peek( readAddress ); cpu.StealCycles( cpu.GetClock(1) ); } dma.buffer = cpu.Peek( dma.address ); cpu.StealCycles( cpu.GetClock() ); dma.address = 0x8000 | ((dma.address + 1U) & 0x7FFF); dma.buffered = true; NST_VERIFY( dma.lengthCounter ); if (!--dma.lengthCounter) { if (regs.ctrl & REG0_LOOP) { dma.address = regs.address; dma.lengthCounter = regs.lengthCounter; } else if (regs.ctrl & REG0_IRQ_ENABLE) { cpu.DoIRQ( Cpu::IRQ_DMC ); } } } NST_SINGLE_CALL bool Apu::Dmc::WriteReg0(const uint data,const CpuModel model) { regs.ctrl = data; frequency = lut[model][data & REG0_FREQUENCY]; return data & REG0_IRQ_ENABLE; } NST_SINGLE_CALL void Apu::Dmc::WriteReg1(const uint data) { out.dac = data & 0x7F; curSample = out.dac * outputVolume; } NST_SINGLE_CALL void Apu::Dmc::WriteReg2(const uint data) { regs.address = 0xC000 | (data << 6); } NST_SINGLE_CALL void Apu::Dmc::WriteReg3(const uint data) { regs.lengthCounter = (data << 4) + 1; } NST_SINGLE_CALL bool Apu::Dmc::ClockDAC() { if (out.active) { const uint next = out.dac + ((out.buffer & 0x1U) << 2) - 2; out.buffer >>= 1; if (next <= 0x7F && next != out.dac) { out.dac = next; return true; } } return false; } NST_SINGLE_CALL void Apu::Dmc::Update() { curSample = out.dac * outputVolume; } NST_SINGLE_CALL void Apu::Dmc::ClockDMA(Cpu& cpu,Cycle& clock,const uint readAddress) { const Cycle tmp = clock; clock += frequency; if (out.shifter) { out.shifter--; } else { out.shifter = 7; out.active = dma.buffered; if (out.active) { out.active = outputVolume; dma.buffered = false; out.buffer = dma.buffer; if (dma.lengthCounter) DoDMA( cpu, tmp, readAddress ); } } } inline uint Apu::Dmc::GetLengthCounter() const { return dma.lengthCounter; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Apu::ClearBuffers() { ClearBuffers( true ); } NST_NO_INLINE void Apu::ClearBuffers(bool resync) { if (resync) synchronizer.Resync( settings.speed, cpu ); square[0].ClearAmp(); square[1].ClearAmp(); triangle.ClearAmp(); noise.ClearAmp(); dmc.ClearAmp(); dcBlocker.Reset(); buffer.Reset( settings.bits, false ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif Cycle Apu::Clock() { if (cycles.dmcClock <= cpu.GetCycles()) ClockDmc( cpu.GetCycles() ); if (cycles.frameIrqClock <= cpu.GetCycles()) ClockFrameIRQ( cpu.GetCycles() ); return NST_MIN(cycles.dmcClock,cycles.frameIrqClock); } void Apu::ClockDMA(uint readAddress) { if (cycles.dmcClock <= cpu.GetCycles()) ClockDmc( cpu.GetCycles(), readAddress ); } NST_NO_INLINE void Apu::ClockOscillators(const bool twoClocks) { for (uint i=0; i < 2; ++i) square[i].ClockEnvelope(); triangle.ClockLinearCounter(); noise.ClockEnvelope(); if (twoClocks) { for (uint i=0; i < 2; ++i) square[i].ClockSweep( i-1 ); triangle.ClockLengthCounter(); noise.ClockLengthCounter(); } } NST_NO_INLINE void Apu::ClockDmc(const Cycle target,const uint readAddress) { NST_ASSERT( cycles.dmcClock <= target ); do { if (dmc.ClockDAC()) { Update( cycles.dmcClock ); dmc.Update(); } dmc.ClockDMA( cpu, cycles.dmcClock, readAddress ); } while (cycles.dmcClock <= target); } NST_NO_INLINE void Apu::ClockFrameCounter() { NST_COMPILE_ASSERT( STATUS_SEQUENCE_5_STEP == 0x80 ); NST_VERIFY( cycles.frameCounter <= cpu.GetCycles() * cycles.fixed ); ClockOscillators( cycles.frameDivider & 0x1U ); cycles.frameDivider = (cycles.frameDivider + 1) & 0x3U; cycles.frameCounter += Cycles::oscillatorClocks[cpu.GetModel()][ctrl >> 7][cycles.frameDivider] * cycles.fixed; } NST_NO_INLINE void Apu::ClockFrameIRQ(const Cycle target) { NST_VERIFY( ctrl == STATUS_FRAME_IRQ_ENABLE ); cpu.DoIRQ( Cpu::IRQ_FRAME, cycles.frameIrqClock ); Cycle clock = cycles.frameIrqClock; uint repeat = cycles.frameIrqRepeat; do { clock += Cycles::frameClocks[cpu.GetModel()][1 + repeat++ % 3]; } while (clock <= target); cycles.frameIrqClock = clock; cycles.frameIrqRepeat = repeat; } NST_NO_INLINE Apu::Channel::Sample Apu::GetSample() { dword dac[2]; return Clamp ( dcBlocker.Apply ( (0 != (dac[0] = square[0].GetSample() + square[1].GetSample()) ? NLN_SQ_0 / (NLN_SQ_1 / dac[0] + NLN_SQ_2) : 0) + (0 != (dac[1] = triangle.GetSample() + noise.GetSample() + dmc.GetSample()) ? NLN_TND_0 / (NLN_TND_1 / dac[1] + NLN_TND_2) : 0) ) + (extChannel ? extChannel->GetSample() : 0) ); } NES_POKE_AD(Apu,4000) { UpdateLatency(); square[address >> 2 & 0x1].WriteReg0( data ); } NES_POKE_AD(Apu,4001) { Update(); square[address >> 2 & 0x1].WriteReg1( data ); } NES_POKE_AD(Apu,4002) { Update(); square[address >> 2 & 0x1].WriteReg2( data ); } NES_POKE_AD(Apu,4003) { square[address >> 2 & 0x1].WriteReg3( data, UpdateDelta() ); } NES_POKE_D(Apu,4008) { Update(); triangle.WriteReg0( data ); } NES_POKE_D(Apu,400A) { Update(); triangle.WriteReg2( data ); } NES_POKE_D(Apu,400B) { triangle.WriteReg3( data, UpdateDelta() ); } NES_POKE_D(Apu,400C) { UpdateLatency(); noise.WriteReg0( data ); } NES_POKE_D(Apu,400E) { Update(); noise.WriteReg2( data, cpu.GetModel() ); } NES_POKE_D(Apu,400F) { noise.WriteReg3( data, UpdateDelta() ); } NES_POKE_D(Apu,4010) { if (!dmc.WriteReg0( data, cpu.GetModel() )) cpu.ClearIRQ( Cpu::IRQ_DMC ); } NES_POKE_D(Apu,4011) { Update(); dmc.WriteReg1( data ); } NES_POKE_D(Apu,4012) { dmc.WriteReg2( data ); } NES_POKE_D(Apu,4013) { dmc.WriteReg3( data ); } NES_POKE_D(Apu,4015) { Update(); data = ~data; square[0].Disable ( data >> 0 & 0x1 ); square[1].Disable ( data >> 1 & 0x1 ); triangle.Disable ( data >> 2 & 0x1 ); noise.Disable ( data >> 3 & 0x1 ); dmc.Disable ( data & 0x10, cpu ); } NES_PEEK_A(Apu,4015) { NST_COMPILE_ASSERT( Cpu::IRQ_FRAME == 0x40 && Cpu::IRQ_DMC == 0x80 ); const Cycle elapsed = cpu.Update( address ); if (cycles.frameIrqClock <= elapsed) ClockFrameIRQ( elapsed ); if (cycles.frameCounter < elapsed * cycles.fixed) Update( elapsed ); const uint data = cpu.GetIRQ(); cpu.ClearIRQ( Cpu::IRQ_FRAME ); return (data & (Cpu::IRQ_FRAME|Cpu::IRQ_DMC)) | ( ( square[0].GetLengthCounter() ? 0x01U : 0x00U ) | ( square[1].GetLengthCounter() ? 0x02U : 0x00U ) | ( triangle.GetLengthCounter() ? 0x04U : 0x00U ) | ( noise.GetLengthCounter() ? 0x08U : 0x00U ) | ( dmc.GetLengthCounter() ? 0x10U : 0x00U ) ); } void Apu::WriteFrameCtrl(uint data) { Cycle next = cpu.Update(); if (cpu.IsOddCycle()) next += cpu.GetClock(); Update( next ); if (cycles.frameIrqClock <= next) ClockFrameIRQ( next ); next += cpu.GetClock(); data &= STATUS_BITS; cycles.frameCounter = (next + Cycles::oscillatorClocks[cpu.GetModel()][data >> 7][0]) * cycles.fixed; cycles.frameDivider = 0; cycles.frameIrqRepeat = 0; ctrl = data; if (data) { cycles.frameIrqClock = Cpu::CYCLE_MAX; if (data & STATUS_NO_FRAME_IRQ) cpu.ClearIRQ( Cpu::IRQ_FRAME ); if (data & STATUS_SEQUENCE_5_STEP) ClockOscillators( true ); } else { cycles.frameIrqClock = next + Cycles::frameClocks[cpu.GetModel()][0]; } } NES_PEEK(Apu,40xx) { return 0x40; } } } nestopia-1.51.1/source/core/NstApu.hpp000066400000000000000000000334521411157722000176030ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_CPU_H #error Do not include NstApu.h directly! #endif #include "NstSoundRenderer.hpp" namespace Nes { namespace Core { namespace Sound { class Output; } namespace State { class Saver; class Loader; } class Cpu; class Apu { public: explicit Apu(Cpu&); void Reset(bool); void PowerOff(); void ClearBuffers(); void BeginFrame(Sound::Output*); void EndFrame(); void WriteFrameCtrl(uint); Cycle Clock(); void ClockDMA(uint=0); Result SetSampleRate(dword); Result SetSampleBits(uint); Result SetSpeed(uint); Result SetVolume(uint,uint); uint GetVolume(uint) const; uint GetCtrl(); void Mute(bool); void SetAutoTranspose(bool); void SetGenie(bool); void EnableStereo(bool); void SaveState(State::Saver&,dword) const; void LoadState(State::Loader&); class NST_NO_VTABLE Channel { Apu& apu; protected: explicit Channel(Apu&); ~Channel(); void Update() const; void Connect(bool); dword GetSampleRate() const; uint GetVolume(uint) const; void GetOscillatorClock(Cycle&,uint&) const; Cycle GetCpuClockBase() const; uint GetCpuClockDivider() const; Cycle GetCpuClock(uint=1) const; bool IsMuted() const; bool IsGenie() const; public: typedef Sound::Sample Sample; enum { APU_SQUARE1, APU_SQUARE2, APU_TRIANGLE, APU_NOISE, APU_DPCM, EXT_FDS, EXT_MMC5, EXT_VRC6, EXT_VRC7, EXT_N163, EXT_S5B }; enum { OUTPUT_MIN = -32767, OUTPUT_MAX = +32767, OUTPUT_MUL = 256, OUTPUT_DECAY = OUTPUT_MUL / 4 - 1, DEFAULT_VOLUME = 85 }; virtual void Reset() = 0; virtual Sample GetSample() = 0; virtual Cycle Clock(Cycle,Cycle,Cycle); virtual bool UpdateSettings() = 0; class LengthCounter { public: LengthCounter(); void Reset(); void LoadState(State::Loader&); void SaveState(State::Saver&,dword) const; private: uint enabled; uint count; static const byte lut[32]; public: uint Disable(bool disable) { enabled = disable - 1U; count &= enabled; return enabled; } void Write(uint data) { NST_ASSERT( (data >> 3) < sizeof(array(lut)) ); count = lut[data >> 3] & enabled; } void Write(uint data,bool frameCounterDelta) { NST_VERIFY_MSG( frameCounterDelta, "APU $40xx/framecounter conflict" ); if (frameCounterDelta || !count) Write( data ); } uint GetCount() const { return count; } bool Clock() { return count && !--count; } }; class Envelope { public: Envelope(); void Reset(); void SetOutputVolume(uint); void LoadState(State::Loader&); void SaveState(State::Saver&,dword) const; void Clock(); void Write(uint); private: void UpdateOutput(); dword output; uint outputVolume; byte regs[2]; byte count; bool reset; public: bool Looping() const { return regs[1] & 0x20U; } dword Volume() const { return output; } void ResetClock() { reset = true; } }; class DcBlocker { public: DcBlocker(); void Reset(); Sample Apply(Sample); void LoadState(State::Loader&); void SaveState(State::Saver&,dword) const; private: enum { POLE = 3 // ~0.9999 }; idword prev; idword next; idword acc; }; }; private: typedef void (NST_FASTCALL Apu::*Updater)(Cycle); inline void Update(Cycle); void Update(); void UpdateLatency(); bool UpdateDelta(); void Reset(bool,bool); void CalculateOscillatorClock(Cycle&,uint&) const; void Resync(dword); NST_NO_INLINE void ClearBuffers(bool); enum { MAX_CHANNELS = 11, STATUS_NO_FRAME_IRQ = 0x40, STATUS_SEQUENCE_5_STEP = 0x80, STATUS_FRAME_IRQ_ENABLE = 0, STATUS_BITS = STATUS_NO_FRAME_IRQ|STATUS_SEQUENCE_5_STEP, NLN_VOL = 192, NLN_SQ_F = 900, NLN_SQ_0 = 9552UL * Channel::OUTPUT_MUL * NLN_VOL * (NLN_SQ_F/100), NLN_SQ_1 = 8128UL * Channel::OUTPUT_MUL * NLN_SQ_F, NLN_SQ_2 = NLN_SQ_F * 100UL, NLN_TND_F = 500, NLN_TND_0 = 16367UL * Channel::OUTPUT_MUL * NLN_VOL * (NLN_TND_F/100), NLN_TND_1 = 24329UL * Channel::OUTPUT_MUL * NLN_TND_F, NLN_TND_2 = NLN_TND_F * 100UL }; NES_DECL_POKE( 4000 ); NES_DECL_POKE( 4001 ); NES_DECL_POKE( 4002 ); NES_DECL_POKE( 4003 ); NES_DECL_POKE( 4004 ); NES_DECL_POKE( 4005 ); NES_DECL_POKE( 4006 ); NES_DECL_POKE( 4007 ); NES_DECL_POKE( 4008 ); NES_DECL_POKE( 400A ); NES_DECL_POKE( 400B ); NES_DECL_POKE( 400C ); NES_DECL_POKE( 400E ); NES_DECL_POKE( 400F ); NES_DECL_POKE( 4010 ); NES_DECL_POKE( 4011 ); NES_DECL_POKE( 4012 ); NES_DECL_POKE( 4013 ); NES_DECL_POKE( 4015 ); NES_DECL_PEEK( 4015 ); NES_DECL_PEEK( 40xx ); NST_NO_INLINE Channel::Sample GetSample(); void NST_FASTCALL SyncOn (Cycle); void NST_FASTCALL SyncOnExt (Cycle); void NST_FASTCALL SyncOff (Cycle); NST_NO_INLINE void ClockFrameIRQ(Cycle); NST_NO_INLINE void ClockFrameCounter(); NST_NO_INLINE void ClockDmc(Cycle,uint=0); NST_NO_INLINE void ClockOscillators(bool); template void FlushSound(); void UpdateSettings(); void UpdateVolumes(); struct Cycles { Cycles(); void Update(dword,uint,const Cpu&); void Reset(bool,CpuModel); uint fixed; Cycle rate; Cycle rateCounter; Cycle frameCounter; Cycle extCounter; word frameDivider; word frameIrqRepeat; Cycle frameIrqClock; Cycle dmcClock; static const dword frameClocks[3][4]; static const dword oscillatorClocks[3][2][4]; }; class Synchronizer { uint sync; uint duty; dword streamed; dword rate; public: Synchronizer(); void Reset(uint,dword,const Cpu&); void Resync(uint,const Cpu&); NST_SINGLE_CALL dword Clock(dword,dword,const Cpu&); }; class Oscillator { enum { RESET_CYCLES = 2048 }; protected: Oscillator(); void Reset(); void UpdateSettings(dword,uint); ibool active; idword timer; Cycle rate; Cycle frequency; dword amp; uint fixed; public: inline void ClearAmp(); }; class Square : public Oscillator { public: void Reset(); void UpdateSettings(uint,dword,uint); void LoadState(State::Loader&); void SaveState(State::Saver&,dword) const; NST_SINGLE_CALL void WriteReg0(uint); NST_SINGLE_CALL void WriteReg1(uint); NST_SINGLE_CALL void WriteReg2(uint); NST_SINGLE_CALL void WriteReg3(uint,Cycle); NST_SINGLE_CALL void Disable(bool); dword GetSample(); NST_SINGLE_CALL void ClockEnvelope(); NST_SINGLE_CALL void ClockSweep(uint); inline uint GetLengthCounter() const; private: inline bool CanOutput() const; void UpdateFrequency(); enum { MIN_FRQ = 0x008, MAX_FRQ = 0x7FF, REG0_DUTY_SHIFT = 6, REG1_SWEEP_SHIFT = 0x07, REG1_SWEEP_DECREASE = 0x08, REG1_SWEEP_RATE = 0x70, REG1_SWEEP_RATE_SHIFT = 4, REG1_SWEEP_ENABLED = 0x80, REG3_WAVELENGTH_LOW = 0x00FF, REG3_WAVELENGTH_HIGH = 0x0700 }; uint step; uint duty; Channel::Envelope envelope; Channel::LengthCounter lengthCounter; bool validFrequency; bool sweepReload; byte sweepCount; byte sweepRate; uint sweepIncrease; word sweepShift; word waveLength; }; class Triangle : public Oscillator { public: Triangle(); void Reset(); void UpdateSettings(uint,dword,uint); void LoadState(State::Loader&); void SaveState(State::Saver&,dword) const; NST_SINGLE_CALL void WriteReg0(uint); NST_SINGLE_CALL void WriteReg2(uint); NST_SINGLE_CALL void WriteReg3(uint,Cycle); NST_SINGLE_CALL void Disable(bool); NST_SINGLE_CALL dword GetSample(); NST_SINGLE_CALL void ClockLinearCounter(); NST_SINGLE_CALL void ClockLengthCounter(); inline uint GetLengthCounter() const; private: inline bool CanOutput() const; enum { MIN_FRQ = 2 + 1, STEP_CHECK = 0x1F, REG0_LINEAR_COUNTER_LOAD = 0x7F, REG0_LINEAR_COUNTER_START = 0x80, REG2_WAVE_LENGTH_LOW = 0x00FF, REG3_WAVE_LENGTH_HIGH = 0x0700 }; enum Status { STATUS_COUNTING, STATUS_RELOAD }; uint step; uint outputVolume; Status status; word waveLength; byte linearCtrl; byte linearCounter; Channel::LengthCounter lengthCounter; }; class Noise : public Oscillator { public: void Reset(CpuModel); void UpdateSettings(uint,dword,uint); void LoadState(State::Loader&,CpuModel); void SaveState(State::Saver&,dword) const; NST_SINGLE_CALL void WriteReg0(uint); NST_SINGLE_CALL void WriteReg2(uint,CpuModel); NST_SINGLE_CALL void WriteReg3(uint,Cycle); NST_SINGLE_CALL void Disable(bool); NST_SINGLE_CALL dword GetSample(); NST_SINGLE_CALL void ClockEnvelope(); NST_SINGLE_CALL void ClockLengthCounter(); inline uint GetLengthCounter() const; private: inline bool CanOutput() const; uint GetFrequencyIndex() const; enum { REG2_FREQUENCY = 0x0F, REG2_93BIT_MODE = 0x80 }; uint bits; uint shifter; Channel::Envelope envelope; Channel::LengthCounter lengthCounter; static const word lut[3][16]; }; class Dmc { public: Dmc(); void Reset(CpuModel); void UpdateSettings(uint); void LoadState(State::Loader&,const Cpu&,CpuModel,Cycle&); void SaveState(State::Saver&,dword,const Cpu&,Cycle) const; NST_SINGLE_CALL bool WriteReg0(uint,CpuModel); NST_SINGLE_CALL void WriteReg1(uint); NST_SINGLE_CALL void WriteReg2(uint); NST_SINGLE_CALL void WriteReg3(uint); NST_SINGLE_CALL void Disable(bool,Cpu&); NST_SINGLE_CALL dword GetSample(); NST_SINGLE_CALL bool ClockDAC(); NST_SINGLE_CALL void Update(); NST_SINGLE_CALL void ClockDMA(Cpu&,Cycle&,uint=0); inline void ClearAmp(); inline uint GetLengthCounter() const; static Cycle GetResetFrequency(CpuModel); private: void DoDMA(Cpu&,Cycle,uint=0); enum { REG0_FREQUENCY = 0x0F, REG0_LOOP = 0x40, REG0_IRQ_ENABLE = 0x80, INP_STEP = 8 }; uint curSample; uint linSample; uint outputVolume; Cycle frequency; struct { uint ctrl; word lengthCounter; word address; } regs; struct { byte shifter; byte dac; byte buffer; bool active; } out; struct { word lengthCounter; word address; word buffered; word buffer; } dma; static const word lut[3][16]; }; struct Settings { Settings(); dword rate; uint bits; byte speed; bool muted; bool transpose; bool genie; bool stereo; bool audible; byte volumes[MAX_CHANNELS]; }; uint ctrl; Updater updater; Cpu& cpu; Cycles cycles; Synchronizer synchronizer; Square square[2]; Triangle triangle; Noise noise; Dmc dmc; Channel* extChannel; Channel::DcBlocker dcBlocker; Sound::Output* stream; Sound::Buffer buffer; Settings settings; public: dword GetSampleRate() const { return settings.rate; } uint GetSampleBits() const { return settings.bits; } uint GetSpeed() const { return settings.speed; } bool IsAutoTransposing() const { return settings.transpose; } bool IsGenie() const { return settings.genie; } bool InStereo() const { return settings.stereo; } bool IsMuted() const { return settings.muted; } bool IsAudible() const { return settings.audible && !settings.muted; } }; } } nestopia-1.51.1/source/core/NstAssert.cpp000066400000000000000000000063751411157722000203160ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstCore.hpp" #if defined(NST_DEBUG) && defined(NST_WIN32) #include #include #include #include #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #ifdef _UNICODE #define NST_MESSAGEBOX MessageBoxA #else #define NST_MESSAGEBOX MessageBox #endif #if NST_MSVC >= 1200 #ifdef _UNICODE #define NST_DEBUGSTRING(s_) OutputDebugStringA( s_ ); #else #define NST_DEBUGSTRING(s_) OutputDebugString( s_ ); #endif #else #define NST_DEBUGSTRING(s_) #endif namespace Nes { namespace Assertion { NST_NO_INLINE uint NST_CALL Issue ( const char* expression, const char* msg, const char* file, const char* function, int line ) { const std::size_t length = ( (msg ? std::strlen(msg) : 0) + (expression ? std::strlen(expression) : 16) + (file ? std::strlen(file) : 16) + (function ? std::strlen(function) : 16) + 64 + 1 ); if (char* const buffer = new (std::nothrow) char [length]) { std::sprintf ( buffer, msg ? "%s, Expression: %s\n\n File: %s\n Function: %s\n Line: %i\n\n" : "%sExpression: %s\n\n File: %s\n Function: %s\n Line: %i\n\n", msg ? msg : "", expression ? expression : "break point", file, function ? function : "unknown", line ); NST_DEBUGSTRING( buffer ); int result = NST_MESSAGEBOX ( ::GetActiveWindow(), buffer, "Nestopia Debug Assertion!", MB_ABORTRETRYIGNORE|MB_SETFOREGROUND|MB_TOPMOST ); delete [] buffer; if (result != IDABORT) return result == IDIGNORE ? 1 : 2; result = NST_MESSAGEBOX ( ::GetActiveWindow(), "break into the debugger?", "Nestopia Debug Assertion!", MB_YESNO|MB_SETFOREGROUND|MB_TOPMOST ); if (result == IDNO) ::FatalExit( EXIT_FAILURE ); } else { NST_MESSAGEBOX ( ::GetActiveWindow(), "Out of memory!", "Nestopia Debug Assertion!", MB_OK|MB_ICONERROR|MB_SETFOREGROUND|MB_TOPMOST ); ::FatalExit( EXIT_FAILURE ); } return 0; } } } #endif nestopia-1.51.1/source/core/NstAssert.hpp000066400000000000000000000114211411157722000203070ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_ASSERT_H #define NST_ASSERT_H #ifndef NST_CORE_H #include "NstCore.hpp" #endif #ifdef NST_PRAGMA_ONCE #pragma once #endif #ifndef NST_DEBUG #define NST_DEBUG_MSG(msg_) NST_NOP() #define NST_ASSERT_MSG(expr_,msg_) NST_ASSUME(expr_) #define NST_VERIFY_MSG(expr_,msg_) NST_NOP() #elif defined(NST_WIN32) #if NST_GCC >= 200 || NST_MWERKS >= 0x3000 #define NST_FUNC_NAME __PRETTY_FUNCTION__ #elif NST_MSVC >= 1300 #define NST_FUNC_NAME __FUNCTION__ #elif NST_BCC >= 0x550 #define NST_FUNC_NAME __FUNC__ #else #define NST_FUNC_NAME 0 #endif #if NST_MSVC >= 1300 #define NST_HALT() __debugbreak() #elif NST_MSVC >= 1200 && defined(_M_IX86) #define NST_HALT() __asm {int 3} NST_NOP() #else #include #define NST_HALT() std::abort() #endif namespace Nes { namespace Assertion { NST_NO_INLINE uint NST_CALL Issue ( const char*, const char*, const char*, const char*, int ); } } #define NST_DEBUG_MSG(msg_) \ { \ static bool ignore_ = false; \ \ if (!ignore_) \ { \ switch (Nes::Assertion::Issue(0,msg_,__FILE__,NST_FUNC_NAME,__LINE__)) \ { \ case 0: NST_HALT(); break; \ case 1: ignore_ = true; break; \ } \ } \ } \ NST_NOP() #define NST_ASSERT_MSG(expr_,msg_) \ { \ static bool ignore_ = false; \ \ if (!ignore_ && !(expr_)) \ { \ switch (Nes::Assertion::Issue(#expr_,msg_,__FILE__,NST_FUNC_NAME,__LINE__)) \ { \ case 0: NST_HALT(); break; \ case 1: ignore_ = true; break; \ } \ } \ } \ NST_NOP() #define NST_VERIFY_MSG(expr_,msg_) NST_ASSERT_MSG(expr_,msg_) #else #include #define NST_DEBUG_MSG(msg_) NST_NOP() #define NST_ASSERT_MSG(expr_,msg_) assert( !!(expr_) ) #define NST_VERIFY_MSG(expr_,msg_) NST_NOP() #endif #define NST_ASSERT(expr_) NST_ASSERT_MSG(expr_,0) #define NST_VERIFY(expr_) NST_VERIFY_MSG(expr_,0) #endif nestopia-1.51.1/source/core/NstBarcodeReader.hpp000066400000000000000000000026021411157722000215310ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BARCODEREADER_H #define NST_BARCODEREADER_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class NST_NO_VTABLE BarcodeReader { public: virtual bool Transfer(cstring,uint) = 0; virtual bool IsDigitsSupported(uint) const = 0; virtual bool IsTransferring() const = 0; }; } } #endif nestopia-1.51.1/source/core/NstBase.hpp000066400000000000000000000254571411157722000177360ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BASE_H #define NST_BASE_H #include #include "api/NstApiConfig.hpp" //-------------------------------------------------------------------------------------- // Microsoft Visual C++ //-------------------------------------------------------------------------------------- #ifdef _MSC_VER #define NST_MSVC _MSC_VER #else #define NST_MSVC 0 #endif //-------------------------------------------------------------------------------------- // Intel C/C++ Compiler //-------------------------------------------------------------------------------------- #ifdef __INTEL_COMPILER #define NST_ICC __INTEL_COMPILER #else #define NST_ICC 0 #endif //-------------------------------------------------------------------------------------- // GNU Compiler Collection //-------------------------------------------------------------------------------------- #ifdef __GNUC__ #define NST_GCC (__GNUC__ * 100 + __GNUC_MINOR__) #else #define NST_GCC 0 #endif //-------------------------------------------------------------------------------------- // Borland C++ //-------------------------------------------------------------------------------------- #ifdef __BORLANDC__ #define NST_BCB __BORLANDC__ #else #define NST_BCB 0 #endif //-------------------------------------------------------------------------------------- // Metrowerks CodeWarrior //-------------------------------------------------------------------------------------- #ifdef __MWERKS__ #define NST_MWERKS __MWERKS__ #else #define NST_MWERKS 0 #endif //-------------------------------------------------------------------------------------- #ifdef NST_PRAGMA_ONCE #pragma once #elif NST_MSVC >= 1020 || NST_MWERKS >= 0x3000 #pragma once #define NST_PRAGMA_ONCE #endif //-------------------------------------------------------------------------------------- #ifndef NST_CALL #define NST_CALL #endif namespace Nes { typedef signed char schar; typedef unsigned char uchar; typedef unsigned short ushort; typedef unsigned int uint; typedef unsigned long ulong; #if UCHAR_MAX >= 0xFF typedef unsigned char byte; #else #error Unsupported plattform! #endif #if UCHAR_MAX >= 0xFFFF typedef unsigned char word; #elif USHRT_MAX >= 0xFFFF typedef unsigned short word; #elif UINT_MAX >= 0xFFFF typedef unsigned int word; #else #error Unsupported plattform! #endif #if SCHAR_MAX >= 32767 && SCHAR_MIN <= -32767 typedef signed char iword; #elif SHRT_MAX >= 32767 && SHRT_MIN <= -32767 typedef signed short iword; #elif INT_MAX >= 32767 && INT_MIN <= -32767 typedef signed int iword; #else #error Unsupported plattform! #endif #if UCHAR_MAX >= 0xFFFFFFFF typedef unsigned char dword; #elif USHRT_MAX >= 0xFFFFFFFF typedef unsigned short dword; #elif UINT_MAX >= 0xFFFFFFFF typedef unsigned int dword; #elif ULONG_MAX >= 0xFFFFFFFF typedef unsigned long dword; #else #error Unsupported plattform! #endif #if SCHAR_MAX >= 2147483647 && SCHAR_MIN <= -2147483647 typedef signed char idword; #elif SHRT_MAX >= 2147483647 && SHRT_MIN <= -2147483647 typedef signed short idword; #elif INT_MAX >= 2147483647 && INT_MIN <= -2147483647 typedef signed int idword; #elif LONG_MAX >= 2147483647 && LONG_MIN <= -2147483647 typedef signed long idword; #else #error Unsupported plattform! #endif /** * General result codes. */ enum Result { /** * NTSC/PAL region mismatch. */ RESULT_ERR_WRONG_MODE = -13, /** * Missing FDS BIOS. */ RESULT_ERR_MISSING_BIOS = -12, /** * Unsupported or malformed mapper. */ RESULT_ERR_UNSUPPORTED_MAPPER = -11, /** * Vs DualSystem is unsupported. */ RESULT_ERR_UNSUPPORTED_VSSYSTEM = -10, /** * File format version is no longer supported. */ RESULT_ERR_UNSUPPORTED_FILE_VERSION = -9, /** * Unsupported operation. */ RESULT_ERR_UNSUPPORTED = -8, /** * Invalid CRC checksum. */ RESULT_ERR_INVALID_CRC = -7, /** * Corrupt file. */ RESULT_ERR_CORRUPT_FILE = -6, /** * Invalid file. */ RESULT_ERR_INVALID_FILE = -5, /** * Invalid parameter(s). */ RESULT_ERR_INVALID_PARAM = -4, /** * System not ready. */ RESULT_ERR_NOT_READY = -3, /** * Out of memory. */ RESULT_ERR_OUT_OF_MEMORY = -2, /** * Generic error. */ RESULT_ERR_GENERIC = -1, /** * Success. */ RESULT_OK = 0, /** * Success but operation had no effect. */ RESULT_NOP = 1, /** * Success but image dump may be bad. */ RESULT_WARN_BAD_DUMP = 2, /** * Success but PRG-ROM may be bad. */ RESULT_WARN_BAD_PROM = 3, /** * Success but CHR-ROM may be bad. */ RESULT_WARN_BAD_CROM = 4, /** * Success but file header may have incorrect data. */ RESULT_WARN_BAD_FILE_HEADER = 5, /** * Success but save data has been lost. */ RESULT_WARN_SAVEDATA_LOST = 6, /** * Success but data may have been replaced. */ RESULT_WARN_DATA_REPLACED = 8 }; namespace Core { enum Region { REGION_NTSC, REGION_PAL }; enum System { SYSTEM_NES_NTSC, SYSTEM_NES_PAL, SYSTEM_NES_PAL_A, SYSTEM_NES_PAL_B, SYSTEM_FAMICOM, SYSTEM_DENDY, SYSTEM_VS_UNISYSTEM, SYSTEM_VS_DUALSYSTEM, SYSTEM_PLAYCHOICE_10 }; enum FavoredSystem { FAVORED_NES_NTSC, FAVORED_NES_PAL, FAVORED_FAMICOM, FAVORED_DENDY }; enum CpuModel { CPU_RP2A03, CPU_RP2A07, CPU_DENDY }; enum PpuModel { PPU_RP2C02, PPU_RP2C03B, PPU_RP2C03G, PPU_RP2C04_0001, PPU_RP2C04_0002, PPU_RP2C04_0003, PPU_RP2C04_0004, PPU_RC2C03B, PPU_RC2C03C, PPU_RC2C05_01, PPU_RC2C05_02, PPU_RC2C05_03, PPU_RC2C05_04, PPU_RC2C05_05, PPU_RP2C07, PPU_DENDY }; enum { CLK_M2_MUL = 6, CLK_NTSC = 39375000UL * CLK_M2_MUL, CLK_NTSC_DIV = 11, CLK_NTSC_HVSYNC = 525UL * 455 * CLK_NTSC_DIV * CLK_M2_MUL / 4, CLK_PAL = 35468950UL * CLK_M2_MUL, CLK_PAL_DIV = 8, CLK_PAL_HVSYNC = 625UL * 1418758 / (10000/CLK_PAL_DIV) * CLK_M2_MUL }; enum { CPU_RP2A03_CC = 12, CPU_RP2A07_CC = 16, CPU_DENDY_CC = 15 }; enum { PPU_RP2C02_CC = 4, PPU_RP2C02_HACTIVE = PPU_RP2C02_CC * 256, PPU_RP2C02_HBLANK = PPU_RP2C02_CC * 85, PPU_RP2C02_HSYNC = PPU_RP2C02_HACTIVE + PPU_RP2C02_HBLANK, PPU_RP2C02_VACTIVE = 240, PPU_RP2C02_VSLEEP = 1, PPU_RP2C02_VINT = 20, PPU_RP2C02_VDUMMY = 1, PPU_RP2C02_VBLANK = PPU_RP2C02_VSLEEP + PPU_RP2C02_VINT + PPU_RP2C02_VDUMMY, PPU_RP2C02_VSYNC = PPU_RP2C02_VACTIVE + PPU_RP2C02_VBLANK, PPU_RP2C02_HVSYNCBOOT = PPU_RP2C02_VACTIVE * PPU_RP2C02_HSYNC + PPU_RP2C02_CC * 312, PPU_RP2C02_HVREGBOOT = (PPU_RP2C02_VACTIVE + PPU_RP2C02_VINT) * PPU_RP2C02_HSYNC + PPU_RP2C02_CC * 314, PPU_RP2C02_HVINT = PPU_RP2C02_VINT * ulong(PPU_RP2C02_HSYNC), PPU_RP2C02_HVSYNC_0 = PPU_RP2C02_VSYNC * ulong(PPU_RP2C02_HSYNC), PPU_RP2C02_HVSYNC_1 = PPU_RP2C02_VSYNC * ulong(PPU_RP2C02_HSYNC) - PPU_RP2C02_CC, PPU_RP2C02_HVSYNC = (PPU_RP2C02_HVSYNC_0 + ulong(PPU_RP2C02_HVSYNC_1)) / 2, PPU_RP2C02_FPS = (CLK_NTSC + CLK_NTSC_DIV * ulong(PPU_RP2C02_HVSYNC) / 2) / (CLK_NTSC_DIV * ulong(PPU_RP2C02_HVSYNC)), PPU_RP2C07_CC = 5, PPU_RP2C07_HACTIVE = PPU_RP2C07_CC * 256, PPU_RP2C07_HBLANK = PPU_RP2C07_CC * 85, PPU_RP2C07_HSYNC = PPU_RP2C07_HACTIVE + PPU_RP2C07_HBLANK, PPU_RP2C07_VACTIVE = 240, PPU_RP2C07_VSLEEP = 1, PPU_RP2C07_VINT = 70, PPU_RP2C07_VDUMMY = 1, PPU_RP2C07_VBLANK = PPU_RP2C07_VSLEEP + PPU_RP2C07_VINT + PPU_RP2C07_VDUMMY, PPU_RP2C07_VSYNC = PPU_RP2C07_VACTIVE + PPU_RP2C07_VBLANK, PPU_RP2C07_HVSYNCBOOT = PPU_RP2C07_VACTIVE * PPU_RP2C07_HSYNC + PPU_RP2C07_CC * 312, PPU_RP2C07_HVREGBOOT = (PPU_RP2C07_VACTIVE + PPU_RP2C07_VINT) * PPU_RP2C07_HSYNC + PPU_RP2C07_CC * 314, PPU_RP2C07_HVINT = PPU_RP2C07_VINT * ulong(PPU_RP2C07_HSYNC), PPU_RP2C07_HVSYNC = PPU_RP2C07_VSYNC * ulong(PPU_RP2C07_HSYNC), PPU_RP2C07_FPS = (CLK_PAL + CLK_PAL_DIV * ulong(PPU_RP2C07_HVSYNC) / 2) / (CLK_PAL_DIV * ulong(PPU_RP2C07_HVSYNC)), PPU_DENDY_CC = 5, PPU_DENDY_HACTIVE = PPU_DENDY_CC * 256, PPU_DENDY_HBLANK = PPU_DENDY_CC * 85, PPU_DENDY_HSYNC = PPU_DENDY_HACTIVE + PPU_DENDY_HBLANK, PPU_DENDY_VACTIVE = 240, PPU_DENDY_VSLEEP = 51, PPU_DENDY_VINT = 20, PPU_DENDY_VDUMMY = 1, PPU_DENDY_VBLANK = PPU_DENDY_VSLEEP + PPU_DENDY_VINT + PPU_DENDY_VDUMMY, PPU_DENDY_VSYNC = PPU_DENDY_VACTIVE + PPU_DENDY_VBLANK, PPU_DENDY_HVSYNCBOOT = PPU_DENDY_VACTIVE * PPU_DENDY_HSYNC + PPU_DENDY_CC * 312, PPU_DENDY_HVREGBOOT = (PPU_DENDY_VACTIVE + PPU_DENDY_VINT) * PPU_DENDY_HSYNC + PPU_DENDY_CC * 314, PPU_DENDY_HVINT = PPU_DENDY_VINT * ulong(PPU_DENDY_HSYNC), PPU_DENDY_HVSYNC = PPU_DENDY_VSYNC * ulong(PPU_DENDY_HSYNC), PPU_DENDY_FPS = (CLK_PAL + CLK_PAL_DIV * ulong(PPU_DENDY_HVSYNC) / 2) / (CLK_PAL_DIV * ulong(PPU_DENDY_HVSYNC)) }; template class ImplicitBool; template<> class ImplicitBool { public: int type; typedef int ImplicitBool::*Type; }; template class ImplicitBool { template void operator == (const ImplicitBool&) const; template void operator != (const ImplicitBool&) const; public: operator ImplicitBool::Type () const { return !static_cast(*this) ? 0 : &ImplicitBool::type; } }; } } #define NES_FAILED(x_) ((x_) < Nes::RESULT_OK) #define NES_SUCCEEDED(x_) ((x_) >= Nes::RESULT_OK) #endif nestopia-1.51.1/source/core/NstCartridge.cpp000066400000000000000000000311541411157722000207520ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include "NstLog.hpp" #include "NstChecksum.hpp" #include "NstImageDatabase.hpp" #include "board/NstBoard.hpp" #include "NstCartridge.hpp" #include "NstCartridgeRomset.hpp" #include "NstCartridgeInes.hpp" #include "NstCartridgeUnif.hpp" #include "vssystem/NstVsSystem.hpp" #include "api/NstApiUser.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Cartridge::ProfileEx::ProfileEx() : nmt(NMT_DEFAULT), battery(false), wramAuto(false) {} Cartridge::Cartridge(Context& context) : Image(CARTRIDGE), board(NULL), vs(NULL), favoredSystem(context.favoredSystem) { try { ProfileEx profileEx; switch (Stream::In(&context.stream).Peek32()) { case INES_ID: Ines::Load ( context.stream, context.patch, context.patchBypassChecksum, context.patchResult, prg, chr, context.favoredSystem, profile, profileEx, context.database ); break; case UNIF_ID: Unif::Load ( context.stream, context.patch, context.patchBypassChecksum, context.patchResult, prg, chr, context.favoredSystem, profile, profileEx, context.database ); break; default: Romset::Load ( context.stream, context.patch, context.patchBypassChecksum, context.patchResult, prg, chr, context.favoredSystem, context.askProfile, profile ); break; } if (profile.dump.state == Profile::Dump::BAD) context.result = RESULT_WARN_BAD_DUMP; else context.result = RESULT_OK; const Result result = SetupBoard( prg, chr, &board, &context, profile, profileEx, &prgCrc ); if (NES_FAILED(result)) throw result; board->Load( savefile ); if ((profile.system.type) == Profile::System::VS_UNISYSTEM) { vs = VsSystem::Create ( context.cpu, context.ppu, static_cast(profile.system.ppu), prgCrc ); profile.system.ppu = static_cast(vs->GetPpuModel()); } else if ((profile.system.type) == Profile::System::VS_DUALSYSTEM) { throw RESULT_ERR_UNSUPPORTED_VSSYSTEM; } if (Cartridge::QueryExternalDevice( EXT_DIP_SWITCHES )) Log::Flush( "Cartridge: DIP Switches present" NST_LINEBREAK ); } catch (...) { Destroy(); throw; } } void Cartridge::Destroy() { VsSystem::Destroy( vs ); Boards::Board::Destroy( board ); } Cartridge::~Cartridge() { Destroy(); } void Cartridge::ReadRomset(std::istream& stream,FavoredSystem favoredSystem,bool askSystem,Profile& profile) { Log::Suppressor logSupressor; Ram prg, chr; ProfileEx profileEx; Romset::Load( stream, NULL, false, NULL, prg, chr, favoredSystem, askSystem, profile, true ); SetupBoard( prg, chr, NULL, NULL, profile, profileEx, NULL, true ); } void Cartridge::ReadInes(std::istream& stream,FavoredSystem favoredSystem,Profile& profile) { Log::Suppressor logSupressor; Ram prg, chr; ProfileEx profileEx; Ines::Load( stream, NULL, false, NULL, prg, chr, favoredSystem, profile, profileEx, NULL ); SetupBoard( prg, chr, NULL, NULL, profile, profileEx, NULL ); } void Cartridge::ReadUnif(std::istream& stream,FavoredSystem favoredSystem,Profile& profile) { Log::Suppressor logSupressor; Ram prg, chr; ProfileEx profileEx; Unif::Load( stream, NULL, false, NULL, prg, chr, favoredSystem, profile, profileEx, NULL ); SetupBoard( prg, chr, NULL, NULL, profile, profileEx, NULL ); } uint Cartridge::GetDesiredController(uint port) const { NST_ASSERT( port < Api::Input::NUM_CONTROLLERS ); return profile.game.controllers[port]; } uint Cartridge::GetDesiredAdapter() const { return profile.game.adapter; } Cartridge::ExternalDevice Cartridge::QueryExternalDevice(ExternalDeviceType deviceType) { switch (deviceType) { case EXT_DIP_SWITCHES: if (vs) return &vs->GetDipSwiches(); else return board->QueryDevice( Boards::Board::DEVICE_DIP_SWITCHES ); case EXT_BARCODE_READER: return board->QueryDevice( Boards::Board::DEVICE_BARCODE_READER ); default: return Image::QueryExternalDevice( deviceType ); } } Result Cartridge::SetupBoard ( Ram& prg, Ram& chr, Boards::Board** board, const Context* const context, Profile& profile, const ProfileEx& profileEx, dword* const prgCrc, const bool readOnly ) { NST_ASSERT( bool(board) == bool(context) ); Boards::Board::Type::Nmt nmt; if (profile.board.solderPads & (Profile::Board::SOLDERPAD_H|Profile::Board::SOLDERPAD_V)) { if (profile.board.solderPads & Profile::Board::SOLDERPAD_H) nmt = Boards::Board::Type::NMT_VERTICAL; else nmt = Boards::Board::Type::NMT_HORIZONTAL; } else switch (profileEx.nmt) { case ProfileEx::NMT_HORIZONTAL: nmt = Boards::Board::Type::NMT_HORIZONTAL; break; case ProfileEx::NMT_VERTICAL: nmt = Boards::Board::Type::NMT_VERTICAL; break; case ProfileEx::NMT_SINGLESCREEN: nmt = Boards::Board::Type::NMT_SINGLESCREEN; break; case ProfileEx::NMT_FOURSCREEN: nmt = Boards::Board::Type::NMT_FOURSCREEN; break; default: nmt = Boards::Board::Type::NMT_CONTROLLED; break; } Chips chips; for (Profile::Board::Chips::const_iterator i(profile.board.chips.begin()), end(profile.board.chips.end()); i != end; ++i) { Chips::Type& type = chips.Add( i->type.c_str() ); for (Profile::Board::Pins::const_iterator j(i->pins.begin()), end(i->pins.end()); j != end; ++j) type.Pin(j->number) = j->function.c_str(); for (Profile::Board::Samples::const_iterator j(i->samples.begin()), end(i->samples.end()); j != end; ++j) type.Sample(j->id) = j->file.c_str(); } Boards::Board::Context b ( context ? &context->cpu : NULL, context ? &context->apu : NULL, context ? &context->ppu : NULL, prg, chr, profileEx.trainer, nmt, profileEx.battery || profile.board.HasWramBattery(), profile.board.HasMmcBattery(), chips ); if (profile.board.type.empty() || !b.DetectBoard( profile.board.type.c_str(), profile.board.GetWram() )) { if (profile.board.mapper == Profile::Board::NO_MAPPER || (!b.DetectBoard( profile.board.mapper, profile.board.subMapper, profile.board.chrRam, profile.board.GetWram(), profileEx.wramAuto ) && board)) return RESULT_ERR_UNSUPPORTED_MAPPER; if (profile.board.type.empty()) profile.board.type = std::wstring( b.name, b.name + std::strlen(b.name) ); } if (profile.board.mapper == Profile::Board::NO_MAPPER && b.type.GetMapper() != Boards::Board::Type::NMPR) profile.board.mapper = b.type.GetMapper(); for (uint i=0; i < 2; ++i) { dword size = (i ? b.chr : b.prg).Size(); if (size != (i ? profile.board.GetChr() : profile.board.GetPrg())) { Profile::Board::Roms& roms = (i ? profile.board.chr : profile.board.prg); roms.clear(); if (size) { Profile::Board::Rom rom; rom.size = size; roms.push_back( rom ); } } size = (i ? b.type.GetVram() : b.type.GetWram()); if (size != (i ? profile.board.GetVram() : profile.board.GetWram())) { Profile::Board::Rams& rams = (i ? profile.board.vram : profile.board.wram); rams.clear(); for (uint j=0; j < 2; ++j) { size = i ? (j ? b.type.GetNonSavableVram() : b.type.GetSavableVram()) : (j ? b.type.GetNonSavableWram() : b.type.GetSavableWram()); if (size) { Profile::Board::Ram ram; ram.size = size; ram.battery = (i == 0 && j == 0 && b.wramBattery); rams.push_back( ram ); } } } Profile::Board::Roms& roms = (i ? profile.board.chr : profile.board.prg); for (dword j=0, k=0, n=roms.size(); j < n; k += roms[j].size, ++j) roms[j].hash.Compute( (i ? chr : prg).Mem(k), roms[j].size ); } if (!readOnly) { Checksum checksum; checksum.Compute( prg.Mem(), prg.Size() ); if (prgCrc) *prgCrc = checksum.GetCrc(); checksum.Compute( chr.Mem(), chr.Size() ); profile.hash.Assign( checksum.GetSha1(), checksum.GetCrc() ); } if (board) *board = Boards::Board::Create( b ); return RESULT_OK; } void Cartridge::Reset(const bool hard) { board->Reset( hard ); if (vs) vs->Reset( hard ); } bool Cartridge::PowerOff() { try { if (board) { board->Sync( Boards::Board::EVENT_POWER_OFF, NULL ); board->Save( savefile ); } return true; } catch (...) { return false; } } void Cartridge::SaveState(State::Saver& state,const dword baseChunk) const { state.Begin( baseChunk ); board->SaveState( state, AsciiId<'M','P','R'>::V ); if (vs) vs->SaveState( state, AsciiId<'V','S','S'>::V ); state.End(); } void Cartridge::LoadState(State::Loader& state) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'M','P','R'>::V: board->LoadState( state ); break; case AsciiId<'V','S','S'>::V: NST_VERIFY( vs ); if (vs) vs->LoadState( state ); break; } state.End(); } } Region Cartridge::GetDesiredRegion() const { switch (profile.system.type) { case Profile::System::NES_PAL: case Profile::System::NES_PAL_A: case Profile::System::NES_PAL_B: case Profile::System::DENDY: return REGION_PAL; case Profile::System::NES_NTSC: case Profile::System::FAMICOM: if (favoredSystem == FAVORED_DENDY) return REGION_PAL; default: return REGION_NTSC; } } System Cartridge::GetDesiredSystem(Region region,CpuModel* cpu,PpuModel* ppu) const { if (region == Cartridge::GetDesiredRegion()) { if (favoredSystem == FAVORED_DENDY && region == REGION_PAL) { switch (profile.system.type) { case Profile::System::NES_NTSC: case Profile::System::NES_PAL: case Profile::System::NES_PAL_A: case Profile::System::NES_PAL_B: case Profile::System::FAMICOM: case Profile::System::DENDY: if (cpu) *cpu = CPU_DENDY; if (ppu) *ppu = PPU_DENDY; return SYSTEM_DENDY; case Profile::System::VS_UNISYSTEM: case Profile::System::VS_DUALSYSTEM: case Profile::System::PLAYCHOICE_10: default: break; } } if (cpu) *cpu = static_cast(profile.system.cpu); if (ppu) *ppu = static_cast(profile.system.ppu); return static_cast(profile.system.type); } else { return Image::GetDesiredSystem( region, cpu, ppu ); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Cartridge::BeginFrame(const Api::Input& input,Input::Controllers* controllers) { board->Sync( Boards::Board::EVENT_BEGIN_FRAME, controllers ); if (vs) vs->BeginFrame( input, controllers ); } void Cartridge::VSync() { board->Sync( Boards::Board::EVENT_END_FRAME, NULL ); if (vs) vs->VSync(); } } } nestopia-1.51.1/source/core/NstCartridge.hpp000066400000000000000000000060221411157722000207530ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_CARTRIDGE_H #define NST_CARTRIDGE_H #include "NstRam.hpp" #include "NstImage.hpp" #include "NstFile.hpp" #include "api/NstApiCartridge.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { class Board; } class Cartridge : public Image { public: explicit Cartridge(Context&); void BeginFrame(const Api::Input&,Input::Controllers*); typedef Api::Cartridge::Profile Profile; static void ReadRomset(std::istream&,FavoredSystem,bool,Profile&); static void ReadInes(std::istream&,FavoredSystem,Profile&); static void ReadUnif(std::istream&,FavoredSystem,Profile&); class Ines; class Unif; class Romset; private: ~Cartridge(); struct ProfileEx { ProfileEx(); enum Nmt { NMT_DEFAULT, NMT_HORIZONTAL, NMT_VERTICAL, NMT_SINGLESCREEN, NMT_FOURSCREEN, NMT_CONTROLLED }; Nmt nmt; bool battery; bool wramAuto; Ram trainer; }; class VsSystem; static Result SetupBoard ( Ram&, Ram&, Boards::Board**, const Context*, Profile&, const ProfileEx&, dword*, bool=false ); void Reset(bool); bool PowerOff(); void LoadState(State::Loader&); void SaveState(State::Saver&,dword) const; void Destroy(); void VSync(); uint GetDesiredController(uint) const; uint GetDesiredAdapter() const; void DetectControllers(uint); Region GetDesiredRegion() const; System GetDesiredSystem(Region,CpuModel*,PpuModel*) const; ExternalDevice QueryExternalDevice(ExternalDeviceType); Boards::Board* board; VsSystem* vs; Ram prg; Ram chr; Profile profile; dword prgCrc; File savefile; const FavoredSystem favoredSystem; public: const Profile& GetProfile() const { return profile; } dword GetPrgCrc() const { return prgCrc; } }; } } #endif nestopia-1.51.1/source/core/NstCartridgeInes.cpp000066400000000000000000000524431411157722000215750ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstLog.hpp" #include "NstPatcher.hpp" #include "NstStream.hpp" #include "NstChecksum.hpp" #include "NstImageDatabase.hpp" #include "NstCartridge.hpp" #include "NstCartridgeInes.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif class Cartridge::Ines::Loader { bool Load(Ram&,dword); enum TrainerSetup { TRAINER_NONE, TRAINER_IGNORE, TRAINER_READ }; enum { VS_MAPPER_99 = 99, VS_MAPPER_151 = 151, FFE_MAPPER_6 = 6, FFE_MAPPER_8 = 8, FFE_MAPPER_17 = 17, TRAINER_LENGTH = 0x200, MIN_DB_SEARCH_STRIDE = SIZE_8K, MAX_DB_SEARCH_LENGTH = SIZE_16K * 0xFFFUL + SIZE_8K * 0xFFFUL }; Stream::In stream; const FavoredSystem favoredSystem; Profile& profile; ProfileEx& profileEx; Ram& prg; Ram& chr; const ImageDatabase* const database; Patcher patcher; public: Loader ( std::istream& stdStreamImage, std::istream* const stdStreamPatch, const bool patchBypassChecksum, Result* const patchResult, Ram& p, Ram& c, const FavoredSystem f, Profile& r, ProfileEx& x, const ImageDatabase* const d ) : stream (&stdStreamImage), favoredSystem (f), profile (r), profileEx (x), prg (p), chr (c), database (d), patcher (patchBypassChecksum) { NST_ASSERT( prg.Empty() && chr.Empty() ); if (stdStreamPatch) *patchResult = patcher.Load( *stdStreamPatch, stdStreamImage ); profile = Profile(); profileEx = ProfileEx(); } void Load() { const TrainerSetup trainerSetup = Collect(); if (!profile.patched) { if (const ImageDatabase::Entry entry = SearchDatabase( trainerSetup )) { entry.Fill( profile, patcher.Empty() ); profileEx.wramAuto = false; } } prg.Set( profile.board.GetPrg() ); chr.Set( profile.board.GetChr() ); if (!profile.board.prg.empty()) { for (Profile::Board::Pins::const_iterator it(profile.board.prg.front().pins.begin()), end(profile.board.prg.front().pins.end()); it != end; ++it) prg.Pin(it->number) = it->function.c_str(); } if (!profile.board.chr.empty()) { for (Profile::Board::Pins::const_iterator it(profile.board.chr.front().pins.begin()), end(profile.board.chr.front().pins.end()); it != end; ++it) chr.Pin(it->number) = it->function.c_str(); } if (trainerSetup == TRAINER_READ) { profileEx.trainer.Set( TRAINER_LENGTH ); stream.Read( profileEx.trainer.Mem(), TRAINER_LENGTH ); } else if (trainerSetup == TRAINER_IGNORE) { stream.Seek( TRAINER_LENGTH ); } if (Load( prg, 16 )) Log::Flush( "Ines: PRG-ROM was patched" NST_LINEBREAK ); if (Load( chr, 16 + prg.Size() )) Log::Flush( "Ines: PRG-ROM was patched" NST_LINEBREAK ); } private: TrainerSetup Collect() { NST_COMPILE_ASSERT ( Header::PPU_RP2C03B == 1 && Header::PPU_RP2C03G == 2 && Header::PPU_RP2C04_0001 == 3 && Header::PPU_RP2C04_0002 == 4 && Header::PPU_RP2C04_0003 == 5 && Header::PPU_RP2C04_0004 == 6 && Header::PPU_RC2C03B == 7 && Header::PPU_RC2C03C == 8 && Header::PPU_RC2C05_01 == 9 && Header::PPU_RC2C05_02 == 10 && Header::PPU_RC2C05_03 == 11 && Header::PPU_RC2C05_04 == 12 && Header::PPU_RC2C05_05 == 13 ); Header setup; byte header[16]; stream.Read( header ); if (patcher.Patch( header, header, 16 )) { profile.patched = true; Log::Flush( "Ines: header was patched" NST_LINEBREAK ); } Result result = ReadHeader( setup, header, 16 ); if (NES_FAILED(result)) throw RESULT_ERR_CORRUPT_FILE; Log log; static const char title[] = "Ines: "; if (setup.version) { log << title << "NES 2.0 (extended iNES)" NST_LINEBREAK; } if (result == RESULT_WARN_BAD_FILE_HEADER) log << title << "warning, unknown or invalid header data!" NST_LINEBREAK; log << title << (setup.prgRom / SIZE_1K) << "k PRG-ROM set" NST_LINEBREAK; if (setup.version) { if (setup.prgRam) { log << title << (setup.prgRam % SIZE_1K ? setup.prgRam : setup.prgRam / SIZE_1K) << (setup.prgRam % SIZE_1K ? " byte" : "k") << " PRG-RAM set" NST_LINEBREAK; } if (setup.prgNvRam) { log << title << (setup.prgNvRam % SIZE_1K ? setup.prgNvRam : setup.prgNvRam / SIZE_1K) << (setup.prgNvRam % SIZE_1K ? " bytes" : "k") << " non-volatile PRG-RAM set" NST_LINEBREAK; } } if (setup.chrRom) { log << title << (setup.chrRom / SIZE_1K) << "k CHR-ROM set" NST_LINEBREAK; } if (setup.version) { if (setup.chrRam) { profile.board.chrRam = setup.chrRam / SIZE_1K; log << title << (setup.chrRam % SIZE_1K ? setup.chrRam : setup.chrRam / SIZE_1K) << (setup.chrRam % SIZE_1K ? " bytes" : "k") << " CHR-RAM set" NST_LINEBREAK; } if (setup.chrNvRam) { log << title << (setup.chrNvRam % SIZE_1K ? setup.chrNvRam : setup.chrNvRam / SIZE_1K) << (setup.chrNvRam % SIZE_1K ? " bytes" : "k") << " non-volatile CHR-RAM set" NST_LINEBREAK; } } else { if (header[8]) { log << title << (header[8] * 8U) << "k W-RAM set" NST_LINEBREAK; } if (header[6] & 0x2U) { log << title << "battery set" NST_LINEBREAK; } } log << title << ( setup.mirroring == Header::MIRRORING_FOURSCREEN ? "four-screen" : setup.mirroring == Header::MIRRORING_VERTICAL ? "vertical" : "horizontal" ) << " mirroring set" NST_LINEBREAK; log << title << ( setup.region == Header::REGION_BOTH ? "NTSC/PAL" : setup.region == Header::REGION_PAL ? "PAL": "NTSC" ) << " set" NST_LINEBREAK; if (setup.system == Header::SYSTEM_VS) { log << title << "VS System set" NST_LINEBREAK; if (setup.version) { if (setup.ppu) { static cstring const names[] = { "RP2C03B", "RP2C03G", "RP2C04-0001", "RP2C04-0002", "RP2C04-0003", "RP2C04-0004", "RC2C03B", "RC2C03C", "RC2C05-01", "RC2C05-02", "RC2C05-03", "RC2C05-04", "RC2C05-05" }; NST_ASSERT( setup.ppu < 1+sizeof(array(names)) ); log << title << names[setup.ppu-1] << " PPU set" NST_LINEBREAK; } if (setup.security) { static const cstring names[] = { "RBI Baseball", "TKO Boxing", "Super Xevious" }; NST_ASSERT( setup.security < 1+sizeof(array(names)) ); log << title << names[setup.security-1] << " VS mode set" NST_LINEBREAK; } } } else if (setup.system == Header::SYSTEM_PC10) { log << title << "PlayChoice-10 set" NST_LINEBREAK; } log << title << "mapper " << setup.mapper << " set"; if (setup.system != Header::SYSTEM_VS && (setup.mapper == VS_MAPPER_99 || setup.mapper == VS_MAPPER_151)) { setup.system = Header::SYSTEM_VS; setup.ppu = Header::PPU_RP2C03B; log << ", forcing VS System"; } log << NST_LINEBREAK; if (setup.version && setup.subMapper) log << title << "submapper " << setup.subMapper << " set" NST_LINEBREAK; TrainerSetup trainerSetup; if (!setup.trainer) { trainerSetup = TRAINER_NONE; } else if (setup.mapper == FFE_MAPPER_6 || setup.mapper == FFE_MAPPER_8 || setup.mapper == FFE_MAPPER_17) { trainerSetup = TRAINER_READ; log << title << "trainer set" NST_LINEBREAK; if (setup.prgRam + setup.prgNvRam < SIZE_8K) { setup.prgRam = SIZE_8K - setup.prgNvRam; log << title << "warning, forcing 8k of W-RAM for trainer" NST_LINEBREAK; } } else { trainerSetup = TRAINER_IGNORE; log << title << "warning, trainer ignored" NST_LINEBREAK; } if (setup.prgRom) { Profile::Board::Rom rom; rom.size = setup.prgRom; profile.board.prg.push_back( rom ); } if (setup.chrRom) { Profile::Board::Rom rom; rom.size = setup.chrRom; profile.board.chr.push_back( rom ); } if (setup.prgNvRam) { Profile::Board::Ram ram; ram.size = setup.prgNvRam; ram.battery = true; profile.board.wram.push_back( ram ); } if (setup.prgRam) { Profile::Board::Ram ram; ram.size = setup.prgRam; profile.board.wram.push_back( ram ); } if (setup.chrNvRam) { Profile::Board::Ram ram; ram.size = setup.chrNvRam; ram.battery = true; profile.board.vram.push_back( ram ); } if (setup.chrRam) { Profile::Board::Ram ram; ram.size = setup.chrRam; profile.board.vram.push_back( ram ); } profile.board.mapper = setup.mapper; profile.board.subMapper = setup.subMapper; profileEx.wramAuto = (setup.version == 0 && profile.board.wram.empty()); switch (setup.mirroring) { case Header::MIRRORING_HORIZONTAL: profile.board.solderPads = Profile::Board::SOLDERPAD_V; break; case Header::MIRRORING_VERTICAL: profile.board.solderPads = Profile::Board::SOLDERPAD_H; break; case Header::MIRRORING_FOURSCREEN: profileEx.nmt = ProfileEx::NMT_FOURSCREEN; break; case Header::MIRRORING_SINGLESCREEN: case Header::MIRRORING_CONTROLLED: default: break; } profile.system.cpu = Profile::System::CPU_RP2A03; profile.system.ppu = static_cast(setup.ppu); switch (setup.system) { case Header::SYSTEM_VS: profile.system.type = Profile::System::VS_UNISYSTEM; break; case Header::SYSTEM_PC10: profile.system.type = Profile::System::PLAYCHOICE_10; break; default: switch (setup.region) { case Header::REGION_NTSC: if (favoredSystem == FAVORED_FAMICOM) { profile.system.type = Profile::System::FAMICOM; } else if (favoredSystem == FAVORED_DENDY) { profile.system.type = Profile::System::DENDY; profile.system.ppu = Profile::System::PPU_DENDY; profile.system.cpu = Profile::System::CPU_DENDY; } else { profile.system.type = Profile::System::NES_NTSC; } break; default: profile.multiRegion = true; if (favoredSystem == FAVORED_FAMICOM) { profile.system.type = Profile::System::FAMICOM; break; } else if (favoredSystem != FAVORED_NES_PAL && favoredSystem != FAVORED_DENDY) { profile.system.type = Profile::System::NES_NTSC; break; } case Header::REGION_PAL: if (favoredSystem == FAVORED_DENDY) { profile.system.type = Profile::System::DENDY; profile.system.cpu = Profile::System::CPU_DENDY; profile.system.ppu = Profile::System::PPU_DENDY; } else { profile.system.type = Profile::System::NES_PAL; profile.system.cpu = Profile::System::CPU_RP2A07; profile.system.ppu = Profile::System::PPU_RP2C07; } break; } break; } return trainerSetup; } ImageDatabase::Entry SearchDatabase(const TrainerSetup trainerSetup) { ImageDatabase::Entry entry; if (database && database->Enabled()) { if (trainerSetup != TRAINER_NONE) stream.Seek( TRAINER_LENGTH ); const dword romLength = profile.board.GetPrg() + profile.board.GetChr(); dword count = 0; for (Checksum it, checksum;;) { const uint data = stream.SafeRead8(); if (data <= 0xFF) { const byte in = data; it.Compute( &in, 1 ); if (++count % MIN_DB_SEARCH_STRIDE == 0) checksum = it; } const bool stop = (data > 0xFF || count == MAX_DB_SEARCH_LENGTH); if (stop || count == romLength) { entry = database->Search( Profile::Hash(checksum.GetSha1(),checksum.GetCrc()), favoredSystem ); if (stop || entry) break; } } if (count) stream.Seek( -idword(count) + (trainerSetup == TRAINER_NONE ? 0 : -TRAINER_LENGTH) ); } return entry; } }; bool Cartridge::Ines::Loader::Load(Ram& rom,const dword offset) { if (rom.Size()) { if (patcher.Empty()) { stream.Read( rom.Mem(), rom.Size() ); } else { dword size = stream.Length(); NST_VERIFY( size >= rom.Size() ); if (size > rom.Size()) size = rom.Size(); if (size) stream.Read( rom.Mem(), size ); if (patcher.Patch( rom.Mem(), rom.Mem(), rom.Size(), offset )) { profile.patched = true; return true; } } } return false; } void Cartridge::Ines::Load ( std::istream& stdStreamImage, std::istream* const stdStreamPatch, const bool patchBypassChecksum, Result* const patchResult, Ram& prg, Ram& chr, const FavoredSystem favoredSystem, Profile& profile, ProfileEx& profileEx, const ImageDatabase* const database ) { Loader loader ( stdStreamImage, stdStreamPatch, patchBypassChecksum, patchResult, prg, chr, favoredSystem, profile, profileEx, database ); loader.Load(); } Result Cartridge::Ines::ReadHeader(Header& setup,const byte* const file,const ulong length) { if (file == NULL) return RESULT_ERR_INVALID_PARAM; if ( length < 4 || file[0] != Ascii<'N'>::V || file[1] != Ascii<'E'>::V || file[2] != Ascii<'S'>::V || file[3] != 0x1A ) return RESULT_ERR_INVALID_FILE; if (length < 16) return RESULT_ERR_CORRUPT_FILE; byte header[16]; std::memcpy( header, file, 16 ); Result result = RESULT_OK; setup.version = ((header[7] & 0xCU) == 0x8 ? 2 : 0); if (!setup.version) { for (uint i=10; i < 16; ++i) { if (header[i]) { header[7] = 0; header[8] = 0; header[9] = 0; result = RESULT_WARN_BAD_FILE_HEADER; break; } } } setup.prgRom = header[4]; setup.chrRom = header[5]; if (setup.version) { setup.prgRom |= uint(header[9]) << 8 & 0xF00; setup.chrRom |= uint(header[9]) << 4 & 0xF00; } setup.prgRom *= SIZE_16K; setup.chrRom *= SIZE_8K; setup.trainer = bool(header[6] & 0x4U); setup.mapper = (header[6] >> 4) | (header[7] & 0xF0U); setup.subMapper = 0; if (setup.version) { setup.mapper |= uint(header[8]) << 8 & 0x300; setup.subMapper = header[8] >> 4; } if (header[6] & 0x8U) { setup.mirroring = Header::MIRRORING_FOURSCREEN; } else if (header[6] & 0x1U) { setup.mirroring = Header::MIRRORING_VERTICAL; } else { setup.mirroring = Header::MIRRORING_HORIZONTAL; } setup.security = 0; if (header[7] & 0x1U) { setup.system = Header::SYSTEM_VS; setup.ppu = Header::PPU_RP2C03B; if (setup.version) { if ((header[13] & 0xFU) < 13) setup.ppu = static_cast((header[13] & 0xFU) + 1); if ((header[13] >> 4) < 4) setup.security = header[13] >> 4; } } else if (setup.version && (header[7] & 0x2U)) { setup.system = Header::SYSTEM_PC10; setup.ppu = Header::PPU_RP2C03B; } else { setup.system = Header::SYSTEM_CONSOLE; setup.ppu = Header::PPU_RP2C02; } if (setup.version && (header[12] & 0x2U)) { setup.region = Header::REGION_BOTH; } else if (header[setup.version ? 12 : 9] & 0x1U) { if (setup.system == Header::SYSTEM_CONSOLE) { setup.region = Header::REGION_PAL; setup.ppu = Header::PPU_RP2C07; } else { setup.region = Header::REGION_NTSC; } } else { setup.region = Header::REGION_NTSC; } if (setup.version) { setup.prgRam = ((header[10]) & 0xFU) - 1U < 14 ? 64UL << (header[10] & 0xFU) : 0; setup.prgNvRam = ((header[10]) >> 4) - 1U < 14 ? 64UL << (header[10] >> 4) : 0; setup.chrRam = ((header[11]) & 0xFU) - 1U < 14 ? 64UL << (header[11] & 0xFU) : 0; setup.chrNvRam = ((header[11]) >> 4) - 1U < 14 ? 64UL << (header[11] >> 4) : 0; } else { setup.prgRam = ((header[6] & 0x2U) ? 0 : header[8] * dword(SIZE_8K)); setup.prgNvRam = ((header[6] & 0x2U) ? NST_MAX(header[8],1U) * dword(SIZE_8K) : 0); setup.chrRam = (setup.chrRom ? 0 : SIZE_8K); setup.chrNvRam = 0; } return result; } Result Cartridge::Ines::WriteHeader(const Header& setup,byte* const file,const ulong length) { if ( (file == NULL || length < 16) || (setup.prgRom > (setup.version ? 0xFFFUL * SIZE_16K : 0xFFUL * SIZE_16K)) || (setup.chrRom > (setup.version ? 0xFFFUL * SIZE_8K : 0xFFUL * SIZE_8K)) || (setup.mapper > (setup.version ? 0x1FF : 0xFF)) || (setup.version && setup.subMapper > 0xF) ) return RESULT_ERR_INVALID_PARAM; byte header[16] = { Ascii<'N'>::V, Ascii<'E'>::V, Ascii<'S'>::V, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; if (setup.version) header[7] |= 0x8U; header[4] = (setup.prgRom / SIZE_16K) & 0xFF; header[5] = (setup.chrRom / SIZE_8K) & 0xFF; if (setup.version) { header[9] |= (setup.prgRom / SIZE_16K) >> 8; header[9] |= (setup.chrRom / SIZE_8K) >> 4 & 0xF0; } if (setup.mirroring == Header::MIRRORING_FOURSCREEN) { header[6] |= 0x8U; } else if (setup.mirroring == Header::MIRRORING_VERTICAL) { header[6] |= 0x1U; } if (setup.prgNvRam) header[6] |= 0x2U; if (setup.trainer) header[6] |= 0x4U; if (setup.system == Header::SYSTEM_VS) { header[7] |= 0x1U; } else if (setup.version && setup.system == Header::SYSTEM_PC10) { header[7] |= 0x2U; } header[6] |= setup.mapper << 4 & 0xF0U; header[7] |= setup.mapper & 0xF0U; if (setup.version) { header[8] |= setup.mapper >> 8; header[8] |= setup.subMapper << 4; uint i, data; for (i=0, data=setup.prgRam >> 7; data; data >>= 1, ++i) { if (i > 0xF) return RESULT_ERR_INVALID_PARAM; } header[10] |= i; for (i=0, data=setup.prgNvRam >> 7; data; data >>= 1, ++i) { if (i > 0xF) return RESULT_ERR_INVALID_PARAM; } header[10] |= i << 4; for (i=0, data=setup.chrRam >> 7; data; data >>= 1, ++i) { if (i > 0xF) return RESULT_ERR_INVALID_PARAM; } header[11] |= i; for (i=0, data=setup.chrNvRam >> 7; data; data >>= 1, ++i) { if (i > 0xF) return RESULT_ERR_INVALID_PARAM; } header[11] |= i << 4; if (setup.region == Header::REGION_BOTH) { header[12] |= 0x2U; } else if (setup.region == Header::REGION_PAL) { header[12] |= 0x1U; } if (setup.system == Header::SYSTEM_VS) { if (setup.ppu > 0xF || setup.security > 0xF) return RESULT_ERR_INVALID_PARAM; if (setup.ppu) header[13] = setup.ppu - 1; header[13] |= setup.security << 4; } } else { header[8] = (setup.prgRam + setup.prgNvRam) / SIZE_8K; header[9] = (setup.region == Header::REGION_PAL ? 0x1 : 0x0); } std::memcpy( file, header, 16 ); return RESULT_OK; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } nestopia-1.51.1/source/core/NstCartridgeInes.hpp000066400000000000000000000031521411157722000215730ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_CARTRIDGE_INES_H #define NST_CARTRIDGE_INES_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class Cartridge::Ines { class Loader; public: typedef Api::Cartridge::NesHeader Header; static void Load ( std::istream&, std::istream*, bool, Result*, Ram&, Ram&, FavoredSystem, Profile&, ProfileEx&, const ImageDatabase* ); static Result ReadHeader(Header&,const byte*,ulong); static Result WriteHeader(const Header&,byte*,ulong); }; } } #endif nestopia-1.51.1/source/core/NstCartridgeRomset.cpp000066400000000000000000000716761411157722000221610ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include #include "NstLog.hpp" #include "NstPatcher.hpp" #include "NstXml.hpp" #include "NstStream.hpp" #include "NstChecksum.hpp" #include "NstCartridge.hpp" #include "NstCartridgeRomset.hpp" #include "api/NstApiCartridge.hpp" #include "api/NstApiUser.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif class Cartridge::Romset::Loader { typedef std::vector Profiles; enum { DEFAULT_VERSION = 10, MIN_PLAYERS = 1, MAX_PLAYERS = 255, MIN_CHIP_SIZE = 1, MAX_CHIP_SIZE = SIZE_16384K, MIN_IC_PINS = 1, MAX_IC_PINS = 127, MAX_CHIP_SAMPLES = 255, MAX_MAPPER = 255 }; std::istream& imageStream; std::istream* const patchStream; const FavoredSystem favoredSystem; Ram& prg; Ram& chr; Profile& profile; Profiles profiles; Result* const patchResult; const bool askProfile; const bool readOnly; const bool patchBypassChecksum; public: Loader ( std::istream& i, std::istream* t, const bool b, Result* const e, Ram& p, Ram& c, const FavoredSystem f, const bool a, Profile& r, const bool o ) : imageStream (i), patchStream (t), favoredSystem (f), prg (p), chr (c), profile (r), patchResult (e), askProfile (a), readOnly (o), patchBypassChecksum (b) { NST_ASSERT( prg.Empty() && chr.Empty() ); } void Load() { Collect(); ChooseProfile(); LoadRoms(); PatchRoms(); } private: void Collect() { Xml xml; if (!xml.Read( imageStream )) throw RESULT_ERR_INVALID_FILE; const Xml::Node romset( xml.GetRoot() ); if (!romset.IsType( L"romset" )) throw RESULT_ERR_INVALID_FILE; uint version = DEFAULT_VERSION; if (const Xml::Attribute attribute=romset.GetAttribute( L"version" )) { wcstring const string = attribute.GetValue(); if ( (string[0] >= L'1' && string[0] <= L'9') && (string[1] == L'.') && (string[2] >= L'0' && string[2] <= L'9') && (string[3] == L'\0') ) { version = (string[0] - L'0') * 10 + (string[2] - L'0'); } else { throw RESULT_ERR_INVALID_FILE; } } bool strict = true; if (const Xml::Attribute attribute=romset.GetAttribute( L"conformance" )) { if (attribute.IsValue( L"loose" )) { strict = false; } else if (version != DEFAULT_VERSION && !attribute.IsValue( L"strict" )) { throw RESULT_ERR_INVALID_FILE; } } profiles.reserve( 4 ); for (Xml::Node game(xml.GetRoot().GetFirstChild()); game; game=game.GetNextSibling()) { for (Xml::Node image(game.GetFirstChild()); image; image=image.GetNextSibling()) { Profile p; p.game.title = game.GetAttribute( L"name" ).GetValue(); p.game.altTitle = game.GetAttribute( L"altname" ).GetValue(); p.game.clss = game.GetAttribute( L"class" ).GetValue(); p.game.subClss = game.GetAttribute( L"subclass" ).GetValue(); p.game.catalog = game.GetAttribute( L"catalog" ).GetValue(); p.game.publisher = game.GetAttribute( L"publisher" ).GetValue(); p.game.developer = game.GetAttribute( L"developer" ).GetValue(); p.game.portDeveloper = game.GetAttribute( L"portdeveloper" ).GetValue(); p.game.region = game.GetAttribute( L"region" ).GetValue(); if (const Xml::Attribute attribute=game.GetAttribute( L"players" )) { const ulong players = attribute.GetUnsignedValue(); if (players >= MIN_PLAYERS && players <= MAX_PLAYERS) { p.game.players = players; } else if (strict) { throw RESULT_ERR_INVALID_FILE; } } if (image.IsType( L"cartridge" )) { if (const Xml::Attribute attribute=image.GetAttribute( L"system" )) { if (attribute.IsValue( L"famicom" )) { p.system.type = Profile::System::FAMICOM; } else if (attribute.IsValue( L"nes-ntsc" )) { p.system.type = Profile::System::NES_NTSC; } else if (attribute.IsValue( L"nes-pal" )) { p.system.type = Profile::System::NES_PAL; p.system.cpu = Profile::System::CPU_RP2A07; p.system.ppu = Profile::System::PPU_RP2C07; } else if (attribute.IsValue( L"nes-pal-a" )) { p.system.type = Profile::System::NES_PAL_A; p.system.cpu = Profile::System::CPU_RP2A07; p.system.ppu = Profile::System::PPU_RP2C07; } else if (attribute.IsValue( L"nes-pal-b" )) { p.system.type = Profile::System::NES_PAL_B; p.system.cpu = Profile::System::CPU_RP2A07; p.system.ppu = Profile::System::PPU_RP2C07; } else if (attribute.IsValue( L"dendy" )) { p.system.type = Profile::System::DENDY; p.system.cpu = Profile::System::CPU_DENDY; p.system.ppu = Profile::System::PPU_DENDY; } else if (!strict) { if (favoredSystem == FAVORED_NES_PAL) { p.system.type = Profile::System::NES_PAL; p.system.cpu = Profile::System::CPU_RP2A07; p.system.ppu = Profile::System::PPU_RP2C07; } else if (favoredSystem == FAVORED_FAMICOM) { p.system.type = Profile::System::FAMICOM; } else if (favoredSystem == FAVORED_DENDY) { p.system.type = Profile::System::DENDY; p.system.cpu = Profile::System::CPU_DENDY; p.system.ppu = Profile::System::PPU_DENDY; } else { p.system.type = Profile::System::NES_NTSC; } } else { throw RESULT_ERR_INVALID_FILE; } } else if (strict) { throw RESULT_ERR_INVALID_FILE; } } else if (image.IsType( L"arcade" )) { p.system.ppu = Profile::System::PPU_RP2C03B; if (const Xml::Attribute attribute=image.GetAttribute( L"system" )) { if (attribute.IsValue( L"vs-unisystem" )) { p.system.type = Profile::System::VS_UNISYSTEM; } else if (attribute.IsValue( L"vs-dualsystem" )) { p.system.type = Profile::System::VS_DUALSYSTEM; } else if (attribute.IsValue( L"playchoice-10" )) { p.system.type = Profile::System::PLAYCHOICE_10; } else { throw RESULT_ERR_INVALID_FILE; } } else { throw RESULT_ERR_INVALID_FILE; } } else { throw RESULT_ERR_INVALID_FILE; } p.dump.by = image.GetAttribute( L"dumper" ).GetValue(); p.dump.date = image.GetAttribute( L"datedumped" ).GetValue(); p.dump.state = Profile::Dump::OK; if (const Xml::Attribute attribute=image.GetAttribute( L"dump" )) { if (attribute.IsValue( L"bad" )) { p.dump.state = Profile::Dump::BAD; } else if (attribute.IsValue( L"unknown" )) { p.dump.state = Profile::Dump::UNKNOWN; } else if (strict && !attribute.IsValue( L"ok" )) { throw RESULT_ERR_INVALID_FILE; } } if (Xml::Node node=image.GetChild( L"properties" )) { for (node=node.GetFirstChild(); node.IsType( L"property" ); node=node.GetNextSibling()) { Profile::Property property; property.name = node.GetAttribute( L"name" ).GetValue(); property.value = node.GetAttribute( L"value" ).GetValue(); p.properties.push_back( property ); } } if (p.system.type == Profile::System::VS_UNISYSTEM || p.system.type == Profile::System::VS_DUALSYSTEM) { if (const Xml::Attribute attribute=image.GetAttribute( L"ppu" )) { if (attribute.IsValue( L"rp2c03b" )) p.system.ppu = Profile::System::PPU_RP2C03B; else if (attribute.IsValue( L"rp2c03g" )) p.system.ppu = Profile::System::PPU_RP2C03G; else if (attribute.IsValue( L"rp2c04-0001" )) p.system.ppu = Profile::System::PPU_RP2C04_0001; else if (attribute.IsValue( L"rp2c04-0002" )) p.system.ppu = Profile::System::PPU_RP2C04_0002; else if (attribute.IsValue( L"rp2c04-0003" )) p.system.ppu = Profile::System::PPU_RP2C04_0003; else if (attribute.IsValue( L"rp2c04-0004" )) p.system.ppu = Profile::System::PPU_RP2C04_0004; else if (attribute.IsValue( L"rc2c03b" )) p.system.ppu = Profile::System::PPU_RC2C03B; else if (attribute.IsValue( L"rc2c03c" )) p.system.ppu = Profile::System::PPU_RC2C03C; else if (attribute.IsValue( L"rc2c05-01" )) p.system.ppu = Profile::System::PPU_RC2C05_01; else if (attribute.IsValue( L"rc2c05-02" )) p.system.ppu = Profile::System::PPU_RC2C05_02; else if (attribute.IsValue( L"rc2c05-03" )) p.system.ppu = Profile::System::PPU_RC2C05_03; else if (attribute.IsValue( L"rc2c05-04" )) p.system.ppu = Profile::System::PPU_RC2C05_04; else if (attribute.IsValue( L"rc2c05-05" )) p.system.ppu = Profile::System::PPU_RC2C05_05; } } p.game.revision = image.GetAttribute( L"revision" ).GetValue(); p.hash.Assign ( image.GetAttribute( L"sha1" ).GetValue(), image.GetAttribute( L"crc" ).GetValue() ); if (const Xml::Node board=image.GetChild( L"board" )) { p.board.type = board.GetAttribute( L"type" ).GetValue(); p.board.pcb = board.GetAttribute( L"pcb" ).GetValue(); p.board.cic = board.GetChild( L"cic" ).GetAttribute( L"type" ).GetValue(); if (const Xml::Attribute attribute=board.GetAttribute( L"mapper" )) { const ulong mapper = attribute.GetUnsignedValue(); if (mapper <= MAX_MAPPER) { p.board.mapper = mapper; } else if (strict) { throw RESULT_ERR_INVALID_FILE; } } if (const Xml::Node pad=board.GetChild( L"pad" )) { p.board.solderPads = ( (pad.GetAttribute( L"h" ).IsValue( L"1" ) ? Profile::Board::SOLDERPAD_H : 0U) | (pad.GetAttribute( L"v" ).IsValue( L"1" ) ? Profile::Board::SOLDERPAD_V : 0U) ); } for (Xml::Node node=board.GetFirstChild(); node; node=node.GetNextSibling()) { dword size = 0; if (const Xml::Attribute attribute=node.GetAttribute( L"size" )) { wcstring end; const ulong value = attribute.GetUnsignedValue( end, 10 ); if (end[0] == L'\0') { size = value; } else if ((end[0] == L'k' || end[0] == L'K') && end[1] == L'\0' && value <= MAX_CHIP_SIZE/SIZE_1K) { size = value * SIZE_1K; } } Profile::Board::Pins pins; Profile::Board::Samples samples; for (Xml::Node child(node.GetFirstChild()); child; child=child.GetNextSibling()) { if (child.IsType(L"pin")) { const ulong number = child.GetAttribute(L"number").GetUnsignedValue(); wcstring const function = child.GetAttribute(L"function").GetValue(); if (number >= MIN_IC_PINS && number <= MAX_IC_PINS && *function) { Profile::Board::Pin pin; pin.number = number; pin.function = function; pins.push_back( pin ); } } else if (child.IsType(L"sample")) { const ulong id = child.GetAttribute(L"id").GetUnsignedValue(); wcstring const file = child.GetAttribute(L"file").GetValue(); if (id <= MAX_CHIP_SAMPLES && *file) { Profile::Board::Sample sample; sample.id = id; sample.file = file; samples.push_back( sample ); } } } bool first; if (true == (first=node.IsType( L"prg" )) || node.IsType( L"chr" )) { if (size < MIN_CHIP_SIZE || size > MAX_CHIP_SIZE) throw RESULT_ERR_INVALID_FILE; Profile::Board::Roms& roms = (first ? p.board.prg : p.board.chr); Profile::Board::Rom rom; rom.id = node.GetAttribute( L"id" ).GetUnsignedValue(); rom.size = size; rom.name = node.GetAttribute( L"name" ).GetValue(); rom.pins = pins; rom.file = node.GetAttribute( L"file" ).GetValue(); rom.package = node.GetAttribute( L"package" ).GetValue(); rom.hash.Assign( node.GetAttribute( L"sha1" ).GetValue(), node.GetAttribute( L"crc" ).GetValue() ); for (Profile::Board::Roms::iterator it(roms.begin()), end(roms.end()); ; ++it) { if (it == end || it->id > rom.id) { roms.insert( it, rom ); break; } } } else if (true == (first=node.IsType( L"wram" )) || node.IsType( L"vram" )) { if (size < MIN_CHIP_SIZE || size > MAX_CHIP_SIZE) throw RESULT_ERR_INVALID_FILE; Profile::Board::Rams& rams = (first ? p.board.wram : p.board.vram); Profile::Board::Ram ram; ram.id = node.GetAttribute( L"id" ).GetUnsignedValue(); ram.size = size; ram.file = node.GetAttribute( L"file" ).GetValue(); ram.pins = pins; ram.package = node.GetAttribute( L"package" ).GetValue(); ram.battery = node.GetAttribute( L"battery" ).IsValue( L"1" ); for (Profile::Board::Rams::iterator it(rams.begin()), end(rams.end()); ; ++it) { if (it == end || it->id > ram.id) { rams.insert( it, ram ); break; } } } else if (node.IsType( L"chip" )) { Profile::Board::Chip chip; chip.type = node.GetAttribute( L"type" ).GetValue(); chip.file = node.GetAttribute( L"file" ).GetValue(); chip.pins = pins; chip.samples = samples; chip.battery = node.GetAttribute( L"battery" ).IsValue( L"1" ); chip.package = node.GetAttribute( L"package" ).GetValue(); p.board.chips.push_back( chip ); } } } if (Xml::Node device=game.GetChild( L"peripherals" )) { for (device=device.GetFirstChild(); device.IsType( L"device" ); device=device.GetNextSibling()) { if (const Xml::Attribute attribute = device.GetAttribute( L"type" )) { if (attribute.IsValue( L"arkanoid" )) { if (p.system.type == Profile::System::FAMICOM) p.game.controllers[4] = Api::Input::PADDLE; else p.game.controllers[1] = Api::Input::PADDLE; } else if (attribute.IsValue( L"bandaihypershot" )) { p.game.controllers[4] = Api::Input::BANDAIHYPERSHOT; } else if (attribute.IsValue( L"barcodeworld" )) { p.game.controllers[4] = Api::Input::BARCODEWORLD; } else if (attribute.IsValue( L"crazyclimber" )) { p.game.controllers[4] = Api::Input::CRAZYCLIMBER; } else if (attribute.IsValue( L"doremikko" )) { p.game.controllers[4] = Api::Input::DOREMIKKOKEYBOARD; } else if (attribute.IsValue( L"excitingboxing" )) { p.game.controllers[4] = Api::Input::EXCITINGBOXING; } else if (attribute.IsValue( L"familykeyboard" )) { p.game.controllers[4] = Api::Input::FAMILYKEYBOARD; } else if (attribute.IsValue( L"familytrainer" )) { p.game.controllers[1] = Api::Input::UNCONNECTED; p.game.controllers[4] = Api::Input::FAMILYTRAINER; } else if (attribute.IsValue( L"fourplayer" )) { if (p.system.type == Profile::System::FAMICOM) p.game.adapter = Api::Input::ADAPTER_FAMICOM; else p.game.adapter = Api::Input::ADAPTER_NES; p.game.controllers[2] = Api::Input::PAD3; p.game.controllers[3] = Api::Input::PAD4; } else if (attribute.IsValue( L"horitrack" )) { p.game.controllers[4] = Api::Input::HORITRACK; } else if (attribute.IsValue( L"konamihypershot" )) { p.game.controllers[0] = Api::Input::UNCONNECTED; p.game.controllers[1] = Api::Input::UNCONNECTED; p.game.controllers[4] = Api::Input::KONAMIHYPERSHOT; } else if (attribute.IsValue( L"mahjong" )) { p.game.controllers[0] = Api::Input::UNCONNECTED; p.game.controllers[1] = Api::Input::UNCONNECTED; p.game.controllers[4] = Api::Input::MAHJONG; } else if (attribute.IsValue( L"oekakidstablet" )) { p.game.controllers[0] = Api::Input::UNCONNECTED; p.game.controllers[1] = Api::Input::UNCONNECTED; p.game.controllers[4] = Api::Input::OEKAKIDSTABLET; } else if (attribute.IsValue( L"pachinko" )) { p.game.controllers[4] = Api::Input::PACHINKO; } else if (attribute.IsValue( L"partytap" )) { p.game.controllers[1] = Api::Input::UNCONNECTED; p.game.controllers[4] = Api::Input::PARTYTAP; } else if (attribute.IsValue( L"pokkunmoguraa" )) { p.game.controllers[1] = Api::Input::UNCONNECTED; p.game.controllers[4] = Api::Input::POKKUNMOGURAA; } else if (attribute.IsValue( L"powerglove" )) { p.game.controllers[0] = Api::Input::POWERGLOVE; } else if (attribute.IsValue( L"powerpad" ) || attribute.IsValue( L"familyfunfitness" )) { if (p.system.type == Profile::System::FAMICOM) { p.game.controllers[1] = Api::Input::UNCONNECTED; p.game.controllers[4] = Api::Input::FAMILYTRAINER; } else { p.game.controllers[1] = Api::Input::POWERPAD; } } else if (attribute.IsValue( L"rob" )) { p.game.controllers[1] = Api::Input::ROB; } else if (attribute.IsValue( L"suborkeyboard" )) { p.game.controllers[4] = Api::Input::SUBORKEYBOARD; } else if (attribute.IsValue( L"subormouse" )) { p.game.controllers[1] = Api::Input::MOUSE; } else if (attribute.IsValue( L"standard" )) { p.game.controllers[0] = Api::Input::PAD1; p.game.controllers[1] = Api::Input::PAD2; } else if (attribute.IsValue( L"topriderbike" )) { p.game.controllers[0] = Api::Input::UNCONNECTED; p.game.controllers[1] = Api::Input::UNCONNECTED; p.game.controllers[4] = Api::Input::TOPRIDER; } else if (attribute.IsValue( L"turbofile" )) { p.game.controllers[4] = Api::Input::TURBOFILE; } else if (attribute.IsValue( L"zapper" )) { if (p.system.type == Profile::System::VS_UNISYSTEM || p.system.type == Profile::System::VS_DUALSYSTEM) { p.game.controllers[0] = Api::Input::ZAPPER; p.game.controllers[1] = Api::Input::UNCONNECTED; } else { p.game.controllers[1] = Api::Input::ZAPPER; } } } } } profiles.push_back( p ); } } } void ChooseProfile() { if (profiles.empty()) throw RESULT_ERR_INVALID_FILE; Profiles::const_iterator bestMatch( profiles.begin() ); if (profiles.size() > 1) { for (Profiles::const_iterator it(profiles.begin()), end(profiles.end()); it != end; ++it) { if (it->system.type == Profile::System::NES_NTSC) { if (favoredSystem == FAVORED_NES_NTSC) { bestMatch = it; break; } } else if ( it->system.type == Profile::System::NES_PAL || it->system.type == Profile::System::NES_PAL_A || it->system.type == Profile::System::NES_PAL_B ) { if (favoredSystem == FAVORED_NES_PAL) { bestMatch = it; break; } } else if (it->system.type == Profile::System::FAMICOM) { if (favoredSystem == FAVORED_FAMICOM) { bestMatch = it; break; } } else if (it->system.type == Profile::System::DENDY) { if (favoredSystem == FAVORED_DENDY) { bestMatch = it; break; } } } if (askProfile && Api::Cartridge::chooseProfileCallback) { std::vector names( profiles.size() ); std::vector::iterator dst( names.begin() ); for (Profiles::const_iterator src(profiles.begin()), end(profiles.end()); src != end; ++src, ++dst) { *dst = src->game.title; if (!src->game.revision.empty()) { *dst += dst->empty() ? L"(Rev. " : L" (Rev. "; *dst += src->game.revision; *dst += L')'; } if (!src->game.region.empty()) { *dst += dst->empty() ? L"(" : L" ("; *dst += src->game.region; *dst += L')'; } if (!dst->empty()) *dst += L' '; *dst += ( src->system.type == Profile::System::NES_PAL ? L"(NES-PAL)" : src->system.type == Profile::System::NES_PAL_A ? L"(NES-PAL-A)" : src->system.type == Profile::System::NES_PAL_B ? L"(NES-PAL-B)" : src->system.type == Profile::System::FAMICOM ? L"(Famicom)" : src->system.type == Profile::System::DENDY ? L"(Dendy)" : src->system.type == Profile::System::VS_UNISYSTEM ? L"(VS)" : src->system.type == Profile::System::VS_DUALSYSTEM ? L"(VS)" : src->system.type == Profile::System::PLAYCHOICE_10 ? L"(PC10)" : L"(NES-NTSC)" ); } const uint selected = Api::Cartridge::chooseProfileCallback( &profiles.front(), &names.front(), profiles.size() ); if (selected < profiles.size()) bestMatch = profiles.begin() + selected; } } profile = *bestMatch; if (profiles.size() > 1) { uint regions = 0x0; for (Profiles::const_iterator it(profiles.begin()), end(profiles.end()); it != end; ++it) { if (profile.hash == it->hash) { switch (it->system.type) { case Profile::System::NES_PAL: case Profile::System::NES_PAL_A: case Profile::System::NES_PAL_B: case Profile::System::DENDY: regions |= 0x1; break; default: regions |= 0x2; break; } } if (regions == 0x3) { profile.multiRegion = true; break; } } } } void LoadRoms() { class Loader : public Api::User::File { wcstring const filename; byte* const rom; const dword size; bool loaded; Action GetAction() const throw() { return LOAD_ROM; } wcstring GetName() const throw() { return filename; } ulong GetMaxSize() const throw() { return size; } Result SetContent(const void* filedata,ulong filesize) throw() { if (filesize) { if (filedata) { std::memcpy( rom, filedata, NST_MIN(size,filesize) ); loaded = true; } else { return RESULT_ERR_INVALID_PARAM; } } return RESULT_OK; } Result SetContent(std::istream& stdStream) throw() { try { Nes::Core::Stream::In stream( &stdStream ); if (const ulong length = stream.Length()) { stream.Read( rom, NST_MIN(size,length) ); loaded = true; } } catch (Result result) { return result; } catch (const std::bad_alloc&) { return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { return RESULT_ERR_GENERIC; } return RESULT_OK; } public: Loader(wcstring f,byte* r,dword s) : filename(f), rom(r), size(s), loaded(false) {} bool Loaded() const { return loaded; } }; for (uint i=0; i < 2; ++i) { Profile::Board::Roms& roms = (i ? profile.board.chr : profile.board.prg); if (roms.empty()) continue; Ram& rom = (i ? chr : prg); dword size = 0; for (Profile::Board::Roms::iterator it(roms.begin()), end(roms.end()); it != end; ++it) { size += it->size; if (it->size < MIN_CHIP_SIZE || size > MAX_CHIP_SIZE) throw RESULT_ERR_INVALID_FILE; } rom.Set( size ); for (Profile::Board::Pins::const_iterator pin(roms.begin()->pins.begin()), end(roms.begin()->pins.end()); pin != end; ++pin) rom.Pin(pin->number) = pin->function.c_str(); if (readOnly) continue; if (!Api::User::fileIoCallback) throw RESULT_ERR_NOT_READY; size = 0; for (Profile::Board::Roms::iterator it(roms.begin()), end(roms.end()); it != end; ++it) { if (it->file.empty()) throw RESULT_ERR_INVALID_FILE; Loader loader( it->file.c_str(), rom.Mem(size), it->size ); Api::User::fileIoCallback( loader ); if (!loader.Loaded()) throw RESULT_ERR_INVALID_FILE; size += it->size; } } } void PatchRoms() { if (patchStream) { Patcher patcher( patchBypassChecksum ); *patchResult = patcher.Load( *patchStream ); if (NES_SUCCEEDED(*patchResult)) { const Patcher::Block blocks[] = { { prg.Mem(), prg.Size() }, { chr.Mem(), chr.Size() } }; *patchResult = patcher.Test( blocks ); if (NES_SUCCEEDED(*patchResult)) { if (patcher.Patch( prg.Mem(), prg.Mem(), prg.Size(), 16 )) { profile.patched = true; Log::Flush( "Romset: PRG-ROM was patched" NST_LINEBREAK ); } if (patcher.Patch( chr.Mem(), chr.Mem(), chr.Size(), 16 + prg.Size() )) { profile.patched = true; Log::Flush( "Romset: CHR-ROM was patched" NST_LINEBREAK ); } } } } } }; void Cartridge::Romset::Load ( std::istream& stdStreamImage, std::istream* const stdStreamPatch, const bool patchBypassChecksum, Result* const patchResult, Ram& prg, Ram& chr, const FavoredSystem favoredSystem, const bool askProfile, Profile& profile, const bool readOnly ) { Loader loader ( stdStreamImage, stdStreamPatch, patchBypassChecksum, patchResult, prg, chr, favoredSystem, askProfile, profile, readOnly ); loader.Load(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } nestopia-1.51.1/source/core/NstCartridgeRomset.hpp000066400000000000000000000026731411157722000221550ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_CARTRIDGE_ROMSET_H #define NST_CARTRIDGE_ROMSET_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class Cartridge::Romset { class Loader; public: static void Load ( std::istream&, std::istream*, bool, Result*, Ram&, Ram&, FavoredSystem, bool, Profile&, bool=false ); }; } } #endif nestopia-1.51.1/source/core/NstCartridgeUnif.cpp000066400000000000000000000451671411157722000216050ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstLog.hpp" #include "NstPatcher.hpp" #include "NstStream.hpp" #include "NstChecksum.hpp" #include "NstImageDatabase.hpp" #include "NstCartridge.hpp" #include "NstCartridgeUnif.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif class Cartridge::Unif::Loader { class Context { public: bool operator () (uint,dword); enum System { SYSTEM_NTSC, SYSTEM_PAL, SYSTEM_BOTH }; struct Rom { Rom(); Ram data; dword truncated; char crc[12]; }; System system; Rom roms[2][16]; private: byte chunks[80]; public: Context() : system(SYSTEM_NTSC) { std::memset( chunks, 0, sizeof(chunks) ); } }; enum { HEADER_RESERVED_LENGTH = 24, MAX_ROM_SIZE = SIZE_16K * 0x1000UL, DUMPER_NAME_LENGTH = 100, DUMPER_AGENT_LENGTH = 100, DUMPER_LENGTH = DUMPER_NAME_LENGTH + 4 + DUMPER_AGENT_LENGTH }; dword ReadString(cstring,Vector*); static cstring ChunkName (char (&)[5],dword); Stream::In stream; const FavoredSystem favoredSystem; Profile& profile; ProfileEx& profileEx; Ram& prg; Ram& chr; Patcher patcher; Result* const patchResult; const ImageDatabase* const database; public: Loader ( std::istream& stdStreamImage, std::istream* const stdStreamPatch, const bool patchBypassChecksum, Result* const e, Ram& p, Ram& c, const FavoredSystem f, Profile& r, ProfileEx& x, const ImageDatabase* const d ) : stream (&stdStreamImage), favoredSystem (f), profile (r), profileEx (x), prg (p), chr (c), patcher (patchBypassChecksum), patchResult (e), database (d) { NST_ASSERT( prg.Empty() && chr.Empty() ); profile = Profile(); profileEx = ProfileEx(); if (stdStreamPatch) *patchResult = patcher.Load( *stdStreamPatch ); } void Load() { ReadHeader(); ReadChunks(); if (database && database->Enabled()) { Checksum checksum; checksum.Compute( prg.Mem(), prg.Size() ); checksum.Compute( chr.Mem(), chr.Size() ); if (const ImageDatabase::Entry entry = database->Search( Profile::Hash(checksum.GetSha1(),checksum.GetCrc()), favoredSystem )) entry.Fill( profile, patcher.Empty() ); } if (!patcher.Empty()) { const Patcher::Block blocks[] = { { prg.Mem(), prg.Size() }, { chr.Mem(), chr.Size() } }; *patchResult = patcher.Test( blocks ); if (NES_SUCCEEDED(*patchResult)) { if (patcher.Patch( prg.Mem(), prg.Mem(), prg.Size(), 16 )) { profile.patched = true; Log::Flush( "Unif: PRG-ROM was patched" NST_LINEBREAK ); } if (patcher.Patch( chr.Mem(), chr.Mem(), chr.Size(), 16 + prg.Size() )) { profile.patched = true; Log::Flush( "Unif: CHR-ROM was patched" NST_LINEBREAK ); } } } } private: void ReadHeader() { if (stream.Read32() != AsciiId<'U','N','I','F'>::V) throw RESULT_ERR_INVALID_FILE; dword version = stream.Read32(); Log() << "Unif: revision " << version << NST_LINEBREAK; byte reserved[HEADER_RESERVED_LENGTH]; stream.Read( reserved ); for (uint i=0; i < HEADER_RESERVED_LENGTH; ++i) { NST_VERIFY( !reserved[i] ); if (reserved[i]) { Log() << "Unif: warning, unknown header data" NST_LINEBREAK; break; } } } void ReadChunks() { Context context; while (!stream.Eof()) { dword id = stream.Read32(); const dword length = stream.Read32(); NST_VERIFY( length <= SIZE_1K * 4096UL ); switch (id) { case AsciiId<'N','A','M','E'>::V: id = (context( 0, id ) ? ReadName ( ) : 0); break; case AsciiId<'R','E','A','D'>::V: id = (context( 1, id ) ? ReadComment ( ) : 0); break; case AsciiId<'D','I','N','F'>::V: id = (context( 2, id ) ? ReadDumper ( ) : 0); break; case AsciiId<'T','V','C','I'>::V: id = (context( 3, id ) ? ReadSystem ( context ) : 0); break; case AsciiId<'B','A','T','R'>::V: id = (context( 4, id ) ? ReadBattery ( ) : 0); break; case AsciiId<'M','A','P','R'>::V: id = (context( 5, id ) ? ReadBoard ( ) : 0); break; case AsciiId<'M','I','R','R'>::V: id = (context( 6, id ) ? ReadMirroring ( ) : 0); break; case AsciiId<'C','T','R','L'>::V: id = (context( 7, id ) ? ReadController ( ) : 0); break; case AsciiId<'V','R','O','R'>::V: id = (context( 8, id ) ? ReadChrRam ( ) : 0); break; default: switch (id & 0x00FFFFFF) { case AsciiId<'P','C','K'>::V: case AsciiId<'C','C','K'>::V: case AsciiId<'P','R','G'>::V: case AsciiId<'C','H','R'>::V: { uint index = id >> 24 & 0xFF; if (index >= Ascii<'0'>::V && index <= Ascii<'9'>::V) { index -= Ascii<'0'>::V; } else if (index >= Ascii<'A'>::V && index <= Ascii<'F'>::V) { index = index - Ascii<'A'>::V + 10; } else { index = ~0U; } if (index < 16) { switch (dword part = (id & 0x00FFFFFF)) { case AsciiId<'P','C','K'>::V: case AsciiId<'C','C','K'>::V: part = (part == AsciiId<'C','C','K'>::V); id = (context( 9 + (part << 4) + index, id) ? ReadChecksum( part, index, context.roms[part][index] ) : 0); break; case AsciiId<'P','R','G'>::V: case AsciiId<'C','H','R'>::V: part = (part == AsciiId<'C','H','R'>::V); id = (context( 9 + 32 + (part << 4) + index, id ) ? ReadRom( part, index, length, context.roms[part] ) : 0); break; } break; } } default: id = ReadUnknown( id ); break; } } if (id < length) { for (id = length - id; id > 0x7FFFFFFF; id -= 0x7FFFFFFF) stream.Seek( 0x7FFFFFFF ); if (id) stream.Seek( id ); } else if (id > length) { throw RESULT_ERR_CORRUPT_FILE; } } for (uint i=0; i < 2; ++i) { uint count = 0; dword size = 0; for (uint j=0; j < 16; ++j) { if (const dword n=context.roms[i][j].data.Size()) { count++; size += n; } } if (count) { Profile::Board::Roms& rom = (i ? profile.board.chr : profile.board.prg); rom.resize( count ); Ram& dst = (i ? chr : prg); dst.Set( size ); if (!rom.empty()) { for (Profile::Board::Pins::const_iterator it(rom.front().pins.begin()), end(rom.front().pins.end()); it != end; ++it) dst.Pin(it->number) = it->function.c_str(); } size = 0; for (uint j=0, k=0; j < 16; ++j) { const Context::Rom& src = context.roms[i][j]; if (src.data.Size()) { rom[k].id = k; rom[k].size = src.data.Size(); rom[k].hash.Assign( NULL, src.crc ); k++; std::memcpy( dst.Mem(size), src.data.Mem(), src.data.Size() ); size += src.data.Size(); } } } } if (profileEx.nmt == ProfileEx::NMT_HORIZONTAL) { profile.board.solderPads = Profile::Board::SOLDERPAD_V; } else if (profileEx.nmt == ProfileEx::NMT_VERTICAL) { profile.board.solderPads = Profile::Board::SOLDERPAD_H; } switch (context.system) { case Context::SYSTEM_NTSC: if (favoredSystem == FAVORED_FAMICOM) { profile.system.type = Profile::System::FAMICOM; } if (favoredSystem == FAVORED_DENDY) { profile.system.type = Profile::System::DENDY; profile.system.cpu = Profile::System::CPU_DENDY; profile.system.ppu = Profile::System::PPU_DENDY; } else { profile.system.type = Profile::System::NES_NTSC; } break; default: profile.multiRegion = true; if (favoredSystem == FAVORED_FAMICOM) { profile.system.type = Profile::System::FAMICOM; break; } else if (favoredSystem != FAVORED_NES_PAL && favoredSystem != FAVORED_DENDY) { profile.system.type = Profile::System::NES_NTSC; break; } case Context::SYSTEM_PAL: if (favoredSystem == FAVORED_DENDY) { profile.system.type = Profile::System::DENDY; profile.system.cpu = Profile::System::CPU_DENDY; profile.system.ppu = Profile::System::PPU_DENDY; } else { profile.system.type = Profile::System::NES_PAL; profile.system.cpu = Profile::System::CPU_RP2A07; profile.system.ppu = Profile::System::PPU_RP2C07; } break; } } dword ReadName() { Vector buffer; const dword length = ReadString( "Unif: name: ", &buffer ); if (length && *buffer.Begin()) profile.game.title.assign( buffer.Begin(), buffer.End() ); return length; } dword ReadComment() { return ReadString( "Unif: comment: ", NULL ); } dword ReadDumper() { struct { char name[DUMPER_NAME_LENGTH]; byte day; byte month; word year; char agent[DUMPER_AGENT_LENGTH]; } dumper; stream.Read( dumper.name, DUMPER_NAME_LENGTH ); dumper.name[DUMPER_NAME_LENGTH-1] = '\0'; dumper.day = stream.Read8(); dumper.month = stream.Read8(); dumper.year = stream.Read16(); stream.Read( dumper.agent, DUMPER_AGENT_LENGTH ); dumper.agent[DUMPER_AGENT_LENGTH-1] = '\0'; Log log; if (*dumper.name) log << "Unif: dumped by: " << dumper.name << NST_LINEBREAK; log << "Unif: dump year: " << dumper.year << NST_LINEBREAK "Unif: dump month: " << dumper.month << NST_LINEBREAK "Unif: dump day: " << dumper.day << NST_LINEBREAK; if (*dumper.agent) log << "Unif: dumper agent: " << dumper.agent << NST_LINEBREAK; return DUMPER_LENGTH; } dword ReadSystem(Context& context) { switch (stream.Read8()) { case 0: context.system = Context::SYSTEM_NTSC; Log::Flush( "Unif: NTSC system" NST_LINEBREAK ); break; case 1: context.system = Context::SYSTEM_PAL; Log::Flush( "Unif: PAL system" NST_LINEBREAK ); break; default: context.system = Context::SYSTEM_BOTH; Log::Flush( "Unif: dual system" NST_LINEBREAK ); break; } return 1; } dword ReadBattery() { profileEx.battery = true; Log::Flush( "Unif: battery present" NST_LINEBREAK ); return 0; } dword ReadBoard() { Vector buffer; const dword length = ReadString( "Unif: board: ", &buffer ); if (length && *buffer.Begin()) profile.board.type.assign( buffer.Begin(), buffer.End() ); return length; } dword ReadMirroring() { switch (stream.Read8()) { case 0: profileEx.nmt = ProfileEx::NMT_HORIZONTAL; Log::Flush( "Unif: horizontal mirroring" NST_LINEBREAK ); break; case 1: profileEx.nmt = ProfileEx::NMT_VERTICAL; Log::Flush( "Unif: vertical mirroring" NST_LINEBREAK ); break; case 2: case 3: profileEx.nmt = ProfileEx::NMT_SINGLESCREEN; Log::Flush( "Unif: single-screen mirroring" NST_LINEBREAK ); break; case 4: profileEx.nmt = ProfileEx::NMT_FOURSCREEN; Log::Flush( "Unif: four-screen mirroring" NST_LINEBREAK ); break; case 5: profileEx.nmt = ProfileEx::NMT_CONTROLLED; Log::Flush( "Unif: mapper controlled mirroring" NST_LINEBREAK ); break; } return 1; } dword ReadChecksum(const uint type,const uint index,Context::Rom& rom) { NST_ASSERT( type < 2 && index < 16 ); for (dword crc=stream.Read32(), i=0; i < 8; ++i) { uint c = crc >> (i*4) & 0xF; rom.crc[i] = (c < 0xA ? '0' + c : 'A' + (c - 0xA) ); } Log() << "Unif: " << (type ? "CHR-ROM " : "PRG-ROM ") << char(index < 10 ? index + '0' : index-10 + 'A') << " CRC: " << rom.crc << NST_LINEBREAK; return 4; } dword ReadRom(const uint type,const uint index,dword length,Context::Rom* const roms) { NST_ASSERT( type < 2 && index < 16 ); Log() << "Unif: " << (type ? "CHR-ROM " : "PRG-ROM ") << char(index < 10 ? index + '0' : index-10 + 'A') << " size: " << (length / SIZE_1K) << "k" NST_LINEBREAK; dword available = 0; for (uint i=0; i < 16; ++i) available += roms[i].data.Size(); available = MAX_ROM_SIZE - available; NST_VERIFY( length <= available ); if (length > available) { roms[index].truncated = length - available; length = available; Log() << "Unif: warning, " << (type ? "CHR-ROM " : "PRG-ROM ") << char(index < 10 ? index + '0' : index-10 + 'A') << " truncated to: " << (length / SIZE_1K) << "k" NST_LINEBREAK; } if (length) { roms[index].data.Set( length ); stream.Read( roms[index].data.Mem(), length ); } return length; } dword ReadController() { Log log; log << "Unif: controllers: "; const uint controller = stream.Read8(); NST_VERIFY( !(controller & (0x40|0x80)) ); if (controller & (0x1|0x2|0x4|0x8|0x10|0x20)) { if (controller & 0x01) { profile.game.controllers[0] = Api::Input::PAD1; profile.game.controllers[1] = Api::Input::PAD2; log << "standard joypad"; } if (controller & 0x02) { profile.game.controllers[1] = Api::Input::ZAPPER; cstring const zapper = ", zapper"; log << (zapper + ((controller & 0x1) ? 0 : 2)); } if (controller & 0x04) { profile.game.controllers[1] = Api::Input::ROB; cstring const rob = ", R.O.B."; log << (rob + ((controller & (0x1|0x2)) ? 0 : 2)); } if (controller & 0x08) { profile.game.controllers[0] = Api::Input::PADDLE; cstring const paddle = ", paddle"; log << (paddle + ((controller & (0x1|0x2|0x4)) ? 0 : 2)); } if (controller & 0x10) { profile.game.controllers[1] = Api::Input::POWERPAD; cstring const powerpad = ", power pad"; log << (powerpad + ((controller & (0x1|0x2|0x4|0x8)) ? 0 : 2)); } if (controller & 0x20) { profile.game.controllers[2] = Api::Input::PAD3; profile.game.controllers[3] = Api::Input::PAD4; cstring const fourplayer = ", four player adapter"; log << (fourplayer + ((controller & (0x1|0x2|0x4|0x8|0x10)) ? 0 : 2)); } log << NST_LINEBREAK; } else { log << ((controller & (0x40|0x80)) ? "unknown" NST_LINEBREAK : "unspecified" NST_LINEBREAK); } return 1; } static dword ReadChrRam() { Log::Flush( "Unif: CHR is writable" NST_LINEBREAK ); return 0; } static dword ReadUnknown(dword id) { NST_DEBUG_MSG("unknown unif chunk"); char name[5]; Log() << "Unif: warning, skipping unknown chunk: \"" << ChunkName(name,id) << "\"" NST_LINEBREAK; return 0; } }; void Cartridge::Unif::Load ( std::istream& stdStreamImage, std::istream* const stdStreamPatch, const bool patchBypassChecksum, Result* const patchResult, Ram& prg, Ram& chr, const FavoredSystem favoredSystem, Profile& profile, ProfileEx& profileEx, const ImageDatabase* const database ) { Loader loader ( stdStreamImage, stdStreamPatch, patchBypassChecksum, patchResult, prg, chr, favoredSystem, profile, profileEx, database ); loader.Load(); } Cartridge::Unif::Loader::Context::Rom::Rom() : truncated(0) { for (uint i=0; i < sizeof(crc); ++i) crc[i] = '\0'; } bool Cartridge::Unif::Loader::Context::operator () (const uint id,const dword chunk) { NST_VERIFY( chunks[id] == 0 ); if (chunks[id] == 0) { chunks[id] = 1; return true; } else { char name[5]; Log() << "Unif: warning, duplicate chunk: \"" << ChunkName(name,chunk) << "\" ignored" NST_LINEBREAK; return false; } } dword Cartridge::Unif::Loader::ReadString(cstring const logtext,Vector* string) { Vector tmp; if (string == NULL) string = &tmp; const dword count = stream.Read( *string ); if (string->Size() > 1) Log() << logtext << string->Begin() << NST_LINEBREAK; return count; } cstring Cartridge::Unif::Loader::ChunkName(char (&name)[5],const dword id) { const byte bytes[] = { id >> 0 & 0xFF, id >> 8 & 0xFF, id >> 16 & 0xFF, id >> 24 & 0xFF, 0 }; Stream::In::AsciiToC( name, bytes, 5 ); return name; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } nestopia-1.51.1/source/core/NstCartridgeUnif.hpp000066400000000000000000000027051411157722000216010ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_CARTRIDGE_UNIF_H #define NST_CARTRIDGE_UNIF_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class Cartridge::Unif { class Loader; public: static void Load ( std::istream&, std::istream*, bool, Result*, Ram&, Ram&, FavoredSystem, Profile&, ProfileEx&, const ImageDatabase* ); }; } } #endif nestopia-1.51.1/source/core/NstCheats.cpp000066400000000000000000000142501411157722000202530ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstCpu.hpp" #include "NstCheats.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Cheats::Cheats(Cpu& c) : cpu(c), frameLocked(false) {} Cheats::~Cheats() { ClearCodes(); } Result Cheats::SetCode ( const word address, const byte data, const byte compare, const bool useCompare, const bool activate ) { if (address < 0x2000) { const LoCode code = {address,data,compare,useCompare}; for (LoCode *it=loCodes.Begin(), *const end=loCodes.End(); ; ++it) { if (it == end || it->address > address) { loCodes.Insert( it, code ); break; } else if (it->address == address) { if (it->data == code.data && it->useCompare == code.useCompare && (!code.useCompare || it->compare == code.compare)) { return RESULT_NOP; } else { *it = code; return RESULT_WARN_DATA_REPLACED; } } } } else { const HiCode code = {address,data,compare,useCompare,NULL}; HiCode* it = hiCodes.Begin(); for (const HiCode* const end=hiCodes.End(); ; ++it) { if (it == end || it->address > address) { it = hiCodes.Insert( it, code ); break; } else if (it->address == address) { if (it->data == code.data && it->useCompare == code.useCompare && (!code.useCompare || it->compare == code.compare)) { return RESULT_NOP; } else { it->data = code.data; it->compare = code.compare; it->useCompare = code.useCompare; return RESULT_WARN_DATA_REPLACED; } } } if (activate) Map( *it ); } return RESULT_OK; } Result Cheats::DeleteCode(dword index) { if (loCodes.Size() > index) { loCodes.Erase( loCodes.Begin() + index ); return RESULT_OK; } else if (hiCodes.Size() > (index -= loCodes.Size())) { HiCode* const it = hiCodes.Begin() + index; cpu.Unlink( it->address, this, &Cheats::Peek_Wizard, &Cheats::Poke_Wizard ); hiCodes.Erase( it ); return RESULT_OK; } else { return RESULT_ERR_INVALID_PARAM; } } void Cheats::Reset() { loCodes.Defrag(); hiCodes.Defrag(); for (HiCode *it=hiCodes.Begin(), *const end=hiCodes.End(); it != end; ++it) Map( *it ); } void Cheats::Map(HiCode& code) { code.port = cpu.Link( code.address, Cpu::LEVEL_HIGH, this, &Cheats::Peek_Wizard, &Cheats::Poke_Wizard ); } void Cheats::ClearCodes() { loCodes.Destroy(); for (const HiCode *it=hiCodes.Begin(), *const end=hiCodes.End(); it != end; ++it) cpu.Unlink( it->address, this, &Cheats::Peek_Wizard, &Cheats::Poke_Wizard ); hiCodes.Destroy(); } Result Cheats::GetCode ( dword index, ushort* const address, uchar* const data, uchar* const compare, bool* const useCompare ) const { if (loCodes.Size() > index) { const LoCode* NST_RESTRICT code = loCodes.Begin() + index; if (address) *address = code->address; if (data) *data = code->data; if (compare) *compare = code->compare; if (useCompare) *useCompare = code->useCompare; } else if (hiCodes.Size() > (index -= loCodes.Size())) { const HiCode* NST_RESTRICT code = hiCodes.Begin() + index; if (address) *address = code->address; if (data) *data = code->data; if (compare) *compare = code->compare; if (useCompare) *useCompare = code->useCompare; } else { return RESULT_ERR_INVALID_PARAM; } return RESULT_OK; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Cheats::BeginFrame(bool frameLock) { frameLocked = frameLock; if (!frameLock) { for (const LoCode* NST_RESTRICT it=loCodes.Begin(), *const end=loCodes.End(); it != end; ++it) { const uint address = it->address & (Cpu::RAM_SIZE-1); if (!it->useCompare || cpu.GetRam()[address] == it->compare) cpu.GetRam()[address] = it->data; } } } inline bool Cheats::HiCode::operator < (const Cheats::HiCode& c) const { return address < c.address; } inline bool Cheats::HiCode::operator < (Address a) const { return address < a; } inline bool operator < (Address a,const Cheats::HiCode& c) { return a < c.address; } NES_PEEK_A(Cheats,Wizard) { NST_ASSERT( address >= 0x2000 ); const HiCode* const NST_RESTRICT code = std::lower_bound( hiCodes.Begin(), hiCodes.End(), address ); if (!frameLocked) { if (code->useCompare) { const uint data = code->port->Peek( address ); if (code->compare != data) return data; } return code->data; } else { return code->port->Peek( address ); } } NES_POKE_AD(Cheats,Wizard) { NST_ASSERT( address >= 0x2000 ); return std::lower_bound( hiCodes.Begin(), hiCodes.End(), address )->port->Poke( address, data ); } } } nestopia-1.51.1/source/core/NstCheats.hpp000066400000000000000000000044001411157722000202540ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_CHEATS_H #define NST_CHEATS_H #ifndef NST_VECTOR_H #include "NstVector.hpp" #endif #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class Cheats { public: explicit Cheats(Cpu&); ~Cheats(); void Reset(); void BeginFrame(bool); void ClearCodes(); Result GetCode (dword,ushort*,uchar*,uchar*,bool*) const; Result SetCode (word,byte,byte,bool,bool); Result DeleteCode (dword); private: NES_DECL_PEEK( Wizard ); NES_DECL_POKE( Wizard ); struct LoCode { word address; byte data; byte compare; ibool useCompare; }; struct HiCode { inline bool operator < (const HiCode&) const; inline bool operator < (Address) const; word address; byte data; byte compare; ibool useCompare; const Io::Port* port; }; inline friend bool operator < (Address,const HiCode&); typedef Vector LoCodes; typedef Vector HiCodes; void Map(HiCode&); Cpu& cpu; ibool frameLocked; LoCodes loCodes; HiCodes hiCodes; public: dword NumCodes() const { return loCodes.Size() + hiCodes.Size(); } }; } } #endif nestopia-1.51.1/source/core/NstChecksum.cpp000066400000000000000000000040741411157722000206110ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstAssert.hpp" #include "NstChecksum.hpp" #include "NstCrc32.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Checksum::Checksum() : crc32(0) {} Checksum::Checksum(const byte* data,dword size) : crc32(0) { Compute( data, size ); } void Checksum::Clear() { crc32 = 0; sha1.Clear(); } void Checksum::Compute(const byte* data,dword size) { crc32 = Crc32::Compute( data, size, crc32 ); Sha1::Compute( sha1, data, size ); } void Checksum::Recompute(const byte* data,dword size) { Clear(); Compute( data, size ); } bool Checksum::operator == (const Checksum& checksum) const { NST_VERIFY( (crc32 == checksum.crc32) == (sha1 == checksum.sha1) ); return crc32 == checksum.crc32 && sha1 == checksum.sha1; } bool Checksum::operator ! () const { NST_VERIFY( !crc32 == !sha1 ); return !crc32 && !sha1; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } nestopia-1.51.1/source/core/NstChecksum.hpp000066400000000000000000000034741411157722000206210ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_CHECKSUM_H #define NST_CHECKSUM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstCore.hpp" #include "NstSha1.hpp" namespace Nes { namespace Core { class Checksum : public ImplicitBool { public: Checksum(); Checksum(const byte*,dword); void Clear(); void Compute(const byte*,dword); void Recompute(const byte*,dword); bool operator == (const Checksum&) const; bool operator ! () const; private: Sha1::Key sha1; dword crc32; public: bool operator != (const Checksum& checksum) const { return !(*this == checksum); } Sha1::Key::Digest GetSha1() const { return sha1.GetDigest(); } dword GetCrc() const { return crc32; } }; } } #endif nestopia-1.51.1/source/core/NstChips.cpp000066400000000000000000000054541411157722000201200ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include "NstAssert.hpp" #include "NstChips.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif struct Chips::Container { struct Less { bool operator () (const std::wstring& a,const std::wstring& b) const { return Core::StringCompare( a.c_str(), b.c_str() ) < 0; } }; typedef std::multimap Map; Map map; }; Chips::Chips(const Chips& chips) : container(chips.container ? new Container(*chips.container) : NULL) {} Chips::~Chips() { Clear(); } Chips& Chips::operator = (const Chips& chips) { if (this != &chips) { Clear(); if (chips.container) container = new Container(*chips.container); } return *this; } Chips::Type& Chips::Add(wcstring type) { if (container == NULL) container = new Container; return container->map.insert( Container::Map::value_type(type,Type()) )->second; } void Chips::Clear() { if (Container* tmp = container) { container = NULL; delete tmp; } } Chips::Type* Chips::Find(wcstring type) { NST_ASSERT( type ); if (container) { Container::Map::iterator it(container->map.find(type)); if (it != container->map.end()) return &it->second; } return NULL; } const Chips::Type* Chips::Find(wcstring type) const { NST_ASSERT( type ); if (container) { Container::Map::const_iterator it(static_cast(container->map).find(type)); if (it != container->map.end()) return &it->second; } return NULL; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } nestopia-1.51.1/source/core/NstChips.hpp000066400000000000000000000045441411157722000201240ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_CHIPS_H #define NST_CHIPS_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstPins.hpp" namespace Nes { namespace Core { class Chips { public: Chips(const Chips&); ~Chips(); Chips& operator = (const Chips&); class Type { friend class Chips; Pins pins; Properties samples; public: Pins::PinsProxy Pin(uint number) { return pins[number]; } Pins::ConstPinsProxy Pin(uint number) const { return pins[number]; } Properties::Proxy Sample(uint number) { return samples[number]; } Properties::ConstProxy Sample(uint number) const { return samples[number]; } bool PinsDefined() const { return pins; } bool HasSamples() const { return samples; } }; Type& Add(wcstring); Type* Find(wcstring); const Type* Find(wcstring) const; void Clear(); private: struct Container; Container* container; public: Chips() : container(NULL) {} bool Has(wcstring type) const { return Find(type); } Type& operator [] (wcstring type) { return *Find(type); } const Type& operator [] (wcstring type) const { return *Find(type); } }; } } #endif nestopia-1.51.1/source/core/NstCore.cpp000066400000000000000000000101461411157722000177340ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstCore.hpp" #if NST_MSVC #if (defined(_DEBUG) && defined(NDEBUG)) || (!defined(_DEBUG) && !defined(NDEBUG)) #pragma message("warning, NDEBUG and _DEBUG macro inconsistency!") #endif #if !defined(_DEBUG) && defined(__MSVC_RUNTIME_CHECKS) #pragma message("performance warning, RTCx compiler options enabled in non-debug mode!") #endif #ifdef _CPPRTTI #pragma message("performance warning, RTTI compiler option needlessly enabled!") #endif #endif #ifndef NST_NATIVE_QWORD #if NST_MSVC || NST_MWERKS >= 0x3000 || NST_BCB >= 0x600 #pragma message("performance warning, no native 64bit integer support!") #elif NST_GCC && !defined(__STRICT_ANSI__) #warning "performance warning, no native 64bit integer support!" #endif #include "NstAssert.hpp" namespace Nes { void qaword::Multiply(qaword multiplier) { qaword multiplicand(*this); lo = 0; hi = 0; while (multiplicand) { if (multiplicand.lo & 0x1) (*this) += multiplier; multiplicand.lo = (multiplicand.lo >> 1) | (multiplicand.hi << 31 & LO_MASK); multiplicand.hi >>= 1; multiplier.hi = (multiplier.hi << 1 & LO_MASK) | (multiplier.lo >> 31); multiplier.lo = (multiplier.lo << 1 & LO_MASK); } } void qaword::Divide(qaword& dividend,const qaword divisor,const bool mod) { NST_ASSERT( bool(divisor) ); qaword remainder(0); qaword quotient(0); if (divisor < dividend) { uint bits = 64; do { remainder.hi = (remainder.hi << 1 & LO_MASK) | (remainder.lo >> 31); remainder.lo = (remainder.lo << 1 & LO_MASK) | (dividend.hi >> 31); dividend.hi = (dividend.hi << 1 & LO_MASK) | (dividend.lo >> 31); dividend.lo = (dividend.lo << 1 & LO_MASK); --bits; } while (remainder < divisor); for (;;) { qaword tmp(remainder); tmp -= divisor; quotient.hi = (quotient.hi << 1 & LO_MASK) | (quotient.lo >> 31); quotient.lo = (quotient.lo << 1 & LO_MASK); if (!(tmp.hi & LO_MSB)) { quotient.lo |= 0x1; remainder = tmp; } if (!bits) break; --bits; remainder.hi = (remainder.hi << 1 & LO_MASK) | (remainder.lo >> 31); remainder.lo = (remainder.lo << 1 & LO_MASK) | (dividend.hi >> 31); dividend.hi = (dividend.hi << 1 & LO_MASK) | (dividend.lo >> 31); dividend.lo = (dividend.lo << 1 & LO_MASK); } } else if (divisor == dividend) { quotient = 1; } else { remainder = dividend; } if (!mod) dividend = quotient; else dividend = remainder; } void qaword::Shl(const uint v) { NST_ASSERT( v < 64 ); if (v) { if (v < 32) { dword t = lo >> (32-v); lo = (lo << v) & LO_MASK; hi = (hi << v | t) & LO_MASK; } else { hi = (lo << (v-32)) & LO_MASK; lo = 0; } } } void qaword::Shr(const uint v) { NST_ASSERT( v < 64 ); if (v) { if (v < 32) { dword t = (hi << (32-v)) & LO_MASK; hi = hi >> v; lo = lo >> v | t; } else { lo = hi >> (v-32); hi = 0; } } } } #endif nestopia-1.51.1/source/core/NstCore.hpp000066400000000000000000000413221411157722000177410ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_CORE_H #define NST_CORE_H #include #ifndef NST_BASE_H #include "NstBase.hpp" #endif #ifdef NST_PRAGMA_ONCE #pragma once #endif #if defined(_WIN32) || defined(WIN32) || defined(__WIN32__) #define NST_WIN32 #endif #if NST_MSVC #pragma warning( disable : 4018 4100 4127 4244 4245 4308 4309 4310 4512 4800 4996 ) #if NST_MSVC >= 800 #ifdef NST_WIN32 #define NST_FASTCALL __fastcall #define NST_REGCALL NST_FASTCALL #endif #if NST_MSVC >= 1200 #ifndef NST_FASTDELEGATE #define NST_FASTDELEGATE #endif #ifndef _DEBUG #define NST_MSVC_OPTIMIZE #define NST_FORCE_INLINE __forceinline #pragma inline_depth( 255 ) #pragma inline_recursion( on ) #endif #define NST_SINGLE_CALL __forceinline #if NST_MSVC >= 1300 #ifndef NST_NO_INLINE #define NST_NO_INLINE __declspec(noinline) #endif #ifndef NST_ASSUME #define NST_ASSUME(x_) __assume(x_) #endif #ifndef NST_DEBUG #define NST_UNREACHABLE() __assume(0) #endif #if !defined(NST_MM_INTRINSICS) && defined(NST_WIN32) && defined(_M_IX86) #define NST_MM_INTRINSICS #endif #define NST_NO_VTABLE __declspec(novtable) #if NST_MSVC >= 1400 #ifndef NST_RESTRICT #define NST_RESTRICT __restrict #endif #pragma warning( default : 4191 4263 4287 4289 4296 4350 4545 4546 4547 4549 4555 4557 4686 4836 4905 4906 4928 4946 ) #if 0 #pragma warning( default : 4820 ) // byte padding on structs #pragma warning( default : 4710 ) // function not inlined #pragma warning( default : 4711 ) // function auto inlined #pragma warning( default : 4100 ) // unreferenced parameter #endif #endif #endif #endif #endif #elif NST_GCC #if NST_GCC >= 291 #ifndef NST_RESTRICT #define NST_RESTRICT __restrict__ #endif #if NST_GCC >= 301 #ifndef NST_NO_INLINE #define NST_NO_INLINE __attribute__((noinline)) #endif // Commenting this fixes a lot of warnings on newer versions of GCC // #define NST_SINGLE_CALL __attribute__((always_inline)) #if (NST_GCC >= 304) && defined(__i386__) #define NST_REGCALL __attribute__((regparm(2))) #endif #endif #endif #endif #if NST_ICC #pragma warning( disable : 11 69 304 373 383 444 810 869 981 1418 1572 1599 1786 ) #if !defined(NST_RESTRICT) && NST_ICC >= 810 #define NST_RESTRICT restrict #endif #endif #define NST_NOP() ((void)0) #ifndef NST_FORCE_INLINE #define NST_FORCE_INLINE inline #endif #ifndef NST_SINGLE_CALL #define NST_SINGLE_CALL NST_FORCE_INLINE #endif #ifndef NST_NO_INLINE #define NST_NO_INLINE #endif #ifndef NST_ASSUME #define NST_ASSUME(x_) NST_NOP() #endif #ifndef NST_NO_VTABLE #define NST_NO_VTABLE #endif #ifndef NST_RESTRICT #define NST_RESTRICT #endif #ifndef NST_UNREACHABLE #define NST_UNREACHABLE() NST_ASSERT(0) #endif #ifndef NST_FASTCALL #define NST_FASTCALL #endif #ifndef NST_REGCALL #define NST_REGCALL #endif #define NST_MIN(x_,y_) ((x_) < (y_) ? (x_) : (y_)) #define NST_MAX(x_,y_) ((x_) < (y_) ? (y_) : (x_)) #define NST_COMMA , #define NST_CAT_NEXT(x_,y_) x_##y_ #define NST_CAT(x_,y_) NST_CAT_NEXT(x_,y_) #define NST_COMPILE_ASSERT(expr_) typedef char NST_CAT(Nestopia_assertion_at_line_,__LINE__)[(expr_) ? 1 : -1] namespace Nes { namespace Core { typedef const char* cstring; typedef const wchar_t* wcstring; typedef uint ibool; typedef uint Data; typedef uint Address; typedef dword Cycle; template char(& array(T(&)[N]))[N]; namespace Helper { template struct CountBits { enum { VALUE = 1 + CountBits::VALUE }; }; template<> struct CountBits<1UL> { enum { VALUE = 1 }; }; template<> struct CountBits<0UL> { enum { VALUE = 0 }; }; template struct ShiftSigned { static long Left(T v,uint c) { return v << c; } static long Right(T v,uint c) { return v >> c; } }; template struct ShiftSigned { static long Left(T v,uint c) { return (v >= 0) ? +long(ulong(v) << c) : -long(ulong(-v) << c); } static long Right(T v,uint c) { return (v >= 0) ? +long(ulong(v) >> c) : -long(ulong(-v) >> c); } }; template struct SignExtend8 { static T Convert(T v) { return schar(v); } }; template struct SignExtend8 { static T Convert(T v) { return (v & 1U << 7) ? (v | ~0UL << 7) : v; } }; } template struct ValueBits { enum { VALUE = Helper::CountBits::VALUE }; }; template inline long signed_shl(T v,uint c) { enum {NATIVE = -(T(7) << 1) == -14}; return Helper::ShiftSigned::Left( v, c ); } template inline long signed_shr(T v,uint c) { enum {NATIVE = -(T(7) >> 1) == -4 || -(T(7) >> 1) == -3}; return Helper::ShiftSigned::Right( v, c ); } template inline T sign_extend_8(T v) { enum {NATIVE = CHAR_BIT == 8 && UCHAR_MAX == 0xFF && SCHAR_MIN == -128 && SCHAR_MAX == 127 && T(-2) == T(~1UL)}; return Helper::SignExtend8::Convert( v ); } template inline idword Clamp(idword value) { return (value <= Max) ? (value >= Min) ? value : Min : Max; } enum { SIZE_1K = 0x400, SIZE_2K = 0x800, SIZE_4K = 0x1000, SIZE_5K = 0x1400, SIZE_6K = 0x1800, SIZE_8K = 0x2000, SIZE_16K = 0x4000, SIZE_32K = 0x8000, SIZE_40K = 0xA000, SIZE_64K = 0x10000, SIZE_128K = 0x20000, SIZE_256K = 0x40000, SIZE_512K = 0x80000, SIZE_1024K = 0x100000, SIZE_2048K = 0x200000, SIZE_3072K = 0x300000, SIZE_4096K = 0x400000, SIZE_8192K = 0x800000, SIZE_16384K = 0x1000000 }; template struct Ascii { enum { V = ( T >= 'a' && T <= 'z') ? T - 'a' + 0x61 : ( T >= 'A' && T <= 'Z') ? T - 'A' + 0x41 : ( T >= '0' && T <= '9') ? T - '0' + 0x30 : ( T == '\0' ) ? 0x00 : ( T == ' ' ) ? 0x20 : ( T == '!' ) ? 0x21 : ( T == '#' ) ? 0x23 : ( T == '%' ) ? 0x25 : ( T == '^' ) ? 0x5E : ( T == '&' ) ? 0x26 : ( T == '*' ) ? 0x2A : ( T == '(' ) ? 0x28 : ( T == ')' ) ? 0x29 : ( T == '-' ) ? 0x2D : ( T == '_' ) ? 0x5F : ( T == '+' ) ? 0x2B : ( T == '=' ) ? 0x3D : ( T == '~' ) ? 0x7E : ( T == '[' ) ? 0x5B : ( T == ']' ) ? 0x5D : ( T == '\\' ) ? 0x5C : ( T == '|' ) ? 0x7C : ( T == ';' ) ? 0x3B : ( T == ':' ) ? 0x3A : ( T == '\'' ) ? 0x27 : ( T == '\"' ) ? 0x22 : ( T == '{' ) ? 0x7B : ( T == '}' ) ? 0x7D : ( T == ',' ) ? 0x2C : ( T == '.' ) ? 0x2E : ( T == '<' ) ? 0x3C : ( T == '>' ) ? 0x3E : ( T == '/' ) ? 0x2F : ( T == '?' ) ? 0x3F : ( T == '\a' ) ? 0x07 : ( T == '\b' ) ? 0x08 : ( T == '\t' ) ? 0x09 : ( T == '\v' ) ? 0x0B : ( T == '\n' ) ? 0x0A : ( T == '\r' ) ? 0x0D : ( T == '\f' ) ? 0x0C : 0xFF }; NST_COMPILE_ASSERT( V != 0xFF ); }; template struct AsciiId { enum { V = ( dword( Ascii::V ) << 0 | dword( Ascii::V ) << 8 | dword( Ascii::V ) << 16 | dword( Ascii::V ) << 24 ) }; static dword R(byte a,byte b=0,byte c=0,byte d=0) { return ( dword( Ascii::V + a ) << 0 | dword( Ascii::V + b ) << 8 | dword( Ascii::V + c ) << 16 | dword( Ascii::V + d ) << 24 ); } }; template int StringCompare(const T* a,const U* b) { do { const wchar_t v[] = { (*a < L'a' || *a > L'z') ? *a : (L'A' + (*a - L'a')), (*b < L'a' || *b > L'z') ? *b : (L'A' + (*b - L'a')) }; if (v[0] < v[1]) return -1; if (v[0] > v[1]) return +1; } while (++b, *a++); return 0; } template int StringCompare(const T* a,const U* b,uint l) { for (; l--; ++a, ++b) { const wchar_t v[] = { (*a < L'a' || *a > L'z') ? *a : (L'A' + (*a - L'a')), (*b < L'a' || *b > L'z') ? *b : (L'A' + (*b - L'a')) }; if (v[0] < v[1]) return -1; if (v[0] > v[1]) return +1; if (!v[0]) return 0; } return 0; } } #ifdef NST_U64 typedef NST_U64 qaword; #define NST_NATIVE_QWORD #elif (ULONG_MAX > 0xFFFFFFFF) && (ULONG_MAX / 0xFFFFFFFF - 1 > 0xFFFFFFFF) typedef unsigned long qaword; #define NST_NATIVE_QWORD #elif (defined(ULLONG_MAX) && (ULLONG_MAX > 0xFFFFFFFF) && (ULLONG_MAX / 0xFFFFFFFF - 1 > 0xFFFFFFFF)) || (NST_GCC >= 300) #if NST_GCC __extension__ typedef unsigned long long qaword; #else typedef unsigned long long qaword; #endif #define NST_NATIVE_QWORD #elif defined(_UI64_MAX) && (NST_MSVC >= 900 || NST_BCB >= 0x530) typedef unsigned __int64 qaword; #define NST_NATIVE_QWORD #else class qaword { void Multiply(qaword); static void Divide(qaword&,const qaword,bool); void Shl(uint); void Shr(uint); enum { LO_MASK = 0xFFFFFFFF, LO_MSB = 0x80000000 }; dword lo; dword hi; public: qaword() {} qaword(dword v) : lo(v), hi(0) {} qaword(dword msdw,dword lsdw) : lo(lsdw), hi(msdw) {} qaword(const qaword& v) : lo(v.lo), hi(v.hi) {} template qaword& operator = (const V& v) { lo = v; hi = 0; return *this; } qaword& operator = (const qaword& v) { lo = v.lo; hi = v.hi; return *this; } template qaword& operator += (const V& v) { dword t = lo; lo = (lo + v) & LO_MASK; hi = (hi + (t > lo)) & LO_MASK; return *this; } template qaword& operator -= (const V& v) { dword t = lo; lo = (lo - v) & LO_MASK; hi = (hi - (t < lo)) & LO_MASK; return *this; } qaword operator ++ (int) { qaword t; t.lo = lo; lo = (lo + 1) & LO_MASK; t.hi = hi; hi = (hi + (t.lo > lo)) & LO_MASK; return t; } qaword& operator ++ () { dword t = lo; lo = (lo + 1) & LO_MASK; hi = (hi + (t > lo)) & LO_MASK; return *this; } qaword operator -- (int) { qaword t; t.lo = lo; lo = (lo - 1) & LO_MASK; t.hi = hi; hi = (hi - (t.lo < lo)) & LO_MASK; return t; } qaword& operator -- () { dword t = lo; lo = (lo - 1) & LO_MASK; hi = (hi - (t < lo)) & LO_MASK; return *this; } template qaword& operator *= (const V& v) { if (!(((lo | v) & 0xFFFF0000) | hi)) lo = (lo * v) & LO_MASK; else Multiply( qaword(v) ); return *this; } template qaword& operator /= (const V& v) { if (!hi) lo /= v; else Divide( *this, qaword(v), false ); return *this; } template qaword& operator %= (const V& v) { if (!hi) lo %= v; else Divide( *this, qaword(v), true ); return *this; } template qaword operator + (const V& v) const { return qaword(*this) += v; } template qaword operator - (const V& v) const { return qaword(*this) -= v; } template qaword operator * (const V& v) const { return qaword(*this) *= v; } template qaword operator / (const V& v) const { return qaword(*this) /= v; } template qaword operator % (const V& v) const { return qaword(*this) %= v; } template qaword& operator |= (const V& v) { lo |= v; return *this; } template qaword& operator &= (const V& v) { lo &= v; hi = 0; return *this; } template qaword& operator ^= (const V& v) { lo ^= v; return *this; } template qaword operator | (const V& v) const { return qaword( hi, lo | v ); } template qaword operator & (const V& v) const { return qaword( lo & v ); } template qaword operator ^ (const V& v) const { return qaword( hi, lo ^ v ); } template qaword& operator >>= (const V& v) { Shr(v); return *this; } template qaword& operator <<= (const V& v) { Shl(v); return *this; } template qaword operator >> (const V& v) const { return qaword(*this) >>= v; } template qaword operator << (const V& v) const { return qaword(*this) <<= v; } qaword operator ~() const { return qaword( hi ^ LO_MASK, lo ^ LO_MASK ); } template bool operator == (const V& v) const { return !((lo - v) | hi); } template bool operator < (const V& v) const { return (lo < v && !hi); } template bool operator <= (const V& v) const { return (lo <= v && !hi); } template bool operator != (const V& v) const { return !(*this == v); } template bool operator > (const V& v) const { return !(*this <= v); } template bool operator >= (const V& v) const { return !(*this < v); } bool operator !() const { return !(lo|hi); } operator bool() const { return (lo|hi); } operator int () const { return lo; } operator uint () const { return lo; } operator char () const { return lo; } operator schar () const { return lo; } operator uchar () const { return lo; } operator short () const { return lo; } operator ushort () const { return lo; } operator long () const { return lo; } operator ulong () const { return lo; } }; template<> inline qaword& qaword::operator += (const qaword& v) { dword t = lo; lo = (lo + v.lo) & LO_MASK; hi = (hi + (t > lo) + v.hi) & LO_MASK; return *this; } template<> inline qaword& qaword::operator -= (const qaword& v) { dword t = lo; lo = (lo - v.lo) & LO_MASK; hi = (hi - ((t < lo) + v.hi)) & LO_MASK; return *this; } template<> inline qaword& qaword::operator *= (const qaword& v) { Multiply( v ); return *this; } template<> inline qaword& qaword::operator /= (const qaword& v) { if (hi | v.hi) Divide( *this, v, false ); else lo /= v.lo; return *this; } template<> inline qaword& qaword::operator %= (const qaword& v) { Divide( *this, v, true ); return *this; } template<> inline qaword& qaword::operator |= (const qaword& v) { lo |= v.lo; hi |= v.hi; return *this; } template<> inline qaword& qaword::operator &= (const qaword& v) { lo &= v.lo; hi &= v.hi; return *this; } template<> inline qaword& qaword::operator ^= (const qaword& v) { lo ^= v.lo; hi ^= v.hi; return *this; } template<> inline qaword qaword::operator | (const qaword& v) const { return qaword( hi | v.hi, lo | v.lo ); } template<> inline qaword qaword::operator & (const qaword& v) const { return qaword( hi & v.hi, lo & v.lo ); } template<> inline qaword qaword::operator ^ (const qaword& v) const { return qaword( hi ^ v.hi, lo ^ v.lo ); } template<> inline bool qaword::operator == (const qaword& v) const { return !((lo - v.lo) | (hi - v.hi)); } template<> inline bool qaword::operator < (const qaword& v) const { return (hi < v.hi) || (lo < v.lo && hi == v.hi); } template<> inline bool qaword::operator <= (const qaword& v) const { return (hi < v.hi) || (hi == v.hi ? (lo <= v.lo) : false); } #endif } #endif nestopia-1.51.1/source/core/NstCpu.cpp000066400000000000000000001736371411157722000176120ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include "NstCpu.hpp" #include "NstHook.hpp" #include "NstState.hpp" #include "api/NstApiUser.hpp" namespace Nes { namespace Core { dword Cpu::logged = 0; void (Cpu::*const Cpu::opcodes[0x100])() = { &Cpu::op0x00, &Cpu::op0x01, &Cpu::op0x02, &Cpu::op0x03, &Cpu::op0x04, &Cpu::op0x05, &Cpu::op0x06, &Cpu::op0x07, &Cpu::op0x08, &Cpu::op0x09, &Cpu::op0x0A, &Cpu::op0x0B, &Cpu::op0x0C, &Cpu::op0x0D, &Cpu::op0x0E, &Cpu::op0x0F, &Cpu::op0x10, &Cpu::op0x11, &Cpu::op0x12, &Cpu::op0x13, &Cpu::op0x14, &Cpu::op0x15, &Cpu::op0x16, &Cpu::op0x17, &Cpu::op0x18, &Cpu::op0x19, &Cpu::op0x1A, &Cpu::op0x1B, &Cpu::op0x1C, &Cpu::op0x1D, &Cpu::op0x1E, &Cpu::op0x1F, &Cpu::op0x20, &Cpu::op0x21, &Cpu::op0x22, &Cpu::op0x23, &Cpu::op0x24, &Cpu::op0x25, &Cpu::op0x26, &Cpu::op0x27, &Cpu::op0x28, &Cpu::op0x29, &Cpu::op0x2A, &Cpu::op0x2B, &Cpu::op0x2C, &Cpu::op0x2D, &Cpu::op0x2E, &Cpu::op0x2F, &Cpu::op0x30, &Cpu::op0x31, &Cpu::op0x32, &Cpu::op0x33, &Cpu::op0x34, &Cpu::op0x35, &Cpu::op0x36, &Cpu::op0x37, &Cpu::op0x38, &Cpu::op0x39, &Cpu::op0x3A, &Cpu::op0x3B, &Cpu::op0x3C, &Cpu::op0x3D, &Cpu::op0x3E, &Cpu::op0x3F, &Cpu::op0x40, &Cpu::op0x41, &Cpu::op0x42, &Cpu::op0x43, &Cpu::op0x44, &Cpu::op0x45, &Cpu::op0x46, &Cpu::op0x47, &Cpu::op0x48, &Cpu::op0x49, &Cpu::op0x4A, &Cpu::op0x4B, &Cpu::op0x4C, &Cpu::op0x4D, &Cpu::op0x4E, &Cpu::op0x4F, &Cpu::op0x50, &Cpu::op0x51, &Cpu::op0x52, &Cpu::op0x53, &Cpu::op0x54, &Cpu::op0x55, &Cpu::op0x56, &Cpu::op0x57, &Cpu::op0x58, &Cpu::op0x59, &Cpu::op0x5A, &Cpu::op0x5B, &Cpu::op0x5C, &Cpu::op0x5D, &Cpu::op0x5E, &Cpu::op0x5F, &Cpu::op0x60, &Cpu::op0x61, &Cpu::op0x62, &Cpu::op0x63, &Cpu::op0x64, &Cpu::op0x65, &Cpu::op0x66, &Cpu::op0x67, &Cpu::op0x68, &Cpu::op0x69, &Cpu::op0x6A, &Cpu::op0x6B, &Cpu::op0x6C, &Cpu::op0x6D, &Cpu::op0x6E, &Cpu::op0x6F, &Cpu::op0x70, &Cpu::op0x71, &Cpu::op0x72, &Cpu::op0x73, &Cpu::op0x74, &Cpu::op0x75, &Cpu::op0x76, &Cpu::op0x77, &Cpu::op0x78, &Cpu::op0x79, &Cpu::op0x7A, &Cpu::op0x7B, &Cpu::op0x7C, &Cpu::op0x7D, &Cpu::op0x7E, &Cpu::op0x7F, &Cpu::op0x80, &Cpu::op0x81, &Cpu::op0x82, &Cpu::op0x83, &Cpu::op0x84, &Cpu::op0x85, &Cpu::op0x86, &Cpu::op0x87, &Cpu::op0x88, &Cpu::op0x89, &Cpu::op0x8A, &Cpu::op0x8B, &Cpu::op0x8C, &Cpu::op0x8D, &Cpu::op0x8E, &Cpu::op0x8F, &Cpu::op0x90, &Cpu::op0x91, &Cpu::op0x92, &Cpu::op0x93, &Cpu::op0x94, &Cpu::op0x95, &Cpu::op0x96, &Cpu::op0x97, &Cpu::op0x98, &Cpu::op0x99, &Cpu::op0x9A, &Cpu::op0x9B, &Cpu::op0x9C, &Cpu::op0x9D, &Cpu::op0x9E, &Cpu::op0x9F, &Cpu::op0xA0, &Cpu::op0xA1, &Cpu::op0xA2, &Cpu::op0xA3, &Cpu::op0xA4, &Cpu::op0xA5, &Cpu::op0xA6, &Cpu::op0xA7, &Cpu::op0xA8, &Cpu::op0xA9, &Cpu::op0xAA, &Cpu::op0xAB, &Cpu::op0xAC, &Cpu::op0xAD, &Cpu::op0xAE, &Cpu::op0xAF, &Cpu::op0xB0, &Cpu::op0xB1, &Cpu::op0xB2, &Cpu::op0xB3, &Cpu::op0xB4, &Cpu::op0xB5, &Cpu::op0xB6, &Cpu::op0xB7, &Cpu::op0xB8, &Cpu::op0xB9, &Cpu::op0xBA, &Cpu::op0xBB, &Cpu::op0xBC, &Cpu::op0xBD, &Cpu::op0xBE, &Cpu::op0xBF, &Cpu::op0xC0, &Cpu::op0xC1, &Cpu::op0xC2, &Cpu::op0xC3, &Cpu::op0xC4, &Cpu::op0xC5, &Cpu::op0xC6, &Cpu::op0xC7, &Cpu::op0xC8, &Cpu::op0xC9, &Cpu::op0xCA, &Cpu::op0xCB, &Cpu::op0xCC, &Cpu::op0xCD, &Cpu::op0xCE, &Cpu::op0xCF, &Cpu::op0xD0, &Cpu::op0xD1, &Cpu::op0xD2, &Cpu::op0xD3, &Cpu::op0xD4, &Cpu::op0xD5, &Cpu::op0xD6, &Cpu::op0xD7, &Cpu::op0xD8, &Cpu::op0xD9, &Cpu::op0xDA, &Cpu::op0xDB, &Cpu::op0xDC, &Cpu::op0xDD, &Cpu::op0xDE, &Cpu::op0xDF, &Cpu::op0xE0, &Cpu::op0xE1, &Cpu::op0xE2, &Cpu::op0xE3, &Cpu::op0xE4, &Cpu::op0xE5, &Cpu::op0xE6, &Cpu::op0xE7, &Cpu::op0xE8, &Cpu::op0xE9, &Cpu::op0xEA, &Cpu::op0xEB, &Cpu::op0xEC, &Cpu::op0xED, &Cpu::op0xEE, &Cpu::op0xEF, &Cpu::op0xF0, &Cpu::op0xF1, &Cpu::op0xF2, &Cpu::op0xF3, &Cpu::op0xF4, &Cpu::op0xF5, &Cpu::op0xF6, &Cpu::op0xF7, &Cpu::op0xF8, &Cpu::op0xF9, &Cpu::op0xFA, &Cpu::op0xFB, &Cpu::op0xFC, &Cpu::op0xFD, &Cpu::op0xFE, &Cpu::op0xFF }; const byte Cpu::writeClocks[0x100] = { 0x1C, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x18, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x60, 0x60, 0x1C, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x18, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x60, 0x60, 0x00, 0x20, 0x00, 0x20, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x20, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 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, 0xC0, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x60, 0x60 }; #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif #if NST_MSVC >= 1200 #pragma warning( push ) #pragma warning( disable : 4355 ) #endif Cpu::Cpu() : model ( CPU_RP2A03 ), apu ( *this ), map ( this, &Cpu::Peek_Overflow, &Cpu::Poke_Overflow ) { cycles.UpdateTable( GetModel() ); Reset( false, false ); } #if NST_MSVC >= 1200 #pragma warning( pop ) #endif void Cpu::PowerOff() { Reset( false, true ); } void Cpu::SetRamPowerState(uint powerstate) { ram.powerstate = powerstate; } void Cpu::Reset(bool hard) { Reset( true, hard ); } void Cpu::Reset(const bool on,const bool hard) { if (!on || hard) { ram.Reset( GetModel() ); a = 0x00; x = 0x00; y = 0x00; sp = 0xFD; flags.nz = 0U ^ 1U; flags.c = 0; flags.v = 0; flags.d = 0; } else { sp = (sp - 3) & 0xFF; } opcode = 0; flags.i = Flags::I; jammed = false; ticks = 0; logged = 0; pc = RESET_VECTOR; cycles.count = 0; cycles.offset = 0; cycles.round = 0; cycles.frame = (model == CPU_RP2A03 ? PPU_RP2C02_HVSYNC : model == CPU_RP2A07 ? PPU_RP2C07_HVSYNC : PPU_DENDY_HVSYNC); interrupt.Reset(); hooks.Clear(); linker.Clear(); if (on) { map( 0x0000, 0x07FF ).Set( &ram, &Ram::Peek_Ram_0, &Ram::Poke_Ram_0 ); map( 0x0800, 0x0FFF ).Set( &ram, &Ram::Peek_Ram_1, &Ram::Poke_Ram_1 ); map( 0x1000, 0x17FF ).Set( &ram, &Ram::Peek_Ram_2, &Ram::Poke_Ram_2 ); map( 0x1800, 0x1FFF ).Set( &ram, &Ram::Peek_Ram_3, &Ram::Poke_Ram_3 ); map( 0x2000, 0xFFFF ).Set( this, &Cpu::Peek_Nop, &Cpu::Poke_Nop ); map( 0xFFFC ).Set( this, &Cpu::Peek_Jam_1, &Cpu::Poke_Nop ); map( 0xFFFD ).Set( this, &Cpu::Peek_Jam_2, &Cpu::Poke_Nop ); apu.Reset( hard ); } else { map( 0x0000, 0xFFFF ).Set( this, &Cpu::Peek_Nop, &Cpu::Poke_Nop ); if (hard) apu.PowerOff(); } } void Cpu::Boot(const bool hard) { NST_VERIFY( pc == RESET_VECTOR ); pc = map.Peek16( RESET_VECTOR ); if (hard) { Poke(0x4017, 0x00); cycles.count = cycles.clock[RESET_CYCLES] + cycles.clock[0]; } else { Poke(0x4017, apu.GetCtrl()); cycles.count = cycles.clock[RESET_CYCLES] + cycles.clock[0]; } } void Cpu::SetModel(const CpuModel m) { NST_ASSERT( pc == RESET_VECTOR && cycles.count == 0 ); if (model != m) { model = m; cycles.UpdateTable( m ); } } void Cpu::AddHook(const Hook& hook) { hooks.Add( hook ); } void Cpu::RemoveHook(const Hook& hook) { hooks.Remove( hook ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif bool Cpu::IsOddCycle() const { return uint((ticks + cycles.count) % cycles.clock[1]); } bool Cpu::IsWriteCycle(Cycle clock) const { if (const uint clocks = writeClocks[opcode]) { clock = (clock - cycles.offset) / cycles.clock[0]; if (clock < 8) return clocks >> clock & 0x1; } return false; } Cycle Cpu::GetClockBase() const { return model == CPU_RP2A07 || model == CPU_DENDY ? CLK_PAL : CLK_NTSC; } uint Cpu::GetClockDivider() const { return model == CPU_RP2A07 || model == CPU_DENDY ? CLK_PAL_DIV : CLK_NTSC_DIV; } dword Cpu::GetTime(Cycle clock) const { return ( model == CPU_RP2A03 ? clock * qaword( CPU_RP2A03_CC * CLK_NTSC_DIV ) / CLK_NTSC : model == CPU_RP2A07 ? clock * qaword( CPU_RP2A07_CC * CLK_PAL_DIV ) / CLK_PAL : clock * qaword( CPU_DENDY_CC * CLK_PAL_DIV ) / CLK_PAL ); } dword Cpu::GetFps() const { return ( model == CPU_RP2A03 ? PPU_RP2C02_FPS : model == CPU_RP2A07 ? PPU_RP2C07_FPS : PPU_DENDY_FPS ); } inline uint Cpu::Cycles::InterruptEdge() const { return clock[0] + clock[0] / 2; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Cpu::SaveState(State::Saver& state,const dword cpuChunk,const dword apuChunk) const { state.Begin( cpuChunk ); { const byte data[7] = { pc & 0xFF, pc >> 8, sp, a, x, y, flags.Pack() }; state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End(); } state.Begin( AsciiId<'R','A','M'>::V ).Compress( ram.mem ).End(); { const byte data[5] = { ((interrupt.nmiClock != CYCLE_MAX) ? 0x01U : 0x00U) | ((interrupt.low & IRQ_FRAME) ? 0x02U : 0x00U) | ((interrupt.low & IRQ_DMC) ? 0x04U : 0x00U) | ((interrupt.low & IRQ_EXT) ? 0x08U : 0x00U) | (jammed ? 0x40U : 0x00U) | (model == CPU_RP2A07 ? 0x80U : model == CPU_DENDY ? 0x20U : 0x00U), cycles.count & 0xFF, cycles.count >> 8, (interrupt.nmiClock != CYCLE_MAX) ? interrupt.nmiClock+1 : 0, (interrupt.irqClock != CYCLE_MAX) ? interrupt.irqClock+1 : 0 }; state.Begin( AsciiId<'F','R','M'>::V ).Write( data ).End(); } state.Begin( AsciiId<'C','L','K'>::V ).Write64( ticks ).End(); state.End(); apu.SaveState( state, apuChunk ); } void Cpu::LoadState(State::Loader& state,const dword cpuChunk,const dword apuChunk,const dword baseChunk) { if (baseChunk == cpuChunk) { CpuModel stateModel = GetModel(); ticks = 0; while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: { State::Loader::Data<7> data( state ); pc = data[0] | data[1] << 8; sp = data[2]; a = data[3]; x = data[4]; y = data[5]; flags.Unpack( data[6] ); break; } case AsciiId<'R','A','M'>::V: state.Uncompress( ram.mem ); break; case AsciiId<'F','R','M'>::V: { State::Loader::Data<5> data( state ); switch (data[0] & (0x80|0x20)) { case 0x20: stateModel = CPU_DENDY; break; case 0x80: stateModel = CPU_RP2A07; break; default: stateModel = CPU_RP2A03; break; } interrupt.nmiClock = CYCLE_MAX; interrupt.irqClock = CYCLE_MAX; interrupt.low = 0; if (data[0] & (0x2|0x4|0x8)) { interrupt.low = ( ((data[0] & 0x2) ? IRQ_FRAME : 0) | ((data[0] & 0x4) ? IRQ_DMC : 0) | ((data[0] & 0x8) ? IRQ_EXT : 0) ); if (!flags.i) interrupt.irqClock = data[4] ? data[4] - 1 : 0; } cycles.count = data[1] | data[2] << 8; if (data[0] & 0x1) interrupt.nmiClock = data[3] ? data[3] - 1 : cycles.InterruptEdge(); jammed = data[0] >> 6 & 0x1; if (jammed) interrupt.Reset(); break; } case AsciiId<'C','L','K'>::V: ticks = state.Read64(); break; } state.End(); } const CpuModel actualModel = GetModel(); if (stateModel != actualModel) { const uint clocks[2] = { stateModel == CPU_RP2A03 ? CPU_RP2A03_CC : stateModel == CPU_RP2A07 ? CPU_RP2A07_CC : CPU_DENDY_CC, actualModel == CPU_RP2A03 ? CPU_RP2A03_CC : actualModel == CPU_RP2A07 ? CPU_RP2A07_CC : CPU_DENDY_CC }; cycles.count = cycles.count / clocks[0] * clocks[1]; ticks = ticks / clocks[0] * clocks[1]; if (interrupt.nmiClock != CYCLE_MAX) interrupt.nmiClock = interrupt.nmiClock / clocks[0] * clocks[1]; if (interrupt.irqClock != CYCLE_MAX) interrupt.irqClock = interrupt.irqClock / clocks[0] * clocks[1]; } NST_VERIFY( cycles.count < cycles.frame ); if (cycles.count >= cycles.frame) cycles.count = 0; ticks -= (ticks + cycles.count) % cycles.clock[0]; } else if (baseChunk == apuChunk) { apu.LoadState( state ); } } void Cpu::NotifyOp(const char (&code)[4],const dword which) { if (!(logged & which)) { logged |= which; Api::User::eventCallback( Api::User::EVENT_CPU_UNOFFICIAL_OPCODE, code ); } } Cpu::Hooks::Hooks() : hooks(new Hook [2]), size(0), capacity(2) {} Cpu::Hooks::~Hooks() { delete [] hooks; } void Cpu::Hooks::Clear() { size = 0; } void Cpu::Hooks::Add(const Hook& hook) { for (uint i=0, n=size; i < n; ++i) { if (hooks[i] == hook) return; } if (size == capacity) { Hook* const NST_RESTRICT next = new Hook [capacity+1]; ++capacity; for (uint i=0, n=size; i < n; ++i) next[i] = hooks[i]; delete [] hooks; hooks = next; } hooks[size++] = hook; } void Cpu::Hooks::Remove(const Hook& hook) { for (uint i=0, n=size; i < n; ++i) { if (hooks[i] == hook) { while (++i < n) hooks[i-1] = hooks[i]; --size; return; } } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif inline uint Cpu::Hooks::Size() const { return size; } inline const Hook* Cpu::Hooks::Ptr() const { return hooks; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Cpu::Linker::Chain::Chain(const Port& p,uint a,uint l) : Port(p), address(a), level(l) {} Cpu::Linker::Linker() : chain(NULL) {} Cpu::Linker::~Linker() { Clear(); } void Cpu::Linker::Clear() { if (Chain* next = chain) { chain = NULL; do { Chain* tmp = next->next; delete next; next = tmp; } while (next); } } const Io::Port* Cpu::Linker::Add(const Address address,const uint level,const Io::Port& port,IoMap& map) { NST_ASSERT( level ); Chain* const entry = new Chain( port, address, level ); for (Chain *it=chain, *prev=NULL; it; prev=it, it=it->next) { if (it->address == address) { NST_ASSERT( it->next && it->next->address == address ); if (level > it->level) { entry->next = it; if (prev) prev->next = entry; else chain = entry; map(address) = port; return it; } else for (;;) { it = it->next; NST_ASSERT( level != it->level ); if (level > it->level) { const Chain tmp( *it ); *it = *entry; it->next = entry; *entry = tmp; return entry; } } } } entry->next = new Chain( map[address], address ); entry->next->next = NULL; map(address) = port; if (Chain* it = chain) { while (it->next) it = it->next; it->next = entry; } else { chain = entry; } return entry->next; } void Cpu::Linker::Remove(const Address address,const Io::Port& port,IoMap& map) { for (Chain *it=chain, *prev=NULL; it; prev=it, it=it->next) { if (it->address == address && port == *it) { const Chain* const next = it->next; NST_ASSERT( it->level && next && next->address == address ); *it = *next; delete next; if (map(address) == port) map(address) = *it; if (it->level == 0) { if (prev == NULL) { it = it->next; delete chain; chain = it; } else if (prev->address != address) { prev->next = it->next; delete it; } } break; } } } void Cpu::Cycles::UpdateTable(CpuModel model) { for (uint cc = (model == CPU_RP2A03 ? CPU_RP2A03_CC : model == CPU_RP2A07 ? CPU_RP2A07_CC : CPU_DENDY_CC), i=0; i < 8; ++i) clock[i] = (i+1) * cc; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif uint Cpu::Flags::Pack() const { NST_ASSERT( (i == 0 || i == I) && (c == 0 || c == C) && (d == 0 || d == D) ); return ( ((nz | nz >> 1) & N) | ((nz & 0xFF) ? 0 : Z) | c | (v ? V : 0) | i | d | R ); } void Cpu::Flags::Unpack(const uint f) { nz = (~f & Z) | ((f & N) << 1); c = f & C; v = f & V; i = f & I; d = f & D; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Cpu::Interrupt::Reset() { nmiClock = CYCLE_MAX; irqClock = CYCLE_MAX; low = 0; } template Cpu::IoMap::IoMap(Cpu* cpu,T peek,U poke) : Io::Map( cpu, peek, poke ) {} #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif inline uint Cpu::IoMap::Peek8(const uint address) const { NST_ASSERT( address < FULL_SIZE ); return ports[address].Peek( address ); } inline uint Cpu::IoMap::Peek16(const uint address) const { NST_ASSERT( address < FULL_SIZE-1 ); return ports[address].Peek( address ) | ports[address + 1].Peek( address + 1 ) << 8; } inline void Cpu::IoMap::Poke8(const uint address,const uint data) const { NST_ASSERT( address < FULL_SIZE ); ports[address].Poke( address, data ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Cpu::Ram::Reset(const CpuModel model) { switch (powerstate) { case 1: std::memset( mem, 0xFF, sizeof(mem) ); break; case 2: std::memset( mem, byte(std::rand()), sizeof(mem) ); break; default: std::memset( mem, 0x00, sizeof(mem) ); break; } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(Cpu::Ram,Ram_0) { return mem[address - 0x0000]; } NES_PEEK_A(Cpu::Ram,Ram_1) { return mem[address - 0x0800]; } NES_PEEK_A(Cpu::Ram,Ram_2) { return mem[address - 0x1000]; } NES_PEEK_A(Cpu::Ram,Ram_3) { return mem[address - 0x1800]; } NES_POKE_AD(Cpu::Ram,Ram_0) { mem[address - 0x0000] = data; } NES_POKE_AD(Cpu::Ram,Ram_1) { mem[address - 0x0800] = data; } NES_POKE_AD(Cpu::Ram,Ram_2) { mem[address - 0x1000] = data; } NES_POKE_AD(Cpu::Ram,Ram_3) { mem[address - 0x1800] = data; } NES_PEEK_A(Cpu,Nop) { return address >> 8; } NES_POKE(Cpu,Nop) { } NES_PEEK_A(Cpu,Overflow) { pc &= 0xFFFF; return ram.mem[address & 0x7FF]; } NES_POKE_AD(Cpu,Overflow) { pc &= 0xFFFF; ram.mem[address & 0x7FF] = data; } NES_PEEK(Cpu,Jam_1) { pc = (pc - 1) & 0xFFFF; return 0xFC; } NES_PEEK(Cpu,Jam_2) { return 0xFF; } inline uint Cpu::FetchZpg16(const uint address) const { return ram.mem[address & 0xFF] | uint(ram.mem[(address+1) & 0xFF]) << 8; } inline uint Cpu::FetchPc8() { const uint data = map.Peek8( pc ); ++pc; return data; } inline uint Cpu::FetchPc16() { const uint data = map.Peek16( pc ); pc += 2; return data; } //////////////////////////////////////////////////////////////////////////////////////// // Immediate addressing //////////////////////////////////////////////////////////////////////////////////////// inline uint Cpu::Imm_R() { const uint data = FetchPc8(); cycles.count += cycles.clock[1]; return data; } //////////////////////////////////////////////////////////////////////////////////////// // Absolute addressing //////////////////////////////////////////////////////////////////////////////////////// uint Cpu::Abs_R() { uint data = FetchPc16(); cycles.count += cycles.clock[2]; data = map.Peek8( data ); cycles.count += cycles.clock[0]; return data; } uint Cpu::Abs_RW(uint& data) { const uint address = FetchPc16(); cycles.count += cycles.clock[2]; data = map.Peek8( address ); cycles.count += cycles.clock[0]; map.Poke8( address, data ); cycles.count += cycles.clock[0]; return address; } inline uint Cpu::Abs_W() { const uint address = FetchPc16(); cycles.count += cycles.clock[2]; return address; } //////////////////////////////////////////////////////////////////////////////////////// // Zero page addressing //////////////////////////////////////////////////////////////////////////////////////// inline uint Cpu::Zpg_R() { const uint address = FetchPc8(); cycles.count += cycles.clock[2]; return ram.mem[address]; } inline uint Cpu::Zpg_RW(uint& data) { const uint address = FetchPc8(); cycles.count += cycles.clock[4]; data = ram.mem[address]; return address; } inline uint Cpu::Zpg_W() { const uint address = FetchPc8(); cycles.count += cycles.clock[2]; return address; } //////////////////////////////////////////////////////////////////////////////////////// // Zero page indexed addressing //////////////////////////////////////////////////////////////////////////////////////// inline uint Cpu::ZpgReg_R(uint indexed) { indexed = (indexed + FetchPc8()) & 0xFF; cycles.count += cycles.clock[3]; return ram.mem[indexed]; } inline uint Cpu::ZpgReg_RW(uint& data,uint indexed) { indexed = (indexed + FetchPc8()) & 0xFF; cycles.count += cycles.clock[5]; data = ram.mem[indexed]; return indexed; } inline uint Cpu::ZpgReg_W(uint indexed) { indexed = (indexed + FetchPc8()) & 0xFF; cycles.count += cycles.clock[3]; return indexed; } //////////////////////////////////////////////////////////////////////////////////////// // Zero page indexed addressing (X && Y) //////////////////////////////////////////////////////////////////////////////////////// inline uint Cpu::ZpgX_R() { return ZpgReg_R( x ); } inline uint Cpu::ZpgX_RW(uint& data) { return ZpgReg_RW( data, x ); } inline uint Cpu::ZpgX_W() { return ZpgReg_W( x ); } inline uint Cpu::ZpgY_R() { return ZpgReg_R( y ); } inline uint Cpu::ZpgY_RW(uint& data) { return ZpgReg_RW( data, y ); } inline uint Cpu::ZpgY_W() { return ZpgReg_W( y ); } //////////////////////////////////////////////////////////////////////////////////////// // Absolute indexed addressing //////////////////////////////////////////////////////////////////////////////////////// uint Cpu::AbsReg_R(uint indexed) { uint data = pc; indexed += map.Peek8( data ); data = (map.Peek8( data + 1 ) << 8) + indexed; cycles.count += cycles.clock[2]; if (indexed & 0x100) { map.Peek8( data - 0x100 ); cycles.count += cycles.clock[0]; } data = map.Peek8( data ); pc += 2; cycles.count += cycles.clock[0]; return data; } uint Cpu::AbsReg_RW(uint& data,uint indexed) { uint address = pc; indexed += map.Peek8( address ); address = (map.Peek8( address + 1 ) << 8) + indexed; map.Peek8( address - (indexed & 0x100) ); pc += 2; cycles.count += cycles.clock[3]; data = map.Peek8( address ); cycles.count += cycles.clock[0]; map.Poke8( address, data ); cycles.count += cycles.clock[0]; return address; } NST_FORCE_INLINE uint Cpu::AbsReg_W(uint indexed) { uint address = pc; indexed += map.Peek8( address ); address = (map.Peek8( address + 1 ) << 8) + indexed; map.Peek8( address - (indexed & 0x100) ); pc += 2; cycles.count += cycles.clock[3]; return address; } //////////////////////////////////////////////////////////////////////////////////////// // Absolute indexed addressing (X && Y) //////////////////////////////////////////////////////////////////////////////////////// inline uint Cpu::AbsX_R() { return AbsReg_R( x ); } inline uint Cpu::AbsY_R() { return AbsReg_R( y ); } inline uint Cpu::AbsX_RW(uint& data) { return AbsReg_RW( data, x ); } inline uint Cpu::AbsY_RW(uint& data) { return AbsReg_RW( data, y ); } NST_FORCE_INLINE uint Cpu::AbsX_W() { return AbsReg_W( x ); } NST_FORCE_INLINE uint Cpu::AbsY_W() { return AbsReg_W( y ); } //////////////////////////////////////////////////////////////////////////////////////// // Indexed indirect addressing //////////////////////////////////////////////////////////////////////////////////////// uint Cpu::IndX_R() { uint data = FetchPc8() + x; cycles.count += cycles.clock[4]; data = FetchZpg16( data ); data = map.Peek8( data ); cycles.count += cycles.clock[0]; return data; } inline uint Cpu::IndX_RW(uint& data) { uint address = FetchPc8() + x; cycles.count += cycles.clock[4]; address = FetchZpg16( address ); data = map.Peek8( address ); cycles.count += cycles.clock[0]; map.Poke8( address, data ); cycles.count += cycles.clock[0]; return address; } inline uint Cpu::IndX_W() { const uint address = FetchPc8() + x; cycles.count += cycles.clock[4]; return FetchZpg16( address ); } //////////////////////////////////////////////////////////////////////////////////////// // Indirect indexed addressing //////////////////////////////////////////////////////////////////////////////////////// uint Cpu::IndY_R() { uint data = FetchPc8(); cycles.count += cycles.clock[3]; const uint indexed = ram.mem[data] + y; data = (uint(ram.mem[(data + 1) & 0xFF]) << 8) + indexed; if (indexed & 0x100) { map.Peek8( data - 0x100 ); cycles.count += cycles.clock[0]; } data = map.Peek8( data ); cycles.count += cycles.clock[0]; return data; } inline uint Cpu::IndY_RW(uint& data) { uint address = FetchPc8(); cycles.count += cycles.clock[4]; const uint indexed = ram.mem[address] + y; address = (uint(ram.mem[(address + 1) & 0xFF]) << 8) + indexed; map.Peek8( address - (indexed & 0x100) ); data = map.Peek8( address ); cycles.count += cycles.clock[0]; map.Poke8( address, data ); cycles.count += cycles.clock[0]; return address; } NST_FORCE_INLINE uint Cpu::IndY_W() { uint address = FetchPc8(); cycles.count += cycles.clock[4]; const uint indexed = ram.mem[address] + y; address = (uint(ram.mem[(address + 1) & 0xFF]) << 8) + indexed; map.Peek8( address - (indexed & 0x100) ); return address; } //////////////////////////////////////////////////////////////////////////////////////// // relative addressing //////////////////////////////////////////////////////////////////////////////////////// template NST_FORCE_INLINE void Cpu::Branch(uint tmp) { if ((!!tmp) == STATE) { pc = ((tmp=pc+1) + sign_extend_8(uint(map.Peek8( pc )))) & 0xFFFF; cycles.count += cycles.clock[2 + ((tmp^pc) >> 8 & 1)]; } else { ++pc; cycles.count += cycles.clock[1]; } } //////////////////////////////////////////////////////////////////////////////////////// // store data //////////////////////////////////////////////////////////////////////////////////////// inline void Cpu::StoreMem(const uint address,const uint data) { map.Poke8( address, data ); cycles.count += cycles.clock[0]; } inline void Cpu::StoreZpg(const uint address,const uint data) { ram.mem[address] = data; } //////////////////////////////////////////////////////////////////////////////////////// // stack management //////////////////////////////////////////////////////////////////////////////////////// inline void Cpu::Push8(const uint data) { NST_ASSERT( sp <= 0xFF ); const uint p = sp; sp = (sp - 1) & 0xFF; ram.mem[0x100+p] = data; } NST_FORCE_INLINE void Cpu::Push16(const uint data) { NST_ASSERT( sp <= 0xFF ); const uint p0 = sp; const uint p1 = (p0 - 1) & 0xFF; sp = (p1 - 1) & 0xFF; ram.mem[0x100+p1] = data & 0xFF; ram.mem[0x100+p0] = data >> 8; } inline uint Cpu::Pull8() { NST_ASSERT( sp <= 0xFF ); sp = (sp + 1) & 0xFF; return ram.mem[0x100+sp]; } inline uint Cpu::Pull16() { NST_ASSERT( sp <= 0xFF ); const uint p0 = (sp + 1) & 0xFF; const uint p1 = (p0 + 1) & 0xFF; sp = p1; return ram.mem[0x100+p0] | uint(ram.mem[0x100+p1]) << 8; } //////////////////////////////////////////////////////////////////////////////////////// // load instructions //////////////////////////////////////////////////////////////////////////////////////// inline void Cpu::Lda(const uint data) { a = data; flags.nz = data; } inline void Cpu::Ldx(const uint data) { x = data; flags.nz = data; } inline void Cpu::Ldy(const uint data) { y = data; flags.nz = data; } //////////////////////////////////////////////////////////////////////////////////////// // store instructions //////////////////////////////////////////////////////////////////////////////////////// inline uint Cpu::Sta() const { return a; } inline uint Cpu::Stx() const { return x; } inline uint Cpu::Sty() const { return y; } //////////////////////////////////////////////////////////////////////////////////////// // transfer instructions //////////////////////////////////////////////////////////////////////////////////////// NST_SINGLE_CALL void Cpu::Tax() { cycles.count += cycles.clock[1]; x = a; flags.nz = a; } NST_SINGLE_CALL void Cpu::Tay() { cycles.count += cycles.clock[1]; y = a; flags.nz = a; } NST_SINGLE_CALL void Cpu::Txa() { cycles.count += cycles.clock[1]; a = x; flags.nz = x; } NST_SINGLE_CALL void Cpu::Tya() { cycles.count += cycles.clock[1]; a = y; flags.nz = y; } //////////////////////////////////////////////////////////////////////////////////////// // flow control instructions //////////////////////////////////////////////////////////////////////////////////////// NST_SINGLE_CALL void Cpu::JmpAbs() { pc = map.Peek16( pc ); cycles.count += cycles.clock[JMP_ABS_CYCLES-1]; } NST_SINGLE_CALL void Cpu::JmpInd() { // 6502 trap, can't cross between pages const uint pos = map.Peek16( pc ); pc = map.Peek8( pos ) | (map.Peek8( (pos & 0xFF00) | ((pos + 1) & 0x00FF) ) << 8); cycles.count += cycles.clock[JMP_IND_CYCLES-1]; } NST_SINGLE_CALL void Cpu::Jsr() { // 6502 trap, return address pushed on the stack is // one byte prior to the next instruction Push16( pc + 1 ); pc = map.Peek16( pc ); cycles.count += cycles.clock[JSR_CYCLES-1]; } NST_SINGLE_CALL void Cpu::Rts() { opcode = map.Peek8( pc ); pc = Pull16() + 1; cycles.count += cycles.clock[RTS_CYCLES-1]; } NST_SINGLE_CALL void Cpu::Rti() { cycles.count += cycles.clock[RTI_CYCLES-1]; { const uint packed = Pull8(); opcode = map.Peek8( pc ); pc = Pull16(); flags.Unpack( packed ); } if (!interrupt.low || flags.i) { interrupt.irqClock = CYCLE_MAX; } else { interrupt.irqClock = 0; cycles.round = 0; } } NST_SINGLE_CALL void Cpu::Bne() { Branch< true >( flags.nz & 0xFF ); } NST_SINGLE_CALL void Cpu::Beq() { Branch< false >( flags.nz & 0xFF ); } NST_SINGLE_CALL void Cpu::Bmi() { Branch< true >( flags.nz & 0x180 ); } NST_SINGLE_CALL void Cpu::Bpl() { Branch< false >( flags.nz & 0x180 ); } NST_SINGLE_CALL void Cpu::Bcs() { Branch< true >( flags.c ); } NST_SINGLE_CALL void Cpu::Bcc() { Branch< false >( flags.c ); } NST_SINGLE_CALL void Cpu::Bvs() { Branch< true >( flags.v ); } NST_SINGLE_CALL void Cpu::Bvc() { Branch< false >( flags.v ); } //////////////////////////////////////////////////////////////////////////////////////// // math operations //////////////////////////////////////////////////////////////////////////////////////// inline void Cpu::Adc(const uint data) { NST_ASSERT( flags.c <= 1 ); // the N2A03 has no BCD mode const uint tmp = a + data + flags.c; flags.v = ~(a ^ data) & (a ^ tmp) & 0x80; a = tmp & 0xFF; flags.nz = a; flags.c = tmp >> 8 & 0x1; } inline void Cpu::Sbc(const uint data) { Adc( data ^ 0xFF ); } //////////////////////////////////////////////////////////////////////////////////////// // logical operations //////////////////////////////////////////////////////////////////////////////////////// inline void Cpu::And(const uint data) { a &= data; flags.nz = a; } inline void Cpu::Ora(const uint data) { a |= data; flags.nz = a; } inline void Cpu::Eor(const uint data) { a ^= data; flags.nz = a; } inline void Cpu::Bit(const uint data) { flags.nz = ((data & a) != 0) | ((data & Flags::N) << 1); flags.v = data & Flags::V; } inline void Cpu::Cmp(uint data) { data = a - data; flags.nz = data & 0xFF; flags.c = ~data >> 8 & 0x1; } inline void Cpu::Cpx(uint data) { data = x - data; flags.nz = data & 0xFF; flags.c = ~data >> 8 & 0x1; } inline void Cpu::Cpy(uint data) { data = y - data; flags.nz = data & 0xFF; flags.c = ~data >> 8 & 0x1; } //////////////////////////////////////////////////////////////////////////////////////// // shift operations //////////////////////////////////////////////////////////////////////////////////////// inline uint Cpu::Asl(const uint data) { flags.c = data >> 7; flags.nz = data << 1 & 0xFF; return flags.nz; } inline uint Cpu::Lsr(const uint data) { flags.c = data & 0x01; flags.nz = data >> 1; return flags.nz; } inline uint Cpu::Rol(const uint data) { NST_ASSERT( flags.c <= 1 ); flags.nz = (data << 1 & 0xFF) | flags.c; flags.c = data >> 7; return flags.nz; } inline uint Cpu::Ror(const uint data) { NST_ASSERT( flags.c <= 1 ); flags.nz = (data >> 1) | (flags.c << 7); flags.c = data & 0x01; return flags.nz; } //////////////////////////////////////////////////////////////////////////////////////// // increment and decrement operations //////////////////////////////////////////////////////////////////////////////////////// inline uint Cpu::Dec(const uint data) { flags.nz = (data - 1) & 0xFF; return flags.nz; } inline uint Cpu::Inc(const uint data) { flags.nz = (data + 1) & 0xFF; return flags.nz; } NST_SINGLE_CALL void Cpu::Dex() { cycles.count += cycles.clock[1]; x = (x - 1) & 0xFF; flags.nz = x; } NST_SINGLE_CALL void Cpu::Dey() { cycles.count += cycles.clock[1]; y = (y - 1) & 0xFF; flags.nz = y; } NST_SINGLE_CALL void Cpu::Inx() { cycles.count += cycles.clock[1]; x = (x + 1) & 0xFF; flags.nz = x; } NST_SINGLE_CALL void Cpu::Iny() { cycles.count += cycles.clock[1]; y = (y + 1) & 0xFF; flags.nz = y; } //////////////////////////////////////////////////////////////////////////////////////// // flags instructions //////////////////////////////////////////////////////////////////////////////////////// NST_SINGLE_CALL void Cpu::Clc() { cycles.count += cycles.clock[1]; flags.c = 0; } NST_SINGLE_CALL void Cpu::Sec() { cycles.count += cycles.clock[1]; flags.c = Flags::C; } NST_SINGLE_CALL void Cpu::Cld() { cycles.count += cycles.clock[1]; flags.d = 0; } NST_SINGLE_CALL void Cpu::Sed() { cycles.count += cycles.clock[1]; flags.d = Flags::D; } NST_SINGLE_CALL void Cpu::Clv() { cycles.count += cycles.clock[1]; flags.v = 0; } NST_SINGLE_CALL void Cpu::Sei() { cycles.count += cycles.clock[1]; if (!flags.i) { flags.i = Flags::I; interrupt.irqClock = CYCLE_MAX; if (interrupt.low) DoISR( IRQ_VECTOR ); } } NST_SINGLE_CALL void Cpu::Cli() { cycles.count += cycles.clock[1]; if (flags.i) { flags.i = 0; NST_VERIFY( interrupt.irqClock == CYCLE_MAX ); if (interrupt.low) { interrupt.irqClock = cycles.count + 1; cycles.NextRound( interrupt.irqClock ); } } } //////////////////////////////////////////////////////////////////////////////////////// // stack operations //////////////////////////////////////////////////////////////////////////////////////// NST_SINGLE_CALL void Cpu::Pha() { cycles.count += cycles.clock[PHA_CYCLES-1]; Push8( a ); } NST_SINGLE_CALL void Cpu::Php() { // 6502 trap, B flag joins the club cycles.count += cycles.clock[PHP_CYCLES-1]; Push8( flags.Pack() | Flags::B ); } NST_SINGLE_CALL void Cpu::Pla() { cycles.count += cycles.clock[PLA_CYCLES-1]; a = Pull8(); flags.nz = a; } NST_SINGLE_CALL void Cpu::Plp() { cycles.count += cycles.clock[PLP_CYCLES-1]; const uint i = flags.i; flags.Unpack( Pull8() ); if (interrupt.low) { if (i > flags.i) { interrupt.irqClock = cycles.count + 1; cycles.NextRound( interrupt.irqClock ); } else if (i < flags.i) { interrupt.irqClock = CYCLE_MAX; DoISR( IRQ_VECTOR ); } } } NST_SINGLE_CALL void Cpu::Tsx() { cycles.count += cycles.clock[1]; x = sp; flags.nz = sp; } NST_SINGLE_CALL void Cpu::Txs() { cycles.count += cycles.clock[1]; sp = x; } //////////////////////////////////////////////////////////////////////////////////////// // undocumented instructions, rarely used //////////////////////////////////////////////////////////////////////////////////////// #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif NST_NO_INLINE void Cpu::Anc(const uint data) { a &= data; flags.nz = a; flags.c = flags.nz >> 7; NotifyOp("ANC",1UL << 0); } NST_SINGLE_CALL void Cpu::Ane(const uint data) { a = (a | 0xEE) & x & data; flags.nz = a; NotifyOp("ANE",1UL << 1); } NST_SINGLE_CALL void Cpu::Arr(const uint data) { a = ((data & a) >> 1) | (flags.c << 7); flags.nz = a; flags.c = a >> 6 & 0x1; flags.v = (a >> 6 ^ a >> 5) & 0x1; NotifyOp("ARR",1UL << 2); } NST_SINGLE_CALL void Cpu::Asr(const uint data) { flags.c = data & a & 0x1; a = (data & a) >> 1; flags.nz = a; NotifyOp("ASR",1UL << 3); } NST_NO_INLINE uint Cpu::Dcp(uint data) { data = (data - 1) & 0xFF; Cmp( data ); NotifyOp("DCP",1UL << 4); return data; } NST_NO_INLINE uint Cpu::Isb(uint data) { data = (data + 1) & 0xFF; Sbc( data ); NotifyOp("ISB",1UL << 5); return data; } NST_SINGLE_CALL void Cpu::Las(const uint data) { sp &= data; x = sp; a = sp; flags.nz = sp; NotifyOp("LAS",1UL << 6); } NST_NO_INLINE void Cpu::Lax(const uint data) { a = data; x = data; flags.nz = data; NotifyOp("LAX",1UL << 7); } NST_SINGLE_CALL void Cpu::Lxa(const uint data) { a = data; x = data; flags.nz = data; NotifyOp("LXA",1UL << 8); } NST_NO_INLINE uint Cpu::Rla(uint data) { const uint carry = flags.c; flags.c = data >> 7; data = (data << 1 & 0xFF) | carry; a &= data; flags.nz = a; NotifyOp("RLA",1UL << 9); return data; } NST_NO_INLINE uint Cpu::Rra(uint data) { const uint carry = flags.c << 7; flags.c = data & 0x01; data = (data >> 1) | carry; Adc( data ); NotifyOp("RRA",1UL << 10); return data; } NST_NO_INLINE uint Cpu::Sax() { const uint data = a & x; NotifyOp("SAX",1UL << 11); return data; } NST_SINGLE_CALL void Cpu::Sbx(uint data) { data = (a & x) - data; flags.c = (data <= 0xFF); x = data & 0xFF; flags.nz = x; NotifyOp("SBX",1UL << 12); } NST_NO_INLINE uint Cpu::Sha(uint address) { address = a & x & ((address >> 8) + 1); NotifyOp("SHA",1UL << 13); return address; } NST_SINGLE_CALL uint Cpu::Shs(uint address) { sp = a & x; address = sp & ((address >> 8) + 1); NotifyOp("SHS",1UL << 14); return address; } NST_SINGLE_CALL void Cpu::Shx(uint address) { uint newaddress = (address + y); uint data = x & ((address >> 8) + 1); Peek((address & 0xFF00) | (newaddress & 0x00FF)); // Dummy read if ((address ^ newaddress) & 0x100) { address = (newaddress & (x << 8)) | (newaddress & 0x00FF); } else { address = newaddress; } NotifyOp("SHX",1UL << 15); StoreMem(address, data); } NST_SINGLE_CALL void Cpu::Shy(uint address) { uint newaddress = (address + x); uint data = y & ((address >> 8) + 1); Peek((address & 0xFF00) | (newaddress & 0x00FF)); // Dummy read if ((address ^ newaddress) & 0x100) { address = (newaddress & (y << 8)) | (newaddress & 0x00FF); } else { address = newaddress; } NotifyOp("SHY",1UL << 16); StoreMem(address, data); } NST_NO_INLINE uint Cpu::Slo(uint data) { flags.c = data >> 7; data = data << 1 & 0xFF; a |= data; flags.nz = a; NotifyOp("SLO",1UL << 17); return data; } NST_NO_INLINE uint Cpu::Sre(uint data) { flags.c = data & 0x01; data >>= 1; a ^= data; flags.nz = a; NotifyOp("SRE",1UL << 18); return data; } void Cpu::Dop() { NotifyOp("DOP",1UL << 19); } void Cpu::Top(uint=0) { NotifyOp("TOP",1UL << 20); } //////////////////////////////////////////////////////////////////////////////////////// // interrupts //////////////////////////////////////////////////////////////////////////////////////// NST_SINGLE_CALL void Cpu::Brk() { NST_DEBUG_MSG("6502 BRK"); opcode = map.Peek8( pc ); Push16( pc + 1 ); Push8( flags.Pack() | Flags::B ); flags.i = Flags::I; NST_VERIFY_MSG(interrupt.irqClock == CYCLE_MAX,"BRK -> IRQ collision!"); interrupt.irqClock = CYCLE_MAX; cycles.count += cycles.clock[BRK_CYCLES-1]; pc = map.Peek16( FetchIRQISRVector() ); } NST_NO_INLINE void Cpu::Jam() { // roll back and keep jamin' pc = (pc - 1) & 0xFFFF; cycles.count += cycles.clock[1]; if (!jammed) { jammed = true; interrupt.Reset(); NST_DEBUG_MSG("6502 JAM"); Api::User::eventCallback( Api::User::EVENT_CPU_JAM ); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif uint Cpu::FetchIRQISRVector() { if (cycles.count >= cycles.frame) map.Peek8( 0x3000 ); if (interrupt.nmiClock != CYCLE_MAX) { NST_DEBUG_MSG("IRQ -> NMI collision!"); if (interrupt.nmiClock + cycles.clock[1] <= cycles.count) { interrupt.nmiClock = CYCLE_MAX; return NMI_VECTOR; } interrupt.nmiClock = cycles.count + 1; } return IRQ_VECTOR; } void Cpu::DoISR(const uint vector) { NST_ASSERT( interrupt.irqClock == CYCLE_MAX ); if (!jammed) { Push16( pc ); Push8( flags.Pack() ); flags.i = Flags::I; cycles.count += cycles.clock[INT_CYCLES-1]; pc = map.Peek16( vector == NMI_VECTOR ? NMI_VECTOR : FetchIRQISRVector() ); apu.Clock(); } } void Cpu::DoIRQ(const IrqLine line,const Cycle cycle) { interrupt.low |= line; if (!flags.i && interrupt.irqClock == CYCLE_MAX) { interrupt.irqClock = cycle + cycles.InterruptEdge(); cycles.NextRound( interrupt.irqClock ); } } void Cpu::DoNMI(const Cycle cycle) { if (interrupt.nmiClock == CYCLE_MAX) { interrupt.nmiClock = cycle + cycles.InterruptEdge(); cycles.NextRound( interrupt.nmiClock ); } } //////////////////////////////////////////////////////////////////////////////////////// // main //////////////////////////////////////////////////////////////////////////////////////// void Cpu::ExecuteFrame(Sound::Output* sound) { NST_VERIFY( cycles.count < cycles.frame ); apu.BeginFrame( sound ); Clock(); switch (hooks.Size()) { case 0: Run0(); break; case 1: Run1(); break; default: Run2(); break; } } void Cpu::EndFrame() { apu.EndFrame(); for (const Hook *hook = hooks.Ptr(), *const end = hook+hooks.Size(); hook != end; ++hook) hook->Execute(); NST_ASSERT( cycles.count >= cycles.frame && interrupt.nmiClock >= cycles.frame ); cycles.count -= cycles.frame; ticks += cycles.frame; if (interrupt.nmiClock != CYCLE_MAX) interrupt.nmiClock -= cycles.frame; if (interrupt.irqClock != CYCLE_MAX) interrupt.irqClock = (interrupt.irqClock > cycles.frame ? interrupt.irqClock - cycles.frame : 0); } void Cpu::Clock() { Cycle clock = apu.Clock(); if (clock > cycles.frame) clock = cycles.frame; if (cycles.count < interrupt.nmiClock) { if (clock > interrupt.nmiClock) clock = interrupt.nmiClock; if (cycles.count < interrupt.irqClock) { if (clock > interrupt.irqClock) clock = interrupt.irqClock; } else { interrupt.irqClock = CYCLE_MAX; DoISR( IRQ_VECTOR ); } } else { NST_VERIFY( interrupt.irqClock == CYCLE_MAX ); interrupt.nmiClock = CYCLE_MAX; interrupt.irqClock = CYCLE_MAX; DoISR( NMI_VECTOR ); } cycles.round = clock; } inline void Cpu::ExecuteOp() { cycles.offset = cycles.count; (*this.*opcodes[opcode=FetchPc8()])(); } void Cpu::Run0() { do { do { ExecuteOp(); } while (cycles.count < cycles.round); Clock(); } while (cycles.count < cycles.frame); } void Cpu::Run1() { const Hook hook( *hooks.Ptr() ); do { do { ExecuteOp(); hook.Execute(); } while (cycles.count < cycles.round); Clock(); } while (cycles.count < cycles.frame); } void Cpu::Run2() { const Hook* const first = hooks.Ptr(); const Hook* const last = first + (hooks.Size() - 1); do { do { ExecuteOp(); const Hook* NST_RESTRICT hook = first; hook->Execute(); do { (++hook)->Execute(); } while (hook != last); } while (cycles.count < cycles.round); Clock(); } while (cycles.count < cycles.frame); } uint Cpu::Peek(const uint address) const { return map.Peek8( address ); } void Cpu::Poke(const uint address,const uint data) const { return map.Poke8( address, data ); } //////////////////////////////////////////////////////////////////////////////////////// // opcodes //////////////////////////////////////////////////////////////////////////////////////// #define StoreZpgX(a_,d_) StoreZpg(a_,d_) #define StoreZpgY(a_,d_) StoreZpg(a_,d_) #define StoreAbs(a_,d_) StoreMem(a_,d_) #define StoreAbsX(a_,d_) StoreMem(a_,d_) #define StoreAbsY(a_,d_) StoreMem(a_,d_) #define StoreIndX(a_,d_) StoreMem(a_,d_) #define StoreIndY(a_,d_) StoreMem(a_,d_) #define NES_I____(instr_,hex_) \ \ void Cpu::op##hex_() \ { \ instr_(); \ } #define NES____C_(nop_,ticks_,hex_) \ \ void Cpu::op##hex_() \ { \ cycles.count += cycles.clock[ticks_ - 1]; \ } #define NES_IR___(instr_,addr_,hex_) \ \ void Cpu::op##hex_() \ { \ instr_( addr_##_R() ); \ } #define NES_I_W__(instr_,addr_,hex_) \ \ void Cpu::op##hex_() \ { \ const uint dst = addr_##_W(); \ Store##addr_( dst, instr_() ); \ } #define NES_IRW__(instr_,addr_,hex_) \ \ void Cpu::op##hex_() \ { \ uint data; \ const uint dst = addr_##_RW( data ); \ Store##addr_( dst, instr_(data) ); \ } #define NES_IRA__(instr_,hex_) \ \ void Cpu::op##hex_() \ { \ cycles.count += cycles.clock[1]; \ a = instr_( a ); \ } #define NES_I_W_A(instr_,addr_,hex_) \ \ void Cpu::op##hex_() \ { \ const uint dst = addr_##_W(); \ Store##addr_( dst, instr_(dst) ); \ } // Unofficial Opcodes SHX/SHY are edge cases #define NES_I_W_U(instr_,addr_,hex_) \ \ void Cpu::op##hex_() \ { \ const uint dst = addr_##_W(); \ instr_(dst); \ } #define NES_IP_C_(instr_,ops_,ticks_,hex_) \ \ void Cpu::op##hex_() \ { \ pc += ops_; \ cycles.count += cycles.clock[ticks_ - 1]; \ instr_(); \ } // param 1 = instruction // param 2 = addressing mode // param 3 = cycles // param 4 = opcode NES_IR___( Adc, Imm, 0x69 ) NES_IR___( Adc, Zpg, 0x65 ) NES_IR___( Adc, ZpgX, 0x75 ) NES_IR___( Adc, Abs, 0x6D ) NES_IR___( Adc, AbsX, 0x7D ) NES_IR___( Adc, AbsY, 0x79 ) NES_IR___( Adc, IndX, 0x61 ) NES_IR___( Adc, IndY, 0x71 ) NES_IR___( And, Imm, 0x29 ) NES_IR___( And, Zpg, 0x25 ) NES_IR___( And, ZpgX, 0x35 ) NES_IR___( And, Abs, 0x2D ) NES_IR___( And, AbsX, 0x3D ) NES_IR___( And, AbsY, 0x39 ) NES_IR___( And, IndX, 0x21 ) NES_IR___( And, IndY, 0x31 ) NES_IRA__( Asl, 0x0A ) NES_IRW__( Asl, Zpg, 0x06 ) NES_IRW__( Asl, ZpgX, 0x16 ) NES_IRW__( Asl, Abs, 0x0E ) NES_IRW__( Asl, AbsX, 0x1E ) NES_I____( Bcc, 0x90 ) NES_I____( Bcs, 0xB0 ) NES_I____( Beq, 0xF0 ) NES_IR___( Bit, Zpg, 0x24 ) NES_IR___( Bit, Abs, 0x2C ) NES_I____( Bmi, 0x30 ) NES_I____( Bne, 0xD0 ) NES_I____( Bpl, 0x10 ) NES_I____( Bvc, 0x50 ) NES_I____( Bvs, 0x70 ) NES_I____( Clc, 0x18 ) NES_I____( Cld, 0xD8 ) NES_I____( Cli, 0x58 ) NES_I____( Clv, 0xB8 ) NES_IR___( Cmp, Imm, 0xC9 ) NES_IR___( Cmp, Zpg, 0xC5 ) NES_IR___( Cmp, ZpgX, 0xD5 ) NES_IR___( Cmp, Abs, 0xCD ) NES_IR___( Cmp, AbsX, 0xDD ) NES_IR___( Cmp, AbsY, 0xD9 ) NES_IR___( Cmp, IndX, 0xC1 ) NES_IR___( Cmp, IndY, 0xD1 ) NES_IR___( Cpx, Imm, 0xE0 ) NES_IR___( Cpx, Zpg, 0xE4 ) NES_IR___( Cpx, Abs, 0xEC ) NES_IR___( Cpy, Imm, 0xC0 ) NES_IR___( Cpy, Zpg, 0xC4 ) NES_IR___( Cpy, Abs, 0xCC ) NES_IRW__( Dec, Zpg, 0xC6 ) NES_IRW__( Dec, ZpgX, 0xD6 ) NES_IRW__( Dec, Abs, 0xCE ) NES_IRW__( Dec, AbsX, 0xDE ) NES_I____( Dex, 0xCA ) NES_I____( Dey, 0x88 ) NES_IR___( Eor, Imm, 0x49 ) NES_IR___( Eor, Zpg, 0x45 ) NES_IR___( Eor, ZpgX, 0x55 ) NES_IR___( Eor, Abs, 0x4D ) NES_IR___( Eor, AbsX, 0x5D ) NES_IR___( Eor, AbsY, 0x59 ) NES_IR___( Eor, IndX, 0x41 ) NES_IR___( Eor, IndY, 0x51 ) NES_IRW__( Inc, Zpg, 0xE6 ) NES_IRW__( Inc, ZpgX, 0xF6 ) NES_IRW__( Inc, Abs, 0xEE ) NES_IRW__( Inc, AbsX, 0xFE ) NES_I____( Inx, 0xE8 ) NES_I____( Iny, 0xC8 ) NES_I____( JmpAbs, 0x4C ) NES_I____( JmpInd, 0x6C ) NES_I____( Jsr, 0x20 ) NES_IR___( Lda, Imm, 0xA9 ) NES_IR___( Lda, Zpg, 0xA5 ) NES_IR___( Lda, ZpgX, 0xB5 ) NES_IR___( Lda, Abs, 0xAD ) NES_IR___( Lda, AbsX, 0xBD ) NES_IR___( Lda, AbsY, 0xB9 ) NES_IR___( Lda, IndX, 0xA1 ) NES_IR___( Lda, IndY, 0xB1 ) NES_IR___( Ldx, Imm, 0xA2 ) NES_IR___( Ldx, Zpg, 0xA6 ) NES_IR___( Ldx, ZpgY, 0xB6 ) NES_IR___( Ldx, Abs, 0xAE ) NES_IR___( Ldx, AbsY, 0xBE ) NES_IR___( Ldy, Imm, 0xA0 ) NES_IR___( Ldy, Zpg, 0xA4 ) NES_IR___( Ldy, ZpgX, 0xB4 ) NES_IR___( Ldy, Abs, 0xAC ) NES_IR___( Ldy, AbsX, 0xBC ) NES_IRA__( Lsr, 0x4A ) NES_IRW__( Lsr, Zpg, 0x46 ) NES_IRW__( Lsr, ZpgX, 0x56 ) NES_IRW__( Lsr, Abs, 0x4E ) NES_IRW__( Lsr, AbsX, 0x5E ) NES____C_( Nop, 2, 0x1A ) NES____C_( Nop, 2, 0x3A ) NES____C_( Nop, 2, 0x5A ) NES____C_( Nop, 2, 0x7A ) NES____C_( Nop, 2, 0xDA ) NES____C_( Nop, 2, 0xEA ) NES____C_( Nop, 2, 0xFA ) NES_IR___( Ora, Imm, 0x09 ) NES_IR___( Ora, Zpg, 0x05 ) NES_IR___( Ora, ZpgX, 0x15 ) NES_IR___( Ora, Abs, 0x0D ) NES_IR___( Ora, AbsX, 0x1D ) NES_IR___( Ora, AbsY, 0x19 ) NES_IR___( Ora, IndX, 0x01 ) NES_IR___( Ora, IndY, 0x11 ) NES_I____( Pha, 0x48 ) NES_I____( Php, 0x08 ) NES_I____( Pla, 0x68 ) NES_I____( Plp, 0x28 ) NES_IRA__( Rol, 0x2A ) NES_IRW__( Rol, Zpg, 0x26 ) NES_IRW__( Rol, ZpgX, 0x36 ) NES_IRW__( Rol, Abs, 0x2E ) NES_IRW__( Rol, AbsX, 0x3E ) NES_IRA__( Ror, 0x6A ) NES_IRW__( Ror, Zpg, 0x66 ) NES_IRW__( Ror, ZpgX, 0x76 ) NES_IRW__( Ror, Abs, 0x6E ) NES_IRW__( Ror, AbsX, 0x7E ) NES_I____( Rti, 0x40 ) NES_I____( Rts, 0x60 ) NES_IR___( Sbc, Imm, 0xE9 ) NES_IR___( Sbc, Imm, 0xEB ) NES_IR___( Sbc, Zpg, 0xE5 ) NES_IR___( Sbc, ZpgX, 0xF5 ) NES_IR___( Sbc, Abs, 0xED ) NES_IR___( Sbc, AbsX, 0xFD ) NES_IR___( Sbc, AbsY, 0xF9 ) NES_IR___( Sbc, IndX, 0xE1 ) NES_IR___( Sbc, IndY, 0xF1 ) NES_I____( Sec, 0x38 ) NES_I____( Sed, 0xF8 ) NES_I____( Sei, 0x78 ) NES_I_W__( Sta, Zpg, 0x85 ) NES_I_W__( Sta, ZpgX, 0x95 ) NES_I_W__( Sta, Abs, 0x8D ) NES_I_W__( Sta, AbsX, 0x9D ) NES_I_W__( Sta, AbsY, 0x99 ) NES_I_W__( Sta, IndX, 0x81 ) NES_I_W__( Sta, IndY, 0x91 ) NES_I_W__( Stx, Zpg, 0x86 ) NES_I_W__( Stx, ZpgY, 0x96 ) NES_I_W__( Stx, Abs, 0x8E ) NES_I_W__( Sty, Zpg, 0x84 ) NES_I_W__( Sty, ZpgX, 0x94 ) NES_I_W__( Sty, Abs, 0x8C ) NES_I____( Tax, 0xAA ) NES_I____( Tay, 0xA8 ) NES_I____( Tsx, 0xBA ) NES_I____( Txa, 0x8A ) NES_I____( Txs, 0x9A ) NES_I____( Tya, 0x98 ) #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif // rarely executed NES_I____( Brk, 0x00 ) NES_I____( Jam, 0x02 ) NES_I____( Jam, 0x12 ) NES_I____( Jam, 0x22 ) NES_I____( Jam, 0x32 ) NES_I____( Jam, 0x42 ) NES_I____( Jam, 0x52 ) NES_I____( Jam, 0x62 ) NES_I____( Jam, 0x72 ) NES_I____( Jam, 0x92 ) NES_I____( Jam, 0xB2 ) NES_I____( Jam, 0xD2 ) NES_I____( Jam, 0xF2 ) // unofficial ops NES_IR___( Anc, Imm, 0x0B ) NES_IR___( Anc, Imm, 0x2B ) NES_IR___( Ane, Imm, 0x8B ) NES_IR___( Arr, Imm, 0x6B ) NES_IR___( Asr, Imm, 0x4B ) NES_IRW__( Dcp, Zpg, 0xC7 ) NES_IRW__( Dcp, ZpgX, 0xD7 ) NES_IRW__( Dcp, IndX, 0xC3 ) NES_IRW__( Dcp, IndY, 0xD3 ) NES_IRW__( Dcp, Abs, 0xCF ) NES_IRW__( Dcp, AbsX, 0xDF ) NES_IRW__( Dcp, AbsY, 0xDB ) NES_IP_C_( Dop, 1, 2, 0x80 ) NES_IP_C_( Dop, 1, 2, 0x82 ) NES_IP_C_( Dop, 1, 2, 0x89 ) NES_IP_C_( Dop, 1, 2, 0xC2 ) NES_IP_C_( Dop, 1, 2, 0xE2 ) NES_IP_C_( Dop, 1, 3, 0x04 ) NES_IP_C_( Dop, 1, 3, 0x44 ) NES_IP_C_( Dop, 1, 3, 0x64 ) NES_IP_C_( Dop, 1, 4, 0x14 ) NES_IP_C_( Dop, 1, 4, 0x34 ) NES_IP_C_( Dop, 1, 4, 0x54 ) NES_IP_C_( Dop, 1, 4, 0x74 ) NES_IP_C_( Dop, 1, 4, 0xD4 ) NES_IP_C_( Dop, 1, 4, 0xF4 ) NES_IRW__( Isb, Zpg, 0xE7 ) NES_IRW__( Isb, ZpgX, 0xF7 ) NES_IRW__( Isb, Abs, 0xEF ) NES_IRW__( Isb, AbsX, 0xFF ) NES_IRW__( Isb, AbsY, 0xFB ) NES_IRW__( Isb, IndX, 0xE3 ) NES_IRW__( Isb, IndY, 0xF3 ) NES_IR___( Las, AbsY, 0xBB ) NES_IR___( Lax, Zpg, 0xA7 ) NES_IR___( Lax, ZpgY, 0xB7 ) NES_IR___( Lax, Abs, 0xAF ) NES_IR___( Lax, AbsY, 0xBF ) NES_IR___( Lax, IndX, 0xA3 ) NES_IR___( Lax, IndY, 0xB3 ) NES_IR___( Lxa, Imm, 0xAB ) NES_IRW__( Rla, Zpg, 0x27 ) NES_IRW__( Rla, ZpgX, 0x37 ) NES_IRW__( Rla, Abs, 0x2F ) NES_IRW__( Rla, AbsX, 0x3F ) NES_IRW__( Rla, AbsY, 0x3B ) NES_IRW__( Rla, IndX, 0x23 ) NES_IRW__( Rla, IndY, 0x33 ) NES_IRW__( Rra, Zpg, 0x67 ) NES_IRW__( Rra, ZpgX, 0x77 ) NES_IRW__( Rra, Abs, 0x6F ) NES_IRW__( Rra, AbsX, 0x7F ) NES_IRW__( Rra, AbsY, 0x7B ) NES_IRW__( Rra, IndX, 0x63 ) NES_IRW__( Rra, IndY, 0x73 ) NES_I_W__( Sax, Zpg, 0x87 ) NES_I_W__( Sax, ZpgY, 0x97 ) NES_I_W__( Sax, Abs, 0x8F ) NES_I_W__( Sax, IndX, 0x83 ) NES_IR___( Sbx, Imm, 0xCB ) NES_I_W_A( Sha, AbsY, 0x9F ) NES_I_W_A( Sha, IndY, 0x93 ) NES_I_W_A( Shs, AbsY, 0x9B ) NES_I_W_U( Shx, Abs, 0x9E ) // Edge case: AbsY done internally NES_I_W_U( Shy, Abs, 0x9C ) // Edge case: AbsX done internally NES_IRW__( Slo, Zpg, 0x07 ) NES_IRW__( Slo, ZpgX, 0x17 ) NES_IRW__( Slo, Abs, 0x0F ) NES_IRW__( Slo, AbsX, 0x1F ) NES_IRW__( Slo, AbsY, 0x1B ) NES_IRW__( Slo, IndX, 0x03 ) NES_IRW__( Slo, IndY, 0x13 ) NES_IRW__( Sre, Zpg, 0x47 ) NES_IRW__( Sre, ZpgX, 0x57 ) NES_IRW__( Sre, Abs, 0x4F ) NES_IRW__( Sre, AbsX, 0x5F ) NES_IRW__( Sre, AbsY, 0x5B ) NES_IRW__( Sre, IndX, 0x43 ) NES_IRW__( Sre, IndY, 0x53 ) NES_IP_C_( Top, 2, 4, 0x0C ) NES_IR___( Top, AbsX, 0x1C ) NES_IR___( Top, AbsX, 0x3C ) NES_IR___( Top, AbsX, 0x5C ) NES_IR___( Top, AbsX, 0x7C ) NES_IR___( Top, AbsX, 0xDC ) NES_IR___( Top, AbsX, 0xFC ) #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif #undef StoreZpgX #undef StoreZpgY #undef StoreAbs #undef StoreAbsX #undef StoreAbsY #undef StoreIndX #undef StoreIndY #undef NES_I____ #undef NES____C_ #undef NES_IR___ #undef NES_I_W__ #undef NES_IRW__ #undef NES_IRA__ #undef NES_I_W_A #undef NES_IP_C_ } } nestopia-1.51.1/source/core/NstCpu.hpp000066400000000000000000000362441411157722000176070ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_CPU_H #define NST_CPU_H #include "NstAssert.hpp" #include "NstIoMap.hpp" #include "NstApu.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class Hook; class Cpu { public: Cpu(); enum { CYCLE_MAX = Cycle(~0UL), RAM_SIZE = SIZE_2K }; enum IrqLine { IRQ_EXT = 0x01, IRQ_FRAME = 0x40, IRQ_DMC = 0x80 }; enum Level { LEVEL_LOW = 1, LEVEL_HIGH = 9, LEVEL_HIGHEST = 10 }; void Reset(bool); void SetRamPowerState(uint); void Boot(bool); void ExecuteFrame(Sound::Output*); void EndFrame(); void PowerOff(); void DoNMI(Cycle); void DoIRQ(IrqLine,Cycle); uint Peek(uint) const; void Poke(uint,uint) const; bool IsOddCycle() const; bool IsWriteCycle(Cycle) const; Cycle GetClockBase() const; uint GetClockDivider() const; dword GetTime(Cycle) const; dword GetFps() const; void SetModel(CpuModel); void AddHook(const Hook&); void RemoveHook(const Hook&); void SaveState(State::Saver&,dword,dword) const; void LoadState(State::Loader&,dword,dword,dword); private: static void NotifyOp(const char (&)[4],dword); enum { NMI_VECTOR = 0xFFFA, RESET_VECTOR = 0xFFFC, IRQ_VECTOR = 0xFFFE, RESET_CYCLES = 7, INT_CYCLES = 7, BRK_CYCLES = 7, RTI_CYCLES = 6, RTS_CYCLES = 6, PHA_CYCLES = 3, PHP_CYCLES = 3, PLA_CYCLES = 4, PLP_CYCLES = 4, JSR_CYCLES = 6, JMP_ABS_CYCLES = 3, JMP_IND_CYCLES = 5 }; void Reset(bool,bool); NES_DECL_POKE( Nop ); NES_DECL_PEEK( Nop ); NES_DECL_POKE( Overflow ); NES_DECL_PEEK( Overflow ); NES_DECL_PEEK( Jam_1 ); NES_DECL_PEEK( Jam_2 ); void DoISR(uint); uint FetchIRQISRVector(); void Clock(); void Run0(); void Run1(); void Run2(); inline void ExecuteOp(); inline uint FetchPc8(); inline uint FetchPc16(); inline uint FetchZpg16(uint) const; inline void Push8(uint); NST_FORCE_INLINE void Push16(uint); inline uint Pull8(); inline uint Pull16(); inline uint ZpgReg_R (uint); inline uint ZpgReg_RW (uint&,uint); inline uint ZpgReg_W (uint); uint AbsReg_R (uint); uint AbsReg_RW (uint&,uint); NST_FORCE_INLINE uint AbsReg_W (uint); template NST_FORCE_INLINE void Branch(uint); inline uint Imm_R (); inline uint Zpg_R (); inline uint ZpgX_R (); inline uint ZpgY_R (); uint Abs_R (); inline uint AbsX_R (); inline uint AbsY_R (); uint IndX_R (); uint IndY_R (); inline uint Zpg_RW (uint&); inline uint ZpgX_RW (uint&); inline uint ZpgY_RW (uint&); uint Abs_RW (uint&); inline uint AbsY_RW (uint&); inline uint AbsX_RW (uint&); inline uint IndX_RW (uint&); inline uint IndY_RW (uint&); inline uint Zpg_W (); inline uint ZpgX_W (); inline uint ZpgY_W (); inline uint Abs_W (); NST_FORCE_INLINE uint AbsX_W (); NST_FORCE_INLINE uint AbsY_W (); inline uint IndX_W (); NST_FORCE_INLINE uint IndY_W (); inline void StoreMem (uint,uint); inline void StoreZpg (uint,uint); inline void Lda (uint); inline void Ldx (uint); inline void Ldy (uint); inline uint Sta() const; inline uint Stx() const; inline uint Sty() const; NST_SINGLE_CALL void Tax (); NST_SINGLE_CALL void Tay (); NST_SINGLE_CALL void Txa (); NST_SINGLE_CALL void Tya (); NST_SINGLE_CALL void JmpAbs (); NST_SINGLE_CALL void JmpInd (); NST_SINGLE_CALL void Jsr (); NST_SINGLE_CALL void Rts (); NST_SINGLE_CALL void Rti (); NST_SINGLE_CALL void Bcc (); NST_SINGLE_CALL void Bcs (); NST_SINGLE_CALL void Beq (); NST_SINGLE_CALL void Bmi (); NST_SINGLE_CALL void Bne (); NST_SINGLE_CALL void Bpl (); NST_SINGLE_CALL void Bvc (); NST_SINGLE_CALL void Bvs (); inline void Adc (uint); inline void Sbc (uint); inline void And (uint); inline void Ora (uint); inline void Eor (uint); inline void Bit (uint); inline void Cmp (uint); inline void Cpx (uint); inline void Cpy (uint); inline uint Asl (uint); inline uint Lsr (uint); inline uint Rol (uint); inline uint Ror (uint); inline uint Dec (uint); inline uint Inc (uint); NST_SINGLE_CALL void Dex (); NST_SINGLE_CALL void Dey (); NST_SINGLE_CALL void Inx (); NST_SINGLE_CALL void Iny (); NST_SINGLE_CALL void Clc (); NST_SINGLE_CALL void Cld (); NST_SINGLE_CALL void Clv (); NST_SINGLE_CALL void Sec (); NST_SINGLE_CALL void Sed (); NST_SINGLE_CALL void Sei (); NST_SINGLE_CALL void Cli (); NST_SINGLE_CALL void Php (); NST_SINGLE_CALL void Plp (); NST_SINGLE_CALL void Pha (); NST_SINGLE_CALL void Pla (); NST_SINGLE_CALL void Tsx (); NST_SINGLE_CALL void Txs (); NST_SINGLE_CALL void Ane (uint); NST_SINGLE_CALL void Arr (uint); NST_SINGLE_CALL void Asr (uint); NST_SINGLE_CALL void Las (uint); NST_SINGLE_CALL void Lxa (uint); NST_SINGLE_CALL void Sbx (uint); NST_SINGLE_CALL uint Shs (uint); NST_SINGLE_CALL void Shx (uint); NST_SINGLE_CALL void Shy (uint); NST_NO_INLINE void Anc (uint); NST_NO_INLINE uint Dcp (uint); NST_NO_INLINE uint Isb (uint); NST_NO_INLINE void Lax (uint); NST_NO_INLINE uint Rla (uint); NST_NO_INLINE uint Rra (uint); NST_NO_INLINE uint Sax (); NST_NO_INLINE uint Sha (uint); NST_NO_INLINE uint Slo (uint); NST_NO_INLINE uint Sre (uint); void Dop (); void Top (uint); NST_SINGLE_CALL void Brk (); NST_NO_INLINE void Jam (); void op0x00(); void op0x01(); void op0x02(); void op0x03(); void op0x04(); void op0x05(); void op0x06(); void op0x07(); void op0x08(); void op0x09(); void op0x0A(); void op0x0B(); void op0x0C(); void op0x0D(); void op0x0E(); void op0x0F(); void op0x10(); void op0x11(); void op0x12(); void op0x13(); void op0x14(); void op0x15(); void op0x16(); void op0x17(); void op0x18(); void op0x19(); void op0x1A(); void op0x1B(); void op0x1C(); void op0x1D(); void op0x1E(); void op0x1F(); void op0x20(); void op0x21(); void op0x22(); void op0x23(); void op0x24(); void op0x25(); void op0x26(); void op0x27(); void op0x28(); void op0x29(); void op0x2A(); void op0x2B(); void op0x2C(); void op0x2D(); void op0x2E(); void op0x2F(); void op0x30(); void op0x31(); void op0x32(); void op0x33(); void op0x34(); void op0x35(); void op0x36(); void op0x37(); void op0x38(); void op0x39(); void op0x3A(); void op0x3B(); void op0x3C(); void op0x3D(); void op0x3E(); void op0x3F(); void op0x40(); void op0x41(); void op0x42(); void op0x43(); void op0x44(); void op0x45(); void op0x46(); void op0x47(); void op0x48(); void op0x49(); void op0x4A(); void op0x4B(); void op0x4C(); void op0x4D(); void op0x4E(); void op0x4F(); void op0x50(); void op0x51(); void op0x52(); void op0x53(); void op0x54(); void op0x55(); void op0x56(); void op0x57(); void op0x58(); void op0x59(); void op0x5A(); void op0x5B(); void op0x5C(); void op0x5D(); void op0x5E(); void op0x5F(); void op0x60(); void op0x61(); void op0x62(); void op0x63(); void op0x64(); void op0x65(); void op0x66(); void op0x67(); void op0x68(); void op0x69(); void op0x6A(); void op0x6B(); void op0x6C(); void op0x6D(); void op0x6E(); void op0x6F(); void op0x70(); void op0x71(); void op0x72(); void op0x73(); void op0x74(); void op0x75(); void op0x76(); void op0x77(); void op0x78(); void op0x79(); void op0x7A(); void op0x7B(); void op0x7C(); void op0x7D(); void op0x7E(); void op0x7F(); void op0x80(); void op0x81(); void op0x82(); void op0x83(); void op0x84(); void op0x85(); void op0x86(); void op0x87(); void op0x88(); void op0x89(); void op0x8A(); void op0x8B(); void op0x8C(); void op0x8D(); void op0x8E(); void op0x8F(); void op0x90(); void op0x91(); void op0x92(); void op0x93(); void op0x94(); void op0x95(); void op0x96(); void op0x97(); void op0x98(); void op0x99(); void op0x9A(); void op0x9B(); void op0x9C(); void op0x9D(); void op0x9E(); void op0x9F(); void op0xA0(); void op0xA1(); void op0xA2(); void op0xA3(); void op0xA4(); void op0xA5(); void op0xA6(); void op0xA7(); void op0xA8(); void op0xA9(); void op0xAA(); void op0xAB(); void op0xAC(); void op0xAD(); void op0xAE(); void op0xAF(); void op0xB0(); void op0xB1(); void op0xB2(); void op0xB3(); void op0xB4(); void op0xB5(); void op0xB6(); void op0xB7(); void op0xB8(); void op0xB9(); void op0xBA(); void op0xBB(); void op0xBC(); void op0xBD(); void op0xBE(); void op0xBF(); void op0xC0(); void op0xC1(); void op0xC2(); void op0xC3(); void op0xC4(); void op0xC5(); void op0xC6(); void op0xC7(); void op0xC8(); void op0xC9(); void op0xCA(); void op0xCB(); void op0xCC(); void op0xCD(); void op0xCE(); void op0xCF(); void op0xD0(); void op0xD1(); void op0xD2(); void op0xD3(); void op0xD4(); void op0xD5(); void op0xD6(); void op0xD7(); void op0xD8(); void op0xD9(); void op0xDA(); void op0xDB(); void op0xDC(); void op0xDD(); void op0xDE(); void op0xDF(); void op0xE0(); void op0xE1(); void op0xE2(); void op0xE3(); void op0xE4(); void op0xE5(); void op0xE6(); void op0xE7(); void op0xE8(); void op0xE9(); void op0xEA(); void op0xEB(); void op0xEC(); void op0xED(); void op0xEE(); void op0xEF(); void op0xF0(); void op0xF1(); void op0xF2(); void op0xF3(); void op0xF4(); void op0xF5(); void op0xF6(); void op0xF7(); void op0xF8(); void op0xF9(); void op0xFA(); void op0xFB(); void op0xFC(); void op0xFD(); void op0xFE(); void op0xFF(); struct Cycles { void UpdateTable(CpuModel); inline uint InterruptEdge() const; Cycle count; byte clock[8]; Cycle offset; Cycle round; Cycle frame; void NextRound(Cycle next) { if (round > next) round = next; } }; struct Flags { uint Pack() const; void Unpack(uint); enum { C = 0x01, // carry Z = 0x02, // zero I = 0x04, // interrupt enable/disable D = 0x08, // decimal mode (not supported on the N2A03) B = 0x10, // software interrupt R = 0x20, // unused but always set V = 0x40, // overflow N = 0x80 // negative }; uint nz; uint c; uint v; uint i; uint d; }; struct Interrupt { void Reset(); Cycle nmiClock; Cycle irqClock; uint low; }; class Hooks { public: Hooks(); ~Hooks(); void Add(const Hook&); void Remove(const Hook&); void Clear(); inline uint Size() const; inline const Hook* Ptr() const; private: Hook* hooks; word size; word capacity; }; struct Ram { typedef byte (&Ref)[RAM_SIZE]; typedef const byte (&ConstRef)[RAM_SIZE]; void Reset(CpuModel); NES_DECL_PEEK( Ram_0 ); NES_DECL_POKE( Ram_0 ); NES_DECL_PEEK( Ram_1 ); NES_DECL_POKE( Ram_1 ); NES_DECL_PEEK( Ram_2 ); NES_DECL_POKE( Ram_2 ); NES_DECL_PEEK( Ram_3 ); NES_DECL_POKE( Ram_3 ); byte mem[RAM_SIZE]; byte powerstate; }; struct IoMap : Io::Map { template IoMap(Cpu*,T,U); inline uint Peek8(uint) const; inline uint Peek16(uint) const; inline void Poke8(uint,uint) const; }; class Linker { struct Chain : Io::Port { Chain(const Port&,uint,uint=0); uint address; uint level; Chain* next; }; Chain* chain; public: Linker(); ~Linker(); void Clear(); const Io::Port* Add(Address,uint,const Io::Port&,IoMap&); void Remove(Address,const Io::Port&,IoMap&); }; uint pc; Cycles cycles; uint a; uint x; uint y; uint sp; Flags flags; Interrupt interrupt; Hooks hooks; uint opcode; word jammed; word model; Linker linker; qaword ticks; Ram ram; Apu apu; IoMap map; static dword logged; static void (Cpu::*const opcodes[0x100])(); static const byte writeClocks[0x100]; public: Apu& GetApu() { return apu; } Cycle Update(uint readAddress=0) { apu.ClockDMA( readAddress ); return cycles.count; } void DoIRQ(IrqLine line=IRQ_EXT) { DoIRQ( line, cycles.count ); } void ClearIRQ(IrqLine line=IRQ_EXT) { NST_VERIFY( interrupt.irqClock == CYCLE_MAX ); interrupt.low &= line ^ uint(IRQ_EXT|IRQ_FRAME|IRQ_DMC); if (!interrupt.low) interrupt.irqClock = CYCLE_MAX; } uint GetIRQ() const { return interrupt.low; } CpuModel GetModel() const { return static_cast(model); } Region GetRegion() const { return model == CPU_RP2A03 ? REGION_NTSC : REGION_PAL; } Cycle GetClock(uint count=1) const { NST_ASSERT( count >= 1 && count <= 8 ); return cycles.clock[count-1]; } Cycle GetCycles() const { return cycles.count; } void StealCycles(Cycle count) { cycles.count += count; } Cycle GetFrameCycles() const { return cycles.frame; } void SetFrameCycles(Cycle count) { cycles.frame = count; cycles.NextRound( count ); } Ram::Ref GetRam() { return ram.mem; } Ram::ConstRef GetRam() const { return ram.mem; } Io::Port& Map(Address address) { return map( address ); } IoMap::Section Map(Address first,Address last) { return map( first, last ); } template const Io::Port* Link(Address address,Level level,T t,U u,V v) { return linker.Add( address, level, Io::Port(t,u,v), map ); } template void Unlink(Address address,T t,U u,V v) { linker.Remove( address, Io::Port(t,u,v), map ); } }; } } #endif nestopia-1.51.1/source/core/NstCrc32.cpp000066400000000000000000000037101411157722000177170ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstCore.hpp" #include "NstCrc32.hpp" namespace Nes { namespace Core { namespace Crc32 { static dword NST_CALL Iterate(uint data,dword crc) { struct Lut { dword data[256]; Lut() { for (uint i=0; i < 256; ++i) { dword n = i; for (uint j=0; j < 8; ++j) n = (n >> 1) ^ (((~n & 1) - 1) & 0xEDB88320); data[i] = n; } } }; static const Lut lut; return (crc >> 8) ^ lut.data[(crc ^ data) & 0xFF]; } dword NST_CALL Compute(uint data,dword crc) { return Iterate( data, crc ^ 0xFFFFFFFF ) ^ 0xFFFFFFFF; } dword NST_CALL Compute(const byte* NST_RESTRICT data,const dword length,dword crc) { crc ^= 0xFFFFFFFF; for (const byte* const end=data+length; data != end; ++data) crc = Iterate( *data, crc ); crc ^= 0xFFFFFFFF; return crc; } } } } nestopia-1.51.1/source/core/NstCrc32.hpp000066400000000000000000000024621411157722000177270ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_CRC32_H #define NST_CRC32_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Crc32 { dword NST_CALL Compute(uint,dword=0); dword NST_CALL Compute(const byte* NST_RESTRICT,dword,dword=0); } } } #endif nestopia-1.51.1/source/core/NstDipSwitches.hpp000066400000000000000000000030441411157722000212760ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIPSWITCHES_H #define NST_DIPSWITCHES_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class NST_NO_VTABLE DipSwitches { protected: ~DipSwitches() {} public: virtual uint NumDips() const = 0; virtual uint NumValues(uint) const = 0; virtual cstring GetDipName(uint) const = 0; virtual cstring GetValueName(uint,uint) const = 0; virtual uint GetValue(uint) const = 0; virtual void SetValue(uint,uint) = 0; }; } } #endif nestopia-1.51.1/source/core/NstFds.cpp000066400000000000000000001275201411157722000175650ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include "NstLog.hpp" #include "NstCrc32.hpp" #include "NstState.hpp" #include "NstFds.hpp" #include "api/NstApiInput.hpp" namespace Nes { namespace Core { const byte Fds::Sound::Modulator::steps[8] = { 0x00, 0x01, 0x02, 0x04, 0x80, 0xFC, 0xFE, 0xFF }; const byte Fds::Sound::volumes[4] = { 30 * 8, 20 * 8, 15 * 8, 12 * 8 }; #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif class Fds::Bios { public: NES_DECL_PEEK( Rom ); NES_DECL_POKE( Nop ); private: enum { FAMICOM_ID = 0x5E607DCF, TWINSYSTEM_ID = 0x4DF24A6C }; byte rom[SIZE_8K]; bool available; public: Bios() : available(false) { } void Set(std::istream* const stdStream) { available = false; if (stdStream) { Stream::In(stdStream).Read( rom, SIZE_8K ); available = true; if (Log::Available()) { switch (Crc32::Compute( rom, SIZE_8K )) { case FAMICOM_ID: case TWINSYSTEM_ID: Log::Flush( "Fds: BIOS ROM ok" NST_LINEBREAK ); break; default: Log::Flush( "Fds: warning, unknown BIOS ROM!" NST_LINEBREAK ); break; } } } } Result Get(std::ostream& stream) const { if (available) { Stream::Out(&stream).Write( rom, SIZE_8K ); return RESULT_OK; } else { return RESULT_ERR_NOT_READY; } } bool Available() const { return available; } }; #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif Fds::Bios Fds::bios; NES_PEEK_A(Fds::Bios,Rom) { return rom[address - 0xE000]; } NES_POKE(Fds::Bios,Nop) { } inline byte* Fds::Disks::Sides::operator [] (uint i) const { NST_ASSERT( i < count ); return data + i * dword(SIDE_SIZE); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif inline void Fds::Adapter::Mount(byte* io,bool protect) { unit.drive.Mount( io, protect ); } Fds::Fds(Context& context) : Image (DISK), disks (context.stream), adapter (context.cpu,disks.sides), cpu (context.cpu), ppu (context.ppu), sound (context.apu), favoredSystem (context.favoredSystem) { if (!bios.Available()) throw RESULT_ERR_MISSING_BIOS; if (context.patch && context.patchResult) *context.patchResult = RESULT_ERR_UNSUPPORTED; ppu.GetChrMem().Source().Set( Core::Ram::RAM, true, true, SIZE_8K ); } Fds::~Fds() { EjectDisk(); if (!disks.writeProtected) disks.sides.Save(); } void Fds::Reset(const bool hard) { disks.mounting = 0; adapter.Reset ( cpu, disks.current == Disks::EJECTED ? NULL : disks.sides[disks.current], disks.writeProtected ); if (hard) { ram.Reset(); ppu.GetChrMem().Source().Fill( 0x00 ); ppu.GetChrMem().SwapBank( 0 ); } cpu.Map( 0x4023 ).Set( this, &Fds::Peek_Nop, &Fds::Poke_4023 ); cpu.Map( 0x4025 ).Set( this, &Fds::Peek_Nop, &Fds::Poke_4025 ); cpu.Map( 0x4026 ).Set( this, &Fds::Peek_Nop, &Fds::Poke_4026 ); cpu.Map( 0x4031 ).Set( this, &Fds::Peek_4031, &Fds::Poke_Nop ); cpu.Map( 0x4033 ).Set( this, &Fds::Peek_4033, &Fds::Poke_Nop ); cpu.Map( 0x4040, 0x407F ).Set( this, &Fds::Peek_4040, &Fds::Poke_4040 ); cpu.Map( 0x4080 ).Set( this, &Fds::Peek_Nop, &Fds::Poke_4080 ); cpu.Map( 0x4082 ).Set( this, &Fds::Peek_Nop, &Fds::Poke_4082 ); cpu.Map( 0x4083 ).Set( this, &Fds::Peek_Nop, &Fds::Poke_4083 ); cpu.Map( 0x4084 ).Set( this, &Fds::Peek_Nop, &Fds::Poke_4084 ); cpu.Map( 0x4085 ).Set( this, &Fds::Peek_Nop, &Fds::Poke_4085 ); cpu.Map( 0x4086 ).Set( this, &Fds::Peek_Nop, &Fds::Poke_4086 ); cpu.Map( 0x4087 ).Set( this, &Fds::Peek_Nop, &Fds::Poke_4087 ); cpu.Map( 0x4088 ).Set( this, &Fds::Peek_Nop, &Fds::Poke_4088 ); cpu.Map( 0x4089 ).Set( this, &Fds::Peek_Nop, &Fds::Poke_4089 ); cpu.Map( 0x408A ).Set( this, &Fds::Peek_Nop, &Fds::Poke_408A ); cpu.Map( 0x4090 ).Set( this, &Fds::Peek_4090, &Fds::Poke_Nop ); cpu.Map( 0x4092 ).Set( this, &Fds::Peek_4092, &Fds::Poke_Nop ); cpu.Map( 0x6000, 0xDFFF ).Set( &ram, &Ram::Peek_Ram, &Ram::Poke_Ram ); cpu.Map( 0xE000, 0xFFFF ).Set( &bios, &Bios::Peek_Rom, &Bios::Poke_Nop ); } bool Fds::PowerOff() { if (io.led != Api::Fds::MOTOR_OFF) { io.led = Api::Fds::MOTOR_OFF; Api::Fds::driveCallback( Api::Fds::MOTOR_OFF ); } return true; } void Fds::SetBios(std::istream* stream) { bios.Set( stream ); } Result Fds::GetBios(std::ostream& stream) { return bios.Get( stream ); } bool Fds::HasBios() { return bios.Available(); } Region Fds::GetDesiredRegion() const { return REGION_NTSC; } System Fds::GetDesiredSystem(Region region,CpuModel* cpu,PpuModel* ppu) const { if (region == REGION_NTSC) { if (cpu) *cpu = CPU_RP2A03; if (ppu) *ppu = PPU_RP2C02; return SYSTEM_FAMICOM; } else if ((region == REGION_PAL) && (favoredSystem == FAVORED_DENDY)) { if (cpu) *cpu = CPU_DENDY; if (ppu) *ppu = PPU_DENDY; return SYSTEM_DENDY; } else { return Image::GetDesiredSystem( region, cpu, ppu ); } } uint Fds::GetDesiredController(const uint port) const { if (port == Api::Input::EXPANSION_PORT) return (disks.id == DOREMIKKO_ID) ? Api::Input::DOREMIKKOKEYBOARD : Api::Input::UNCONNECTED; else return Image::GetDesiredController( port ); } uint Fds::GetDesiredAdapter() const { return Api::Input::ADAPTER_FAMICOM; } Result Fds::InsertDisk(uint disk,const uint side) { NST_VERIFY( disks.sides.count ); if (side < 2) { disk = (disk * 2) + side; if (disk < disks.sides.count) { if (disks.current != disk) { const uint prev = disks.current; disks.current = disk; disks.mounting = Disks::MOUNTING; adapter.Mount( NULL ); if (prev != Disks::EJECTED) Api::Fds::diskCallback( Api::Fds::DISK_EJECT, prev / 2, prev % 2 ); Api::Fds::diskCallback( Api::Fds::DISK_INSERT, disk / 2, disk % 2 ); return RESULT_OK; } return RESULT_NOP; } } return RESULT_ERR_INVALID_PARAM; } Result Fds::EjectDisk() { if (disks.current != Disks::EJECTED) { const uint prev = disks.current; disks.current = Disks::EJECTED; disks.mounting = 0; adapter.Mount( NULL ); Api::Fds::diskCallback( Api::Fds::DISK_EJECT, prev / 2, prev % 2 ); return RESULT_OK; } return RESULT_NOP; } Result Fds::GetDiskData(uint side,Api::Fds::DiskData& data) const { if (side < disks.sides.count) return Unit::Drive::Analyze( disks.sides[side], data ); return RESULT_ERR_INVALID_PARAM; } void Fds::LoadState(State::Loader& state) { uint saveDisks[3] = {~0U,~0U,~0U}; while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'I','O'>::V: { State::Loader::Data<4> data( state ); io.ctrl = adapter.ctrl = data[0]; io.port = data[1]; break; } case AsciiId<'R','A','M'>::V: state.Uncompress( ram.mem ); break; case AsciiId<'C','H','R'>::V: state.Uncompress( ppu.GetChrMem().Source().Mem(), SIZE_8K ); break; case AsciiId<'I','R','Q'>::V: case AsciiId<'D','R','V'>::V: adapter.LoadState( state, chunk, ppu ); break; case AsciiId<'D','S','K'>::V: { State::Loader::Data<4> data( state ); if (data[0] != disks.sides.count) throw RESULT_ERR_INVALID_FILE; saveDisks[0] = data[1]; saveDisks[1] = data[2]; saveDisks[2] = data[3]; break; } case AsciiId<'S','N','D'>::V: sound.LoadState( state ); break; default: for (uint i=0; i < disks.sides.count; ++i) { if (chunk == AsciiId<'D','0','A'>::R( 0, i / 2, i % 2 )) { byte* const data = disks.sides[i]; state.Uncompress( data, SIDE_SIZE ); for (uint j=0; j < SIDE_SIZE; ++j) data[j] ^= 0xFFU; break; } } break; } state.End(); } disks.mounting = 0; if (saveDisks[0] != ~0U) { disks.writeProtected = saveDisks[0] & 0x2U; if (saveDisks[0] & 0x1U) { if (NES_FAILED(InsertDisk( saveDisks[1] / 2, saveDisks[1] % 2 ))) throw RESULT_ERR_CORRUPT_FILE; disks.mounting = saveDisks[2]; } else { EjectDisk(); } } adapter.Mount ( disks.current != Disks::EJECTED && !disks.mounting ? disks.sides[disks.current] : NULL, disks.writeProtected ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Fds::SaveState(State::Saver& state,const dword baseChunk) const { state.Begin( baseChunk ); { const byte data[4] = { io.ctrl, io.port, 0, 0 }; state.Begin( AsciiId<'I','O'>::V ).Write( data ).End(); } adapter.SaveState( state ); state.Begin( AsciiId<'R','A','M'>::V ).Compress( ram.mem ).End(); state.Begin( AsciiId<'C','H','R'>::V ).Compress( ppu.GetChrMem().Source().Mem(), SIZE_8K ).End(); { const byte data[4] = { disks.sides.count, (disks.current != Disks::EJECTED) | (disks.writeProtected ? 0x2U : 0x0U), disks.current != Disks::EJECTED ? disks.current : 0xFF, disks.current != Disks::EJECTED ? disks.mounting : 0 }; state.Begin( AsciiId<'D','S','K'>::V ).Write( data ).End(); } bool saveData = true; if (state.Internal()) { Checksum recentChecksum; for (uint i=0; i < disks.sides.count; ++i) recentChecksum.Compute( disks.sides[i], SIDE_SIZE ); if (checksum == recentChecksum) saveData = false; else checksum = recentChecksum; } if (saveData) { struct Dst { byte* const NST_RESTRICT mem; Dst() : mem(new byte [SIDE_SIZE]) {} ~Dst() { delete [] mem; } }; Dst dst; for (uint i=0; i < disks.sides.count; ++i) { const byte* const NST_RESTRICT src = disks.sides[i]; for (uint j=0; j < SIDE_SIZE; ++j) dst.mem[j] = src[j] ^ 0xFFU; state.Begin( AsciiId<'D','0','A'>::R( 0, i / 2, i % 2 ) ).Compress( dst.mem, SIDE_SIZE ).End(); } } sound.SaveState( state, AsciiId<'S','N','D'>::V ); state.End(); } NES_PEEK(Fds,Nop) { return OPEN_BUS; } NES_POKE(Fds,Nop) { } NES_POKE_D(Fds,4023) { io.ctrl = adapter.ctrl = data; if (!(io.ctrl & Io::CTRL0_DISK_ENABLED)) { cpu.ClearIRQ(); adapter.DisableIRQ(); } } NES_POKE_D(Fds,4026) { io.port = data; } NES_PEEK(Fds,4033) { NST_VERIFY( io.port & Io::BATTERY_CHARGED ); return io.port & Io::BATTERY_CHARGED; } NES_PEEK_A(Fds,4040) { return sound.ReadWaveData( address ); } NES_POKE_AD(Fds,4040) { sound.WriteWaveData( address, data ); } NES_POKE_D(Fds,4080) { sound.WriteReg0( data ); } NES_POKE_D(Fds,4082) { sound.WriteReg1( data ); } NES_POKE_D(Fds,4083) { sound.WriteReg2( data ); } NES_POKE_D(Fds,4084) { sound.WriteReg3( data ); } NES_POKE_D(Fds,4085) { sound.WriteReg4( data ); } NES_POKE_D(Fds,4086) { sound.WriteReg5( data ); } NES_POKE_D(Fds,4087) { sound.WriteReg6( data ); } NES_POKE_D(Fds,4088) { sound.WriteReg7( data ); } NES_POKE_D(Fds,4089) { sound.WriteReg8( data ); } NES_POKE_D(Fds,408A) { sound.WriteReg9( data ); } NES_PEEK(Fds,4090) { return sound.ReadVolumeGain(); } NES_PEEK(Fds,4092) { return sound.ReadSweepGain(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Fds::Disks::Sides::Sides(std::istream& stdStream) { Stream::In stream( &stdStream ); dword size; uint header; switch (stream.Read32()) { case FDS_ID: { size = stream.Read8(); stream.Seek( -5 ); header = HEADER_SIZE; break; } case FDS_RAW_ID: { stream.Seek( -4 ); for (size=0; size < 0xFF && !stream.Eof(); ++size) stream.Seek( SIDE_SIZE ); stream.Seek( -idword(size * SIDE_SIZE) ); header = 0; break; } default: throw RESULT_ERR_INVALID_FILE; } if (!size) throw RESULT_ERR_CORRUPT_FILE; count = size; size *= SIDE_SIZE; data = new byte [HEADER_SIZE + size]; std::memset( data, 0, HEADER_SIZE ); data += HEADER_SIZE; try { stream.Read( data - header, header + size ); file.Load( data - header, header + size, File::DISK ); } catch (...) { delete [] (data - HEADER_SIZE); throw; } } Fds::Disks::Sides::~Sides() { delete [] (data - HEADER_SIZE); } void Fds::Disks::Sides::Save() const { try { const uint header = HasHeader() ? HEADER_SIZE : 0; file.Save( File::DISK, data - header, header + count * dword(SIDE_SIZE) ); } catch (...) { NST_DEBUG_MSG("fds save failure!"); } } Fds::Disks::Disks(std::istream& stream) : sides (stream), crc (Crc32::Compute( sides[0], sides.count * dword(SIDE_SIZE) )), id (dword(sides[0][0x0F]) << 24 | dword(sides[0][0x10]) << 16 | uint(sides[0][0x11]) << 8 | sides[0][0x12]), current (EJECTED), mounting (0), writeProtected (false) { if (Log::Available()) { Log log; for (uint i=0; i < sides.count; ++i) { Api::Fds::DiskData data; if (NES_SUCCEEDED(Unit::Drive::Analyze( sides[i], data ))) { dword disksize = 0; for (Api::Fds::DiskData::Files::const_iterator it(data.files.begin()), end(data.files.end()); it != end; ++it) disksize += it->data.size(); log << "Fds: Disk " << (1+i/2) << (i % 2 ? " Side B: " : " Side A: ") << (disksize / SIZE_1K) << "k in " << data.files.size() << " files"; if (const uint raw = data.raw.size()) log << ", " << raw << "b trailing data"; log << ".." NST_LINEBREAK; for (Api::Fds::DiskData::Files::const_iterator it(data.files.begin()), end(data.files.end()); it != end; ++it) { log << "Fds: file: \"" << it->name << "\", id: " << it->id << ", size: " << it->data.size() << ", index: " << it->index << ", address: " << Log::Hex( 16, it->address ) << ", type: " << ( it->type == Api::Fds::DiskData::File::TYPE_PRG ? "PRG" NST_LINEBREAK : it->type == Api::Fds::DiskData::File::TYPE_CHR ? "CHR" NST_LINEBREAK : it->type == Api::Fds::DiskData::File::TYPE_NMT ? "NMT" NST_LINEBREAK : "unknown" NST_LINEBREAK ); } } } } } Fds::Unit::Timer::Timer() { Reset(); } void Fds::Unit::Timer::Reset() { ctrl = 0; count = 0; latch = 0; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif bool Fds::Unit::Timer::Clock() { bool retval = false; if (ctrl & CTRL_ENABLED) { if (count == 0) { retval = true; count = latch; if (!(ctrl & CTRL_REPEAT)) ctrl &= ~uint(CTRL_ENABLED); } else count--; } return retval; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Fds::Unit::Drive::Drive(const Disks::Sides& s) : sides(s) { Reset(); } void Fds::Unit::Drive::Reset() { count = 0; headPos = 0; dataPos = 0; gap = 0; io = NULL; ctrl = 0; length = 0; in = 0; out = 0; status = STATUS_EJECTED|STATUS_UNREADY|STATUS_PROTECTED|OPEN_BUS; } void Fds::Unit::Drive::Mount(byte* data,bool protect) { io = data; if (data) { status &= ~uint(STATUS_EJECTED|STATUS_PROTECTED); if (protect) status |= uint(STATUS_PROTECTED); } else { count = 0; status |= uint(STATUS_EJECTED|STATUS_PROTECTED|STATUS_UNREADY); } } Result Fds::Unit::Drive::Analyze(const byte* NST_RESTRICT src,Api::Fds::DiskData& dst) { try { idword i = SIDE_SIZE; for (uint block=~0U, files=0; i; ) { const uint prev = block; block = src[0]; if (block == BLOCK_VOLUME) { i -= LENGTH_VOLUME+1; if (i < 0 || prev != ~0U) break; src += LENGTH_VOLUME+1; } else if (block == BLOCK_COUNT) { i -= LENGTH_COUNT+1; if (i < 0 || prev != BLOCK_VOLUME) break; files = src[1]; src += LENGTH_COUNT+1; } else if (block == BLOCK_HEADER) { i -= LENGTH_HEADER+1; if (i < 0 || (prev != BLOCK_DATA && prev != BLOCK_COUNT) || !files) break; dst.files.push_back( Api::Fds::DiskData::File() ); Api::Fds::DiskData::File& file = dst.files.back(); file.index = src[1]; file.id = src[2]; Stream::In::AsciiToC( file.name, src+3, 8 ); for (uint j=8; j < sizeof(array(file.name)); ++j) file.name[j] = '\0'; file.address = src[11] | uint(src[12]) << 8; switch (src[15]) { case 0: file.type = Api::Fds::DiskData::File::TYPE_PRG; break; case 1: file.type = Api::Fds::DiskData::File::TYPE_CHR; break; case 2: file.type = Api::Fds::DiskData::File::TYPE_NMT; break; default: file.type = Api::Fds::DiskData::File::TYPE_UNKNOWN; break; } file.data.resize( src[13] | uint(src[14]) << 8 ); if (const dword size = file.data.size()) std::memset( &file.data.front(), 0x00, size ); src += LENGTH_HEADER+1; } else if (block == BLOCK_DATA) { if (prev != BLOCK_HEADER) break; Api::Fds::DiskData::Data& data = dst.files.back().data; const idword size = data.size(); i -= size+1; if (i < 0) break; ++src; if (size) { std::memcpy( &data.front(), src, size ); src += size; } NST_ASSERT( files ); if (!--files) break; } else { break; } } for (idword j=i; j-- > 0; ) { if (src[j]) { dst.raw.assign( src, src+j+1 ); break; } } return i >= 0 ? RESULT_OK : RESULT_WARN_BAD_DUMP; } catch (const std::bad_alloc&) { return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { return RESULT_ERR_GENERIC; } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NST_SINGLE_CALL void Fds::Unit::Drive::Write(uint reg) { ctrl = reg; if (!(reg & CTRL_ON)) { count = 0; status |= uint(STATUS_UNREADY); } else if (!((reg & CTRL_STOP) | count) && io) { count = CLK_MOTOR; headPos = 0; } } ibool Fds::Unit::Drive::Advance(uint& timer) { NST_ASSERT( io && !count ); if (headPos-1U < MAX_SIDE_SIZE && dataPos < SIDE_SIZE) { NST_VERIFY( !(status & uint(STATUS_UNREADY)) ); ++headPos; byte* stream = io + dataPos; count = CLK_BYTE; NST_VERIFY( ctrl & uint(CTRL_READ_MODE) || length != LENGTH_UNKNOWN ); if (ctrl & uint(CTRL_READ_MODE)) { if (!gap) { if (length == LENGTH_UNKNOWN) { // Non-standard file layout which cannot accurately // be emulated within the FDS file format since it // removes the CRC value at the end of each block. // No choice but to fall back on the BIOS. in = *stream | 0x100U; if (ctrl & uint(CTRL_CRC)) dataPos -= 2; else dataPos += 1; } else if (length-- > 2) { in = *stream; ++dataPos; } else if (length == 1) { if (*stream <= 4) { in = 0x91; } else { in = *stream; ++dataPos; } } else { if (*stream <= 4) { in = 0x88; length = 0; gap = BYTES_GAP_NEXT; } else { in = *stream; length = LENGTH_UNKNOWN; ++dataPos; } } } else { if (!--gap) { NST_VERIFY( *stream <= 4 ); switch (stream[0]) { case BLOCK_HEADER: length = LENGTH_HEADER + 3; break; case BLOCK_DATA: length = (uint(stream[-2]) << 8 | stream[-3]) + 3; NST_VERIFY( length > 3 ); break; case BLOCK_VOLUME: length = LENGTH_VOLUME + 3; break; case BLOCK_COUNT: length = LENGTH_COUNT + 3; break; default: gap = 1; break; } } if (ctrl & uint(CTRL_IO_MODE)) return false; NST_VERIFY( !(ctrl & uint(CTRL_GEN_IRQ)) ); in = 0; } } else if (!(status & uint(STATUS_PROTECTED)) && length != LENGTH_UNKNOWN) { NST_VERIFY( ctrl & uint(CTRL_IO_MODE) || !length ); gap -= (gap > 0); const uint data = (ctrl & uint(CTRL_IO_MODE)) ? out : 0; if (length-- > 3) { ++dataPos; *stream = data; } else if (length == 2) { } else if (length == 1) { gap = BYTES_GAP_NEXT; } else { length = 0; if (data-1 <= 3) { NST_VERIFY( ctrl & uint(CTRL_IO_MODE) ); ++dataPos; switch (*stream = data) { case BLOCK_VOLUME: length = LENGTH_VOLUME + 3; break; case BLOCK_COUNT: length = LENGTH_COUNT + 3; break; case BLOCK_HEADER: length = LENGTH_HEADER + 3; break; case BLOCK_DATA: length = (uint(stream[-2]) << 8 | stream[-3]) + 3; NST_VERIFY( length > 3 ); break; default: NST_UNREACHABLE(); } } } } uint irq = ctrl & uint(CTRL_GEN_IRQ); timer |= irq >> 6; return irq; } else if (headPos) { count = CLK_REWIND; headPos = 0; status |= uint(STATUS_UNREADY); } else if (!(ctrl & uint(CTRL_STOP))) { count = CLK_BYTE; headPos = 1; dataPos = 0; length = 0; gap = BYTES_GAP_INIT + BYTES_GAP_NEXT; status &= ~uint(STATUS_UNREADY); } return false; } NST_SINGLE_CALL bool Fds::Unit::Drive::Clock() { return !count || --count; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Fds::Unit::Unit(const Disks::Sides& s) : drive(s) { status = 0; } void Fds::Unit::Reset(bool) { timer.Reset(); drive.Reset(); status = 0; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif ibool Fds::Unit::Clock() { bool retval = false; if (timer.Clock()) { status |= STATUS_PENDING_IRQ; retval = true; } return (retval | (drive.Clock() ? 0 : drive.Advance(status))); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Fds::Adapter::Adapter(Cpu& c,const Disks::Sides& s) : Timer::M2(c,s) {} void Fds::Adapter::DisableIRQ() { unit.status &= ~uint(Unit::STATUS_PENDING_IRQ); unit.timer.ctrl &= ~uint(Unit::Timer::CTRL_ENABLED); } void Fds::Adapter::Reset(Cpu& cpu,byte* const io,bool protect) { Timer::M2::Reset( true, true ); unit.drive.Mount( io, protect ); cpu.Map( 0x4020 ).Set( this, &Adapter::Peek_Nop, &Adapter::Poke_4020 ); cpu.Map( 0x4021 ).Set( this, &Adapter::Peek_Nop, &Adapter::Poke_4021 ); cpu.Map( 0x4022 ).Set( this, &Adapter::Peek_Nop, &Adapter::Poke_4022 ); cpu.Map( 0x4024 ).Set( this, &Adapter::Peek_Nop, &Adapter::Poke_4024 ); cpu.Map( 0x4030 ).Set( this, &Adapter::Peek_4030, &Adapter::Poke_Nop ); cpu.Map( 0x4032 ).Set( this, &Adapter::Peek_4032, &Adapter::Poke_Nop ); } void Fds::Adapter::SaveState(State::Saver& state) const { { const byte data[7] = { unit.timer.ctrl, unit.status, unit.timer.latch & 0xFFU, unit.timer.latch >> 8, unit.timer.count & 0xFFU, unit.timer.count >> 8, 0 }; state.Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End(); } { const uint headPos = NST_MIN(unit.drive.headPos,SIDE_SIZE); const byte data[16] = { unit.drive.ctrl, unit.drive.status, unit.drive.in & 0xFFU, unit.drive.out, unit.drive.count ? headPos & 0xFF : 0, unit.drive.count ? headPos >> 8 : 0, unit.drive.count ? unit.drive.dataPos & 0xFFU : 0, unit.drive.count ? unit.drive.dataPos >> 8 : 0, unit.drive.count ? unit.drive.gap & 0xFFU : 0, unit.drive.count ? unit.drive.gap >> 8 : 0, unit.drive.count ? unit.drive.length & 0xFFU : 0, unit.drive.count ? unit.drive.length >> 8 : 0, unit.drive.count >> 0 & 0xFF, unit.drive.count >> 8 & 0xFF, unit.drive.count >> 16, unit.drive.in >> 8 }; state.Begin( AsciiId<'D','R','V'>::V ).Write( data ).End(); } } void Fds::Adapter::LoadState(State::Loader& state,const dword chunk,Ppu& ppu) { switch (chunk) { case AsciiId<'I','R','Q'>::V: { State::Loader::Data<7> data( state ); unit.timer.ctrl = data[0]; unit.status = data[1] & (Unit::STATUS_PENDING_IRQ|Unit::STATUS_TRANSFERED); unit.timer.latch = data[2] | data[3] << 8; unit.timer.count = data[4] | data[5] << 8; break; } case AsciiId<'D','R','V'>::V: { State::Loader::Data<16> data( state ); unit.drive.ctrl = data[0]; unit.drive.status = (data[1] & (Unit::Drive::STATUS_EJECTED|Unit::Drive::STATUS_UNREADY|Unit::Drive::STATUS_PROTECTED)) | OPEN_BUS; unit.drive.in = data[2] | (data[15] << 8 & 0x100); unit.drive.out = data[3]; unit.drive.headPos = data[4] | data[5] << 8; unit.drive.dataPos = data[6] | data[7] << 8; unit.drive.gap = data[8] | data[9] << 8; unit.drive.length = data[10] | data[11] << 8; unit.drive.count = data[12] | data[13] << 8 | dword(data[14]) << 16; if (unit.drive.dataPos > SIDE_SIZE) unit.drive.dataPos = SIDE_SIZE; if (unit.drive.headPos < unit.drive.dataPos) unit.drive.headPos = unit.drive.dataPos; ppu.SetMirroring( (unit.drive.ctrl & uint(CTRL1_NMT_HORIZONTAL)) ? Ppu::NMT_H : Ppu::NMT_V ); break; } } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NST_SINGLE_CALL uint Fds::Adapter::Activity() const { return unit.drive.count ? (unit.drive.ctrl & uint(Unit::Drive::CTRL_READ_MODE)) ? Api::Fds::MOTOR_READ : Api::Fds::MOTOR_WRITE : Api::Fds::MOTOR_OFF; } NST_SINGLE_CALL void Fds::Adapter::WriteProtect() { unit.drive.status |= uint(Unit::Drive::STATUS_PROTECTED); } NST_SINGLE_CALL void Fds::Adapter::Write(uint reg) { Update(); unit.status &= (reg >> 6 & Unit::STATUS_TRANSFERED) | Unit::STATUS_PENDING_IRQ; if (!unit.status) ClearIRQ(); unit.drive.Write( reg ); } NST_SINGLE_CALL uint Fds::Adapter::Read() { Update(); unit.status &= Unit::STATUS_PENDING_IRQ; if (!unit.status) ClearIRQ(); return unit.drive.in; } NES_PEEK(Fds::Adapter,Nop) { return OPEN_BUS; } NES_POKE(Fds::Adapter,Nop) { } NES_POKE_D(Fds::Adapter,4020) { Update(); unit.timer.latch = (unit.timer.latch & 0xFF00U) | (data << 0); } NES_POKE_D(Fds::Adapter,4021) { Update(); unit.timer.latch = (unit.timer.latch & 0x00FFU) | (data << 8); } NES_POKE_D(Fds::Adapter,4022) { Update(); if (!(ctrl & Io::CTRL0_DISK_ENABLED)) return; unit.timer.ctrl = data; unit.timer.count = unit.timer.latch; unit.status &= Unit::STATUS_TRANSFERED; if (data & Unit::Timer::CTRL_ENABLED) return; ClearIRQ(); } NES_POKE_D(Fds::Adapter,4024) { Update(); unit.drive.out = data; unit.status &= Unit::STATUS_PENDING_IRQ; if (!unit.status) ClearIRQ(); } NES_PEEK(Fds::Adapter,4030) { Update(); const uint status = unit.status; unit.status = 0; ClearIRQ(); return status; } NES_PEEK(Fds::Adapter,4032) { Update(); NST_ASSERT( unit.drive.status & uint(OPEN_BUS) ); return unit.drive.status | (unit.drive.ctrl & uint(Unit::Drive::CTRL_STOP)); } void Fds::VSync() { adapter.VSync(); if (!disks.mounting) { const uint led = adapter.Activity(); if (io.led != led && (io.led != Api::Fds::MOTOR_WRITE || led != Api::Fds::MOTOR_READ)) { io.led = led; Api::Fds::driveCallback( static_cast(io.led) ); } } else if (!--disks.mounting) { adapter.Mount( disks.sides[disks.current], disks.writeProtected ); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Fds::Io::Io() : led(Api::Fds::MOTOR_OFF) { Reset(); } void Fds::Io::Reset() { ctrl = 0; port = 0; } void Fds::Ram::Reset() { std::memset( mem, 0x00, sizeof(mem) ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(Fds::Ram,Ram) { return mem[address - 0x6000]; } NES_POKE_AD(Fds::Ram,Ram) { mem[address - 0x6000] = data; } NES_POKE_D(Fds,4025) { adapter.Write( data ); ppu.SetMirroring( (data & CTRL1_NMT_HORIZONTAL) ? Ppu::NMT_H : Ppu::NMT_V ); } NES_PEEK(Fds,4031) { const uint data = adapter.Read(); if (data <= 0xFF) return data; if (!disks.writeProtected) { disks.writeProtected = true; adapter.WriteProtect(); Api::Fds::diskCallback( Api::Fds::DISK_NONSTANDARD, disks.current / 2, disks.current % 2 ); } return data & 0xFF; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Fds::Sound::Envelope::Reset() { ctrl = 0; counter = 0; gain = GAIN_MIN; output = GAIN_MIN; } void Fds::Sound::Envelope::SaveState(State::Saver& state,const dword chunk) const { const byte data[3] = { ctrl, counter, gain }; state.Begin( chunk ).Write( data ).End(); } void Fds::Sound::Envelope::LoadState(State::Loader& state) { State::Loader::Data<3> data( state ); ctrl = data[0]; counter = data[1] & CTRL_COUNT; gain = data[2] & CTRL_COUNT; output = NST_MIN(gain,GAIN_MAX); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif inline uint Fds::Sound::Envelope::Gain() const { return gain; } inline uint Fds::Sound::Envelope::Output() const { NST_ASSERT( output == NST_MIN(gain,GAIN_MAX) ); return output; } void Fds::Sound::Envelope::Write(const uint data) { ctrl = data; counter = data & CTRL_COUNT; if (data & CTRL_DISABLE) { gain = data & CTRL_COUNT; output = NST_MIN(gain,GAIN_MAX); } } NST_SINGLE_CALL void Fds::Sound::Envelope::Clock() { if (!(ctrl & CTRL_DISABLE)) { if (counter) { counter--; } else { counter = ctrl & CTRL_COUNT; if (ctrl & CTRL_UP) gain += (gain < GAIN_MAX); else gain -= (gain > GAIN_MIN); output = NST_MIN(gain,GAIN_MAX); } } } inline bool Fds::Sound::CanModulate() const { return modulator.length && !modulator.writing; } bool Fds::Sound::CanOutput() const { return (status & STATUS_OUTPUT_ENABLED) && wave.length && !wave.writing && output; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Fds::Sound::Sound(Apu& a,bool connect) : Channel(a) { Reset(); bool audible = UpdateSettings(); if (connect) Connect( audible ); } void Fds::Sound::Reset() { active = false; wave.writing = false; wave.length = 0; wave.pos = 0; wave.volume = 0; modulator.active = false; modulator.writing = false; modulator.pos = 0; modulator.length = 0; modulator.timer = 0; modulator.sweep = 0; envelopes.counter = 0; envelopes.length = 0; envelopes.units[VOLUME].Reset(); envelopes.units[SWEEP].Reset(); std::memset( wave.table, 0, Wave::SIZE ); std::memset( modulator.table, 0x00, Modulator::SIZE ); status = 0; volume = volumes[0]; amp = 0; dcBlocker.Reset(); } bool Fds::Sound::UpdateSettings() { envelopes.clock = GetCpuClock() * Envelopes::PULSE; Cycle rate; uint fixed; GetOscillatorClock( rate, fixed ); NST_VERIFY( fixed <= 0xFFFF && rate <= 0x7FFFF ); modulator.rate = rate; modulator.clock = dword(fixed) << 16; wave.rate = GetSampleRate(); wave.frame = GetCpuClockBase(); wave.clock = 0x10000UL * GetCpuClock() * GetCpuClockDivider(); amp = 0; uint volume = GetVolume(EXT_FDS) * 69 / DEFAULT_VOLUME; output = IsMuted() ? 0 : volume; dcBlocker.Reset(); active = CanOutput(); return volume; } void Fds::Sound::SaveState(State::Saver& state,const dword baseChunk) const { state.Begin( baseChunk ); state.Begin( AsciiId<'M','A','S'>::V ); { { byte data[6] = { ((status & STATUS_OUTPUT_ENABLED) ? 0U : uint(REG3_OUTPUT_DISABLE)) | ((status & STATUS_ENVELOPES_ENABLED) ? 0U : uint(REG3_ENVELOPE_DISABLE)), wave.writing ? REG9_WRITE_MODE : 0, wave.length & 0xFFU, wave.length >> 8, envelopes.length, envelopes.counter }; for (uint i=0; i < sizeof(array(volumes)); ++i) { if (volume == volumes[i]) { data[1] |= i; break; } } state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End(); } { state.Begin( AsciiId<'W','A','V'>::V ).Compress( wave.table ).End(); } } state.End(); envelopes.units[VOLUME].SaveState( state, AsciiId<'V','O','L'>::V ); envelopes.units[SWEEP].SaveState( state, AsciiId<'S','W','P'>::V ); state.Begin( AsciiId<'M','O','D'>::V ); { { const byte data[4] = { modulator.length & 0xFF, modulator.length >> 8 | (modulator.writing ? REG7_MOD_WRITE_MODE : 0), modulator.sweep, modulator.pos }; state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End(); } { byte data[Modulator::SIZE]; for (uint i=0; i < Modulator::SIZE; ++i) { for (uint j=0; j < sizeof(array(Modulator::steps)); ++j) { if (modulator.table[i] == Modulator::steps[j]) { data[i] = j; break; } } } state.Begin( AsciiId<'R','A','M'>::V ).Compress( data ).End(); } } state.End(); state.End(); } void Fds::Sound::LoadState(State::Loader& state) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'M','A','S'>::V: { while (const dword subchunk = state.Begin()) { switch (subchunk) { case AsciiId<'R','E','G'>::V: { State::Loader::Data<6> data( state ); status = ( ((data[0] & REG3_OUTPUT_DISABLE) ? 0U : uint(STATUS_OUTPUT_ENABLED)) | ((data[0] & REG3_ENVELOPE_DISABLE) ? 0U : uint(STATUS_ENVELOPES_ENABLED)) ); volume = volumes[data[1] & REG9_VOLUME]; wave.writing = data[1] & REG9_WRITE_MODE; wave.length = data[2] | (data[3] & REG3_WAVELENGTH_HIGH) << 8; envelopes.length = data[4]; envelopes.counter = data[5]; break; } case AsciiId<'W','A','V'>::V: state.Uncompress( wave.table ); for (uint i=0; i < Wave::SIZE; ++i) wave.table[i] &= 0x3FU; break; } state.End(); } break; } case AsciiId<'V','O','L'>::V: envelopes.units[VOLUME].LoadState( state ); break; case AsciiId<'S','W','P'>::V: envelopes.units[SWEEP].LoadState( state ); break; case AsciiId<'M','O','D'>::V: { while (const dword subchunk = state.Begin()) { switch (subchunk) { case AsciiId<'R','E','G'>::V: { State::Loader::Data<4> data( state ); modulator.length = data[0] | (data[1] & REG7_MOD_WAVELENGTH_HIGH) << 8; modulator.writing = data[1] & REG7_MOD_WRITE_MODE; modulator.sweep = data[2] & (REG5_MOD_SWEEP|REG5_MOD_NEGATE); modulator.pos = data[3] & 0x3F; break; } case AsciiId<'R','A','M'>::V: { byte data[Modulator::SIZE]; state.Uncompress( data ); for (uint i=0; i < Modulator::SIZE; ++i) modulator.table[i] = Modulator::steps[data[i] & uint(REG8_MOD_DATA)]; break; } } state.End(); } break; } } state.End(); } amp = 0; wave.pos = 0; wave.volume = envelopes.units[VOLUME].Output(); modulator.timer = 0; modulator.active = CanModulate(); active = CanOutput(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif uint Fds::Sound::ReadWaveData(uint address) const { return wave.table[address & 0x3F] | uint(OPEN_BUS); } void Fds::Sound::WriteWaveData(uint address,uint data) { NST_VERIFY( wave.writing ); if (wave.writing) { Update(); wave.table[address & 0x3F] = data & 0x3F; } } void Fds::Sound::WriteReg0(uint data) { Update(); envelopes.units[VOLUME].Write( data ); if (data & Envelope::CTRL_DISABLE && !wave.pos) wave.volume = envelopes.units[VOLUME].Output(); } void Fds::Sound::WriteReg1(uint data) { Update(); wave.length &= uint(REG3_WAVELENGTH_HIGH) << 8; wave.length |= data; active = CanOutput(); } void Fds::Sound::WriteReg2(uint data) { Update(); wave.length &= uint(REG2_WAVELENGTH_LOW); wave.length |= (data & REG3_WAVELENGTH_HIGH) << 8; status = ~data & (REG3_OUTPUT_DISABLE|REG3_ENVELOPE_DISABLE); if (data & REG3_OUTPUT_DISABLE) { wave.pos = 0; wave.volume = envelopes.units[VOLUME].Output(); } active = CanOutput(); } void Fds::Sound::WriteReg3(uint data) { Update(); envelopes.units[SWEEP].Write( data ); } void Fds::Sound::WriteReg4(uint data) { Update(); modulator.sweep = data & (REG5_MOD_SWEEP|REG5_MOD_NEGATE); modulator.pos = 0x00; } void Fds::Sound::WriteReg5(uint data) { Update(); modulator.length &= uint(REG7_MOD_WAVELENGTH_HIGH) << 8; modulator.length |= data; modulator.active = CanModulate(); } void Fds::Sound::WriteReg6(uint data) { Update(); modulator.length &= REG6_MOD_WAVELENGTH_LOW; modulator.length |= (data & REG7_MOD_WAVELENGTH_HIGH) << 8; modulator.writing = data & REG7_MOD_WRITE_MODE; modulator.active = CanModulate(); } void Fds::Sound::WriteReg7(uint data) { NST_VERIFY( modulator.writing ); if (modulator.writing) { Update(); std::memmove( modulator.table, modulator.table + 1, Modulator::SIZE-1 ); modulator.table[Modulator::SIZE-1] = Modulator::steps[data & REG8_MOD_DATA]; } } void Fds::Sound::WriteReg8(uint data) { Update(); volume = volumes[data & REG9_VOLUME]; wave.writing = data & REG9_WRITE_MODE; active = CanOutput(); } void Fds::Sound::WriteReg9(uint data) { Update(); envelopes.length = data; } uint Fds::Sound::ReadVolumeGain() const { return envelopes.units[VOLUME].Gain() | OPEN_BUS; } uint Fds::Sound::ReadSweepGain() const { return envelopes.units[SWEEP].Gain() | OPEN_BUS; } Cycle Fds::Sound::Clock(Cycle rateCycles,Cycle rateClock,const Cycle targetCycles) { rateClock *= envelopes.clock; do { if (envelopes.counter) { envelopes.counter--; } else { envelopes.counter = envelopes.length; if (envelopes.length && status & STATUS_ENVELOPES_ENABLED) { for (uint i=0; i < 2; ++i) envelopes.units[i].Clock(); } } rateCycles += rateClock; } while (rateCycles <= targetCycles); return rateCycles; } NST_SINGLE_CALL dword Fds::Sound::GetModulation() const { if (dword pos = envelopes.units[SWEEP].Gain()) { pos = (pos * (((modulator.sweep & REG5_MOD_SWEEP) - (modulator.sweep & REG5_MOD_NEGATE)))) & 0xFFF; if (modulator.sweep & REG5_MOD_NEGATE) { pos >>= 4; if (pos >= 0xC0) pos = (pos & 0x7F) - (pos & 0x80); } else { pos = (pos >> 4) + ((pos & 0xF) ? 2 : 0); if (pos >= 0xC2) { pos -= 0x102; pos = (pos & 0x7F) - (pos & 0x80); } } pos *= wave.length; if (pos & Modulator::TIMER_CARRY) pos = wave.length - (~(pos-1) >> 6); else pos = wave.length + (pos >> 6); return pos; } return wave.length; } Fds::Sound::Sample Fds::Sound::GetSample() { NST_ASSERT( modulator.active == CanModulate() && bool(active) == CanOutput() ); if (modulator.active) { for (modulator.timer -= modulator.length * modulator.rate; modulator.timer & Modulator::TIMER_CARRY; modulator.timer += modulator.clock) { const uint value = modulator.pos >> 1; modulator.pos = (modulator.pos + 1U) & 0x3F; modulator.sweep = (modulator.table[value] != 0x80) ? (modulator.sweep + modulator.table[value]) & 0x7FU : 0x00U; } } dword sample = 0; if (active) { const dword pos = wave.pos; wave.pos = (wave.pos + dword(qaword(GetModulation()) * wave.frame / wave.clock) + Wave::SIZE * wave.rate) % (Wave::SIZE * wave.rate); if (wave.pos < pos) wave.volume = envelopes.units[VOLUME].Output(); sample = wave.volume * volume * wave.table[(wave.pos / wave.rate) & 0x3F] / 30; } amp = (amp * 2 + sample) / 3; return dcBlocker.Apply( amp * output / DEFAULT_VOLUME ); } } } nestopia-1.51.1/source/core/NstFds.hpp000066400000000000000000000243241411157722000175700ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_FDS_H #define NST_FDS_H #include "NstImage.hpp" #include "NstTimer.hpp" #include "NstFile.hpp" #include "NstChecksum.hpp" #include "api/NstApiFds.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class Ppu; class Fds : public Image { public: explicit Fds(Context&); Result InsertDisk(uint,uint); Result EjectDisk(); Result GetDiskData(uint,Api::Fds::DiskData&) const; static void SetBios(std::istream*); static Result GetBios(std::ostream&); static bool HasBios(); class Sound : public Apu::Channel { public: explicit Sound(Apu&,bool=true); uint ReadWaveData(uint) const; void WriteWaveData(uint,uint); void WriteReg0(uint); void WriteReg1(uint); void WriteReg2(uint); void WriteReg3(uint); void WriteReg4(uint); void WriteReg5(uint); void WriteReg6(uint); void WriteReg7(uint); void WriteReg8(uint); void WriteReg9(uint); uint ReadVolumeGain() const; uint ReadSweepGain() const; void SaveState(State::Saver&,dword) const; void LoadState(State::Loader&); protected: void Reset(); bool UpdateSettings(); Sample GetSample(); Cycle Clock(Cycle,Cycle,Cycle); private: bool CanOutput() const; inline bool CanModulate() const; NST_SINGLE_CALL dword GetModulation() const; enum { REG2_WAVELENGTH_LOW = 0xFF, REG3_WAVELENGTH_HIGH = 0x0F, REG3_ENVELOPE_DISABLE = 0x40, REG3_OUTPUT_DISABLE = 0x80, REG5_MOD_SWEEP = 0x3F, REG5_MOD_NEGATE = 0x40, REG6_MOD_WAVELENGTH_LOW = 0xFF, REG7_MOD_WAVELENGTH_HIGH = 0x0F, REG7_MOD_WRITE_MODE = 0x80, REG8_MOD_DATA = 0x07, REG9_VOLUME = 0x03, REG9_WRITE_MODE = 0x80 }; enum { STATUS_OUTPUT_ENABLED = REG3_OUTPUT_DISABLE, STATUS_ENVELOPES_ENABLED = REG3_ENVELOPE_DISABLE }; class Envelope { public: void Reset(); void Write(uint); NST_SINGLE_CALL void Clock(); inline uint Gain() const; inline uint Output() const; void SaveState(State::Saver&,dword) const; void LoadState(State::Loader&); enum { CTRL_COUNT = 0x3F, CTRL_UP = 0x40, CTRL_DISABLE = 0x80 }; private: enum { GAIN_MAX = 0x20, GAIN_MIN = 0x00 }; byte counter; byte ctrl; byte gain; byte output; }; struct Modulator { enum { TIMER_CARRY = 0x80000000, SIZE = 0x20 }; bool active; bool writing; byte sweep; byte pos; uint length; dword rate; dword timer; dword clock; byte table[SIZE]; static const byte steps[8]; }; enum { VOLUME, SWEEP }; struct Envelopes { enum {PULSE = 8}; byte counter; byte length; word clock; Envelope units[2]; }; struct Wave { enum {SIZE = 0x40}; word length; byte volume; bool writing; dword pos; dword rate; dword frame; dword clock; byte table[SIZE]; }; ibool active; Wave wave; Envelopes envelopes; Modulator modulator; uint volume; dword amp; uint output; uint status; DcBlocker dcBlocker; static const byte volumes[4]; }; private: ~Fds(); void Reset(bool); void VSync(); uint GetDesiredController(uint) const; uint GetDesiredAdapter() const; Region GetDesiredRegion() const; System GetDesiredSystem(Region,CpuModel*,PpuModel*) const; void LoadState(State::Loader&); void SaveState(State::Saver&,dword) const; bool PowerOff(); NES_DECL_PEEK( Nop ); NES_DECL_POKE( Nop ); NES_DECL_POKE( 4023 ); NES_DECL_POKE( 4025 ); NES_DECL_POKE( 4026 ); NES_DECL_PEEK( 4031 ); NES_DECL_PEEK( 4033 ); NES_DECL_PEEK( 4040 ); NES_DECL_POKE( 4040 ); NES_DECL_POKE( 4080 ); NES_DECL_POKE( 4082 ); NES_DECL_POKE( 4083 ); NES_DECL_POKE( 4084 ); NES_DECL_POKE( 4085 ); NES_DECL_POKE( 4086 ); NES_DECL_POKE( 4087 ); NES_DECL_POKE( 4088 ); NES_DECL_POKE( 4089 ); NES_DECL_POKE( 408A ); NES_DECL_PEEK( 4090 ); NES_DECL_PEEK( 4092 ); enum { SIDE_SIZE = 65500, MAX_SIDE_SIZE = 68000, CTRL1_NMT_HORIZONTAL = 0x08, OPEN_BUS = 0x40, DOREMIKKO_ID = 0xA4445245 }; struct Disks { explicit Disks(std::istream&); enum { EJECTED = 0xFFF, MOUNTING = 180 }; class Sides { public: explicit Sides(std::istream&); ~Sides(); inline byte* operator [] (uint) const; void Save() const; uint count; private: enum { HEADER_SIZE = 16 }; byte* data; File file; public: bool HasHeader() const { return data[-HEADER_SIZE]; } }; const Sides sides; const dword crc; const dword id; word current; byte mounting; bool writeProtected; }; struct Ram { void Reset(); NES_DECL_PEEK( Ram ); NES_DECL_POKE( Ram ); byte mem[SIZE_32K]; }; struct Unit { explicit Unit(const Disks::Sides&); void Reset(bool); ibool Clock(); enum { STATUS_PENDING_IRQ = 0x1, STATUS_TRANSFERED = 0x2 }; struct Timer { Timer(); void Reset(); NST_SINGLE_CALL bool Clock(); enum { CTRL_REPEAT = 0x1, CTRL_ENABLED = 0x2 }; uint ctrl; word count; word latch; }; struct Drive { explicit Drive(const Disks::Sides&); static Result Analyze(const byte*,Api::Fds::DiskData&); void Reset(); void Mount(byte*,bool); ibool Advance(uint&); NST_SINGLE_CALL bool Clock(); NST_SINGLE_CALL void Write(uint); enum { CLK_HEAD = 96400, BYTES_GAP_INIT = CLK_HEAD/8UL * 398 / 1000, BYTES_GAP_NEXT = CLK_HEAD/8UL * 10 / 1000, CLK_BYTE = CLK_NTSC / (CLK_HEAD/8UL * CPU_RP2A03_CC * CLK_NTSC_DIV), CLK_MOTOR = CLK_HEAD/8UL * 100 * CLK_BYTE / 1000, CLK_REWIND = CLK_HEAD/8UL * 135 * CLK_BYTE / 1000, CTRL_ON = 0x01, CTRL_STOP = 0x02, CTRL_READ_MODE = 0x04, CTRL_CRC = 0x10, CTRL_IO_MODE = 0x40, CTRL_GEN_IRQ = 0x80, STATUS_EJECTED = 0x01, STATUS_UNREADY = 0x02, STATUS_PROTECTED = 0x04, BLOCK_VOLUME = 1, BLOCK_COUNT, BLOCK_HEADER, BLOCK_DATA, LENGTH_HEADER = 15, LENGTH_VOLUME = 55, LENGTH_COUNT = 1, LENGTH_UNKNOWN = 0xFFFF }; dword count; dword headPos; byte* io; word dataPos; word gap; word length; word in; byte out; byte ctrl; byte status; const Disks::Sides& sides; }; Timer timer; Drive drive; uint status; }; class Adapter : Timer::M2 { NES_DECL_PEEK( Nop ); NES_DECL_POKE( Nop ); NES_DECL_POKE( 4020 ); NES_DECL_POKE( 4021 ); NES_DECL_POKE( 4022 ); NES_DECL_POKE( 4024 ); NES_DECL_PEEK( 4030 ); NES_DECL_PEEK( 4032 ); public: Adapter(Cpu&,const Disks::Sides&); void DisableIRQ(); void Reset(Cpu&,byte*,bool=false); void LoadState(State::Loader&,dword,Ppu&); void SaveState(State::Saver&) const; inline void Mount(byte*,bool=false); NST_SINGLE_CALL void Write(uint); NST_SINGLE_CALL uint Read(); NST_SINGLE_CALL void WriteProtect(); NST_SINGLE_CALL uint Activity() const; using Timer::M2::VSync; byte ctrl; }; struct Io { Io(); void Reset(); enum { CTRL0_DISK_ENABLED = 0x01, BATTERY_CHARGED = 0x80 }; byte ctrl; byte port; mutable word led; }; Disks disks; Adapter adapter; Io io; Cpu& cpu; Ppu& ppu; Ram ram; Sound sound; FavoredSystem favoredSystem; mutable Checksum checksum; class Bios; static Bios bios; public: bool IsAnyDiskInserted() const { return disks.current != Disks::EJECTED; } int CurrentDisk() const { return disks.current != Disks::EJECTED ? int(disks.current / 2U) : -1; } int CurrentDiskSide() const { return disks.current != Disks::EJECTED ? int(disks.current % 2U) : -1; } uint NumSides() const { return disks.sides.count; } uint NumDisks() const { return (disks.sides.count / 2U) + (disks.sides.count % 2U); } dword GetPrgCrc() const { return disks.crc; } bool CanChangeDiskSide() const { return disks.current != Disks::EJECTED && (disks.current | 1U) < disks.sides.count; } bool HasHeader() const { return disks.sides.HasHeader(); } }; } } #endif nestopia-1.51.1/source/core/NstFile.cpp000066400000000000000000000301241411157722000177210ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include "NstStream.hpp" #include "NstVector.hpp" #include "NstChecksum.hpp" #include "NstPatcher.hpp" #include "NstFile.hpp" #include "api/NstApiUser.hpp" namespace Nes { namespace Core { struct File::Context { Checksum checksum; Vector data; }; File::File() : context( *new Context ) { } File::~File() { delete &context; } void File::Load(const byte* data,dword size) const { NST_ASSERT( data && size ); context.checksum.Clear(); context.checksum.Compute( data, size ); context.data.Destroy(); } void File::Load(byte* data,dword size,Type type) const { NST_ASSERT( data && size ); context.data.Assign( data, size ); bool altered = false; const LoadBlock loadBlock = {data,size}; Load( type, &loadBlock, 1, &altered ); if (altered) context.checksum.Clear(); } void File::Load(Type type,byte* data,dword size) const { const LoadBlock loadBlock = {data,size}; Load( type, &loadBlock, 1 ); } void File::Load(const Type type,const LoadBlock* const loadBlock,const uint loadBlockCount,bool* const altered) const { class Loader : public Api::User::File { const Action action; const LoadBlock* const loadBlock; const uint loadBlockCount; bool* const altered; Action GetAction() const throw() { return action; } ulong GetMaxSize() const throw() { dword maxsize = 0; for (const LoadBlock* NST_RESTRICT it=loadBlock, *const end=loadBlock+loadBlockCount; it != end; ++it) maxsize += it->size; return maxsize; } Result SetContent(const void* data,ulong filesize) throw() { if (altered) *altered = true; if (!data || !filesize) return RESULT_ERR_INVALID_PARAM; const byte* NST_RESTRICT filedata = static_cast(data); for (const LoadBlock* NST_RESTRICT it=loadBlock, *const end=loadBlock+loadBlockCount; it != end; ++it) { if (const dword size = NST_MIN(filesize,it->size)) { std::memcpy( it->data, filedata, size ); filedata += size; filesize -= size; } } return RESULT_OK; } void GetRawStorage(void*& data, ulong& size) const throw() { if (loadBlockCount == 1) { data = loadBlock->data; size = loadBlock->size; } else { data = 0; size = 0; } } Result SetContent(std::istream& stdStream) throw() { if (altered) *altered = true; try { Nes::Core::Stream::In stream( &stdStream ); if (ulong length = stream.Length()) { for (const LoadBlock* NST_RESTRICT it=loadBlock, *const end=loadBlock+loadBlockCount; it != end; ++it) { if (const dword size = NST_MIN(length,it->size)) { stream.Read( it->data, size ); length -= size; } } } else { return RESULT_ERR_INVALID_PARAM; } } catch (Result result) { return result; } catch (const std::bad_alloc&) { return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { return RESULT_ERR_GENERIC; } return RESULT_OK; } Result SetPatchContent(std::istream& stream) throw() { if (altered) *altered = true; Patcher patcher; Result result = patcher.Load( stream ); if (NES_FAILED(result)) return result; if (loadBlockCount > 1) { Patcher::Block* const patchBlocks = new (std::nothrow) Patcher::Block [loadBlockCount]; if (!patchBlocks) return RESULT_ERR_OUT_OF_MEMORY; for (uint i=0; i < loadBlockCount; ++i) { patchBlocks[i].data = loadBlock[i].data; patchBlocks[i].size = loadBlock[i].size; } result = patcher.Test( patchBlocks, loadBlockCount ); delete [] patchBlocks; } else { result = patcher.Test( loadBlockCount ? loadBlock->data : NULL, loadBlockCount ? loadBlock->size : 0 ); } if (NES_SUCCEEDED(result)) { for (dword i=0, offset=0; i < loadBlockCount; offset += loadBlock[i].size, ++i) patcher.Patch( loadBlock[i].data, loadBlock[i].data, loadBlock[i].size, offset ); } return result; } public: Loader(Type t,const LoadBlock* l,uint c,bool* a) : action ( t == EEPROM ? LOAD_EEPROM : t == TAPE ? LOAD_TAPE : t == TURBOFILE ? LOAD_TURBOFILE : t == DISK ? LOAD_FDS : LOAD_BATTERY ), loadBlock (l), loadBlockCount (c), altered (a) { if (altered) *altered = false; } }; { Loader loader( type, loadBlock, loadBlockCount, altered ); Api::User::fileIoCallback( loader ); } context.checksum.Clear(); for (const LoadBlock* NST_RESTRICT it=loadBlock, *const end=loadBlock+loadBlockCount; it != end; ++it) context.checksum.Compute( it->data, it->size ); } void File::Load(const Type type,Vector& buffer,const dword maxsize) const { NST_ASSERT( maxsize && type != DISK ); class Loader : public Api::User::File { const Action action; Vector& buffer; const dword maxsize; Action GetAction() const throw() { return action; } ulong GetMaxSize() const throw() { return maxsize; } Result SetContent(const void* filedata,ulong filesize) throw() { if (!filedata || !filesize) return RESULT_ERR_INVALID_PARAM; try { buffer.Assign( static_cast(filedata), NST_MIN(filesize,maxsize) ); } catch (const std::bad_alloc&) { return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { return RESULT_ERR_GENERIC; } return RESULT_OK; } Result SetContent(std::istream& stdStream) throw() { try { Nes::Core::Stream::In stream( &stdStream ); if (const ulong length = stream.Length()) { buffer.Resize( NST_MIN(length,maxsize) ); try { stream.Read( buffer.Begin(), buffer.Size() ); } catch (...) { buffer.Destroy(); throw; } } else { return RESULT_ERR_INVALID_PARAM; } } catch (Result result) { return result; } catch (const std::bad_alloc&) { return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { return RESULT_ERR_GENERIC; } return RESULT_OK; } public: Loader(Type t,Vector& b,dword m) : action ( t == EEPROM ? LOAD_EEPROM : t == TAPE ? LOAD_TAPE : t == TURBOFILE ? LOAD_TURBOFILE : LOAD_BATTERY ), buffer (b), maxsize (m) { } }; { Loader loader( type, buffer, maxsize ); Api::User::fileIoCallback( loader ); } if (buffer.Size()) Load( buffer.Begin(), buffer.Size() ); } void File::Save(Type type,const byte* data,dword size) const { const SaveBlock saveBlock = {data,size}; Save( type, &saveBlock, 1 ); } void File::Save(const Type type,const SaveBlock* const saveBlock,const uint saveBlockCount) const { NST_ASSERT( saveBlock && saveBlockCount ); Checksum checksum; for (const SaveBlock *NST_RESTRICT it=saveBlock, *const end=saveBlock+saveBlockCount; it != end; ++it) checksum.Compute( it->data, it->size ); if (checksum != context.checksum) { class Saver : public Api::User::File { const Action action; const SaveBlock* const saveBlock; const uint saveBlockCount; mutable Vector buffer; const Vector original; Action GetAction() const throw() { return action; } ulong GetMaxSize() const throw() { dword size = 0; for (const SaveBlock* NST_RESTRICT it=saveBlock, *const end=saveBlock+saveBlockCount; it != end; ++it) size += it->size; return size; } Result GetContent(const void*& filedata,ulong& filesize) const throw() { if (saveBlockCount <= 1) { filedata = saveBlock->data; filesize = saveBlock->size; } else { if (!buffer.Size()) { try { buffer.Resize( Saver::GetMaxSize() ); } catch (...) { filedata = NULL; filesize = 0; return RESULT_ERR_OUT_OF_MEMORY; } dword offset = 0; for (const SaveBlock* NST_RESTRICT it=saveBlock, *const end=saveBlock+saveBlockCount; it != end; ++it) { std::memcpy( &buffer[offset], it->data, it->size ); offset += it->size; } } filedata = buffer.Begin(); filesize = buffer.Size(); } return RESULT_OK; } Result GetContent(std::ostream& stdStream) const throw() { try { Nes::Core::Stream::Out stream( &stdStream ); for (const SaveBlock* NST_RESTRICT it=saveBlock, *const end=saveBlock+saveBlockCount; it != end; ++it) { if (it->size) stream.Write( it->data, it->size ); } } catch (Result result) { return result; } catch (const std::bad_alloc&) { return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { return RESULT_ERR_GENERIC; } return RESULT_OK; } Result GetPatchContent(Patch format,std::ostream& stream) const throw() { if (!original.Size() || (format != PATCH_UPS && format != PATCH_IPS)) return RESULT_ERR_UNSUPPORTED; const void* data; ulong size; Result result = Saver::GetContent( data, size ); if (NES_FAILED(result)) return result; if (size != original.Size()) return RESULT_ERR_UNSUPPORTED; Patcher patcher; result = patcher.Create ( format == PATCH_UPS ? Patcher::UPS : Patcher::IPS, original.Begin(), static_cast(data), size ); if (NES_FAILED(result)) return result; return patcher.Save( stream ); } public: Saver(Type t,const SaveBlock* s,uint c,const Vector& o) : action ( t == EEPROM ? SAVE_EEPROM : t == TAPE ? SAVE_TAPE : t == TURBOFILE ? SAVE_TURBOFILE : t == DISK ? SAVE_FDS : SAVE_BATTERY ), saveBlock (s), saveBlockCount (c), original (o) { } }; Saver saver( type, saveBlock, saveBlockCount, context.data ); Api::User::fileIoCallback( saver ); } } } } nestopia-1.51.1/source/core/NstFile.hpp000066400000000000000000000042321411157722000177270ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_FILE_H #define NST_FILE_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { template class Vector; class File { struct Context; Context& context; public: File(); ~File(); enum Type { BATTERY, EEPROM, TAPE, TURBOFILE, DISK }; struct LoadBlock { byte* NST_RESTRICT data; dword size; }; struct SaveBlock { const byte* NST_RESTRICT data; dword size; }; void Load(const byte*,dword) const; void Load(byte*,dword,Type) const; void Load(Type,byte*,dword) const; void Load(Type,Vector&,dword) const; void Save(Type,const byte*,dword) const; private: void Load(Type,const LoadBlock*,uint,bool* = NULL) const; void Save(Type,const SaveBlock*,uint) const; public: template void Load(Type type,const LoadBlock (&block)[N]) const { Load( type, block, N ); } template void Save(Type type,const SaveBlock (&block)[N]) const { Save( type, block, N ); } }; } } #endif nestopia-1.51.1/source/core/NstFpuPrecision.hpp000066400000000000000000000031331411157722000214550ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_FPUPRECISION_H #define NST_FPUPRECISION_H #include #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class FpuPrecision { #if defined(NST_WIN32) && defined(_MCW_PC) && defined(_PC_24) && defined(_PC_53) const uint ctrl; public: FpuPrecision() : ctrl(::_controlfp( 0, 0 ) & _MCW_PC) { if (ctrl == _PC_24) ::_controlfp( _PC_53, _MCW_PC ); } ~FpuPrecision() { if (ctrl == _PC_24) ::_controlfp( _PC_24, _MCW_PC ); } #endif }; } } #endif nestopia-1.51.1/source/core/NstHomebrew.cpp000066400000000000000000000131171411157722000206150ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2018-2018 Phil Smith // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include #include "NstCpu.hpp" #include "NstHomebrew.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Homebrew::Homebrew(Cpu& c) : cpu(c) , exitAddress(0) , exitSet(false) , exitPort(NULL) , stdOutAddress(0) , stdOutSet(false) , stdOutPort(NULL) , stdErrAddress(0) , stdErrSet(false) , stdErrPort(NULL) {} Homebrew::~Homebrew() { ClearPorts(); } void Homebrew::Reset() { ActivateExitPort(); ActivateStdOutPort(); ActivateStdErrPort(); } void Homebrew::ClearPorts() { ClearExitPort(); ClearStdOutPort(); ClearStdErrPort(); } Result Homebrew::SetExitPort ( const word address, const bool activate ) { if ( exitSet && exitAddress == address && (!activate || exitPort != NULL) ) return RESULT_NOP; ClearExitPort(); exitAddress = address; exitSet = true; if (activate) return ActivateExitPort(); else return RESULT_OK; } Result Homebrew::ClearExitPort() { exitSet = false; if (exitPort != NULL) { cpu.Unlink ( exitAddress, this, &Homebrew::Peek_Exit, &Homebrew::Poke_Exit ); exitPort = NULL; return RESULT_OK; } else return RESULT_NOP; } Result Homebrew::SetStdOutPort ( const word address, const bool activate ) { if ( stdOutSet && stdOutAddress == address && (!activate || stdOutPort != NULL) ) return RESULT_NOP; ClearStdOutPort(); stdOutAddress = address; stdOutSet = true; if (activate) return ActivateStdOutPort(); else return RESULT_OK; } Result Homebrew::ClearStdOutPort() { stdOutSet = false; if (stdOutPort != NULL) { cpu.Unlink ( stdOutAddress, this, &Homebrew::Peek_StdOut, &Homebrew::Poke_StdOut ); stdOutPort = NULL; return RESULT_OK; } else return RESULT_NOP; } Result Homebrew::SetStdErrPort ( const word address, const bool activate ) { if ( stdErrSet && stdErrAddress == address && (!activate || stdErrPort != NULL) ) return RESULT_NOP; ClearStdErrPort(); stdErrAddress = address; stdErrSet = true; if (activate) return ActivateStdErrPort(); else return RESULT_OK; } Result Homebrew::ClearStdErrPort() { stdErrSet = false; if (stdErrPort != NULL) { cpu.Unlink ( stdErrAddress, this, &Homebrew::Peek_StdErr, &Homebrew::Poke_StdErr ); stdErrPort = NULL; return RESULT_OK; } else return RESULT_NOP; } dword Homebrew::NumPorts() const { return (exitPort != NULL ? 1 : 0) + (stdOutPort != NULL ? 1 : 0) + (stdErrPort != NULL ? 1 : 0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(Homebrew,Exit) { return exitPort->Peek( address ); } NES_POKE_D(Homebrew,Exit) { std::exit( data ); } NES_PEEK_A(Homebrew,StdOut) { return stdOutPort->Peek( address ); } NES_POKE_D(Homebrew,StdOut) { std::cout << (static_cast(data & 0xFF)); if (data == '\n') std::cout << std::flush; } NES_PEEK_A(Homebrew,StdErr) { return stdErrPort->Peek( address ); } NES_POKE_D(Homebrew,StdErr) { std::cerr << (static_cast(data & 0xFF)); if (data == '\n') std::cerr << std::flush; } Result Homebrew::ActivateExitPort() { if (exitSet && exitPort == NULL) { exitPort = cpu.Link ( exitAddress, Cpu::LEVEL_HIGH, this, &Homebrew::Peek_Exit, &Homebrew::Poke_Exit ); return RESULT_OK; } else return RESULT_NOP; } Result Homebrew::ActivateStdOutPort() { if (stdOutSet && stdOutPort == NULL) { stdOutPort = cpu.Link ( stdOutAddress, Cpu::LEVEL_HIGH, this, &Homebrew::Peek_StdOut, &Homebrew::Poke_StdOut ); return RESULT_OK; } else return RESULT_NOP; } Result Homebrew::ActivateStdErrPort() { if (stdErrSet && stdErrPort == NULL) { stdErrPort = cpu.Link ( stdErrAddress, Cpu::LEVEL_HIGH, this, &Homebrew::Peek_StdErr, &Homebrew::Poke_StdErr ); return RESULT_OK; } else return RESULT_NOP; } } } nestopia-1.51.1/source/core/NstHomebrew.hpp000066400000000000000000000041631411157722000206230ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2018-2018 Phil Smith // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_HOMEBREW_H #define NST_HOMEBREW_H #ifndef NST_VECTOR_H #include "NstVector.hpp" #endif #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class Homebrew { public: explicit Homebrew(Cpu&); ~Homebrew(); void Reset(); void ClearPorts(); Result SetExitPort (word,bool); Result ClearExitPort (); Result SetStdOutPort (word,bool); Result ClearStdOutPort (); Result SetStdErrPort (word,bool); Result ClearStdErrPort (); dword NumPorts () const; private: NES_DECL_PEEK( Exit ); NES_DECL_POKE( Exit ); NES_DECL_PEEK( StdOut ); NES_DECL_POKE( StdOut ); NES_DECL_PEEK( StdErr ); NES_DECL_POKE( StdErr ); Result ActivateExitPort (); Result ActivateStdOutPort (); Result ActivateStdErrPort (); Cpu& cpu; word exitAddress; ibool exitSet; const Io::Port* exitPort; word stdOutAddress; ibool stdOutSet; const Io::Port* stdOutPort; word stdErrAddress; ibool stdErrSet; const Io::Port* stdErrPort; }; } } #endif nestopia-1.51.1/source/core/NstHook.hpp000066400000000000000000000075721411157722000177620ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_HOOK_H #define NST_HOOK_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { #ifdef NST_FASTDELEGATE class Hook : public ImplicitBool { class Component {}; typedef void (Component::*Executor)(); Component* component; Executor executor; NST_COMPILE_ASSERT( sizeof(Executor) <= sizeof(void (*)(void*)) ); public: Hook() {} template Hook(T* c,void (T::*e)()) : component ( reinterpret_cast(c) ), executor ( reinterpret_cast(e) ) { NST_COMPILE_ASSERT( sizeof(executor) == sizeof(e) ); } void Execute() const { (*component.*executor)(); } void Unset() { component = NULL; executor = NULL; } bool operator ! () const { return !executor; } bool operator == (const Hook& h) const { return executor == h.executor && component == h.component; } }; #define NES_DECL_HOOK(a_) void Hook_##a_() #define NES_HOOK(o_,a_) void o_::Hook_##a_() #define NES_HOOK_T(t_,o_,a_) t_ void o_::Hook_##a_() #define NES_DO_HOOK(a_) Hook_##a_() #else class Hook : public ImplicitBool { typedef void* Component; typedef void (NST_REGCALL *Executor)(Component); Component component; Executor executor; public: Hook() {} Hook(Component c,Executor e) : component ( c ), executor ( e ) {} void Execute() const { executor( component ); } void Unset() { component = NULL; executor = NULL; } bool operator ! () const { return !executor; } bool operator == (const Hook& h) const { return executor == h.executor && component == h.component; } }; #define NES_DECL_HOOK(a_) \ \ NST_FORCE_INLINE void NST_FASTCALL Hook_M_##a_(); \ static void NST_REGCALL Hook_##a_(void*) #define NES_HOOK(o_,a_) \ \ void NST_REGCALL o_::Hook_##a_(void* p_) \ { \ static_cast(p_)->Hook_M_##a_(); \ } \ \ NST_FORCE_INLINE void NST_FASTCALL o_::Hook_M_##a_() #define NES_HOOK_T(t_,o_,a_) \ \ t_ void NST_REGCALL o_::Hook_##a_(void* p_) \ { \ static_cast(p_)->Hook_M_##a_(); \ } \ \ t_ NST_FORCE_INLINE void NST_FASTCALL o_::Hook_M_##a_() #define NES_DO_HOOK(a_) Hook_##a_(this) #endif } } #endif nestopia-1.51.1/source/core/NstImage.cpp000066400000000000000000000053071411157722000200710ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstStream.hpp" #include "NstCartridge.hpp" #include "NstFds.hpp" #include "NstNsf.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Image::Image(Type t) : type(t) {} Image* Image::Load(Context& context) { switch (Stream::In(&context.stream).Peek32()) { case INES_ID: case UNIF_ID: default: if (context.type == CARTRIDGE || context.type == UNKNOWN) return new Cartridge (context); break; case FDS_ID: case FDS_RAW_ID: if (context.type == DISK || context.type == UNKNOWN) return new Fds (context); break; case NSF_ID: if (context.type == SOUND || context.type == UNKNOWN) return new Nsf (context); break; } throw RESULT_ERR_INVALID_FILE; } void Image::Unload(Image* image) { delete image; } uint Image::GetDesiredController(uint port) const { switch (port) { case Api::Input::PORT_1: return Api::Input::PAD1; case Api::Input::PORT_2: return Api::Input::PAD2; default: return Api::Input::UNCONNECTED; } } uint Image::GetDesiredAdapter() const { return Api::Input::ADAPTER_NES; } System Image::GetDesiredSystem(Region region,CpuModel* cpu,PpuModel* ppu) const { if (region == REGION_NTSC) { if (cpu) *cpu = CPU_RP2A03; if (ppu) *ppu = PPU_RP2C02; return SYSTEM_NES_NTSC; } else { if (cpu) *cpu = CPU_RP2A07; if (ppu) *ppu = PPU_RP2C07; return SYSTEM_NES_PAL; } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } nestopia-1.51.1/source/core/NstImage.hpp000066400000000000000000000065611411157722000201010ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_IMAGE_H #define NST_IMAGE_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include namespace Nes { namespace Core { namespace State { class Loader; class Saver; } class ImageDatabase; class Cpu; class Apu; class Ppu; class NST_NO_VTABLE Image { public: enum Type { UNKNOWN = 0x0, CARTRIDGE = 0x1, DISK = 0x2, SOUND = 0x4 }; typedef void* ExternalDevice; enum ExternalDeviceType { EXT_DIP_SWITCHES = 1, EXT_BARCODE_READER }; struct Context { const Type type; Cpu& cpu; Apu& apu; Ppu& ppu; std::istream& stream; std::istream* const patch; const bool patchBypassChecksum; Result* const patchResult; const FavoredSystem favoredSystem; const bool askProfile; const ImageDatabase* const database; Result result; Context(Type t,Cpu& c,Apu& a,Ppu& p,std::istream& s,std::istream* h,bool k,Result* r,FavoredSystem f,bool b,const ImageDatabase* d) : type(t), cpu(c), apu(a), ppu(p), stream(s), patch(h), patchBypassChecksum(k), patchResult(r), favoredSystem(f), askProfile(b), database(d), result(RESULT_OK) {} }; static Image* Load(Context&); static void Unload(Image*); virtual void Reset(bool) = 0; virtual bool PowerOff() { return true; } virtual void VSync() {} virtual void LoadState(State::Loader&) {} virtual void SaveState(State::Saver&,dword) const {} virtual uint GetDesiredController(uint) const; virtual uint GetDesiredAdapter() const; virtual Region GetDesiredRegion() const = 0; virtual System GetDesiredSystem(Region,CpuModel* = NULL,PpuModel* = NULL) const; virtual dword GetPrgCrc() const { return 0; } virtual ExternalDevice QueryExternalDevice(ExternalDeviceType) { return NULL; } protected: explicit Image(Type); virtual ~Image() {} enum { INES_ID = AsciiId<'N','E','S'>::V | 0x1AUL << 24, UNIF_ID = AsciiId<'U','N','I','F'>::V, FDS_ID = AsciiId<'F','D','S'>::V | 0x1AUL << 24, FDS_RAW_ID = 0x494E2A01, NSF_ID = AsciiId<'N','E','S','M'>::V }; private: const Type type; public: Type GetType() const { return type; } }; } } #endif nestopia-1.51.1/source/core/NstImageDatabase.cpp000066400000000000000000001273431411157722000215230ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include "NstLog.hpp" #include "NstImageDatabase.hpp" #include "NstXml.hpp" namespace Nes { namespace Core { class ImageDatabase::Item { public: ~Item(); enum { PERIPHERAL_UNSPECIFIED, PERIPHERAL_STANDARD, PERIPHERAL_ZAPPER, PERIPHERAL_POWERPAD, PERIPHERAL_FAMILYTRAINER, PERIPHERAL_ARKANOID, PERIPHERAL_FOURPLAYER, PERIPHERAL_3DGLASSES, PERIPHERAL_MIRACLEPIANO, PERIPHERAL_SUBORKEYBOARD, PERIPHERAL_SUBORMOUSE, PERIPHERAL_FAMILYKEYBOARD, PERIPHERAL_PARTYTAP, PERIPHERAL_CRAZYCLIMBER, PERIPHERAL_EXCITINGBOXING, PERIPHERAL_KONAMIHYPERSHOT, PERIPHERAL_BANDAIHYPERSHOT, PERIPHERAL_POKKUNMOGURAA, PERIPHERAL_OEKAKIDSTABLET, PERIPHERAL_MAHJONG, PERIPHERAL_ROB, PERIPHERAL_POWERGLOVE, PERIPHERAL_HORITRACK, PERIPHERAL_PACHINKO, PERIPHERAL_TOPRIDERBIKE, PERIPHERAL_DOREMIKKO, PERIPHERAL_TURBOFILE, PERIPHERAL_BARCODEWORLD, MAX_PERIPHERALS = 4 }; private: class String { union { mutable wcstring string; dword id; }; public: explicit String(dword i=0) : id(i) {} bool operator == (const String& s) const { return id == s.id; } bool operator < (const String& s) const { return id < s.id; } void operator << (wcstring s) const { string = s + id; } operator wcstring () const { return string; } }; public: struct Ic { struct Pin { uint number; String function; Pin() {} Pin(uint n,dword s) : number(n), function(s) {} }; typedef std::vector Pins; String package; Pins pins; Ic() {} Ic(dword p,const Pins& i) : package(p), pins(i) {} }; struct Rom : Ic { dword id; String name; dword size; Hash hash; Rom() {} Rom(dword i,dword n,dword s,dword e,const Pins& p,const Hash& c) : Ic(e,p), id(i), name(n), size(s), hash(c) {} }; typedef std::vector Roms; struct Ram : Ic { dword id; dword size; bool battery; Ram() {} Ram(dword i,dword s,bool b,dword e,const Pins& p) : Ic(e,p), id(i), size(s), battery(b) {} }; typedef std::vector Rams; struct Chip : Ic { String type; bool battery; Chip() {} Chip(dword id,bool b,dword e,const Pins& p) : Ic(e,p), type(id), battery(b) {} bool operator == (const Chip& chip) const { return type == chip.type; } bool operator < (const Chip& chip) const { return type < chip.type; } }; typedef std::vector Chips; struct Dump { const String by; const String date; const Profile::Dump::State state; Dump(dword b,dword d,Profile::Dump::State o) : by(b), date(d), state(o) {} }; struct Property { String name; String value; Property() {} Property(dword n,dword v) : name(n), value(v) {} }; typedef std::vector Properties; private: const Hash hash; Item* sibling; const Dump dump; const String title; const String altTitle; const String clss; const String subClss; const String catalog; const String publisher; const String developer; const String portDeveloper; const String region; const String revision; const String pcb; const String board; const String cic; const Roms prg; const Roms chr; const Rams wram; const Rams vram; Chips chips; const Properties properties; byte peripherals[MAX_PERIPHERALS]; const word mapper; const byte solderPads; const byte system; const byte cpu; const byte ppu; const byte players; bool multiRegion; public: Item ( const Hash& hashIn, dword dumpBy, dword dumpDate, Profile::Dump::State dumpState, dword titleIn, dword altTitleIn, dword clssIn, dword subClssIn, dword catalogIn, dword publisherIn, dword developerIn, dword portDeveloperIn, dword regionIn, const Properties& propertiesIn, dword playersIn, const byte (&e)[MAX_PERIPHERALS], Profile::System::Type systemIn, Profile::System::Cpu cpuIn, Profile::System::Ppu ppuIn, dword revisionIn, dword boardIn, dword pcbIn, uint mapperIn, const Roms& prgIn, const Roms& chrIn, const Rams& wramIn, const Rams& vramIn, const Chips& chipsIn, dword cicIn, uint solderPadsIn ) : hash ( hashIn ), sibling ( NULL ), dump ( dumpBy, dumpDate, dumpState ), title ( titleIn ), altTitle ( altTitleIn ), clss ( clssIn ), subClss ( subClssIn ), catalog ( catalogIn ), publisher ( publisherIn ), developer ( developerIn ), portDeveloper ( portDeveloperIn ), region ( regionIn ), revision ( revisionIn ), pcb ( pcbIn ), board ( boardIn ), cic ( cicIn ), prg ( prgIn ), chr ( chrIn ), wram ( wramIn ), vram ( vramIn ), chips ( chipsIn ), properties ( propertiesIn ), mapper ( mapperIn ), solderPads ( solderPadsIn ), system ( systemIn ), cpu ( cpuIn ), ppu ( ppuIn ), players ( playersIn ), multiRegion ( false ) { for (uint i=0; i < MAX_PERIPHERALS; ++i) peripherals[i] = e[i]; std::sort( chips.begin(), chips.end() ); } private: template static dword GetMemSize(const T& t) { dword size = 0; for (typename T::const_iterator it(t.begin()), end(t.end()); it != end; ++it) size += it->size; return size; } template static bool HasBattery(const T& t) { for (typename T::const_iterator it(t.begin()), end(t.end()); it != end; ++it) { if (it->battery) return true; } return false; } public: wcstring GetTitle() const { return title; } wcstring GetPublisher() const { return publisher; } wcstring GetDeveloper() const { return developer; } wcstring GetRegion() const { return region; } wcstring GetRevision() const { return revision; } wcstring GetPcb() const { return pcb; } wcstring GetBoard() const { return board; } wcstring GetCic() const { return cic; } uint NumPlayers() const { return players; } uint GetMapper() const { return mapper; } uint GetSolderPads() const { return solderPads; } Profile::System::Type GetSystem() const { return static_cast(system); } Profile::Dump::State GetDumpState() const { return dump.state; } const Hash& GetHash() const { return hash; } dword GetPrgSize() const { return GetMemSize( prg ); } dword GetChrSize() const { return GetMemSize( chr ); } dword GetWramSize() const { return GetMemSize( wram ); } dword GetVramSize() const { return GetMemSize( vram ); } bool HasVRamBattery() const { return HasBattery( vram ); } bool HasWRamBattery() const { return HasBattery( wram ); } bool HasChipBattery() const { return HasBattery( chips ); } bool HasBattery() const { return HasWRamBattery() || HasVRamBattery() || HasChipBattery(); } const Item* GetNextSibling() const { return sibling; } bool IsMultiRegion() const { return multiRegion; } void Fill(Profile& profile,const bool full) const { if (full) { if (*dump.by) profile.dump.by = dump.by; if (*dump.date) profile.dump.date = dump.date; if (dump.state != Profile::Dump::UNKNOWN) profile.dump.state = dump.state; if (*title) profile.game.title = title; if (*altTitle) profile.game.altTitle = altTitle; if (*clss) profile.game.clss = clss; if (*subClss) profile.game.subClss = subClss; if (*catalog) profile.game.catalog = catalog; if (*publisher) profile.game.publisher = publisher; if (*developer) profile.game.developer = developer; if (*portDeveloper) profile.game.portDeveloper = portDeveloper; if (*region) profile.game.region = region; if (*revision) profile.game.revision = revision; if (players) profile.game.players = players; if (*cic) profile.board.cic = cic; if (*pcb) profile.board.pcb = pcb; if (const dword size = properties.size()) { profile.properties.resize( size ); Profile::Properties::iterator b(profile.properties.begin()); for (Properties::const_iterator a(properties.begin()), end(properties.end()); a != end; ++a, ++b) { b->name = a->name; b->value = a->value; } } } for (uint i=0; i < MAX_PERIPHERALS; ++i) { if (peripherals[i] != PERIPHERAL_UNSPECIFIED) { switch (peripherals[i]) { case PERIPHERAL_STANDARD: profile.game.controllers[0] = Api::Input::PAD1; profile.game.controllers[1] = Api::Input::PAD2; break; case PERIPHERAL_FOURPLAYER: if (system == Profile::System::FAMICOM) profile.game.adapter = Api::Input::ADAPTER_FAMICOM; else profile.game.adapter = Api::Input::ADAPTER_NES; profile.game.controllers[2] = Api::Input::PAD3; profile.game.controllers[3] = Api::Input::PAD4; break; case PERIPHERAL_ZAPPER: if (system == Profile::System::VS_UNISYSTEM || system == Profile::System::VS_DUALSYSTEM) { profile.game.controllers[0] = Api::Input::ZAPPER; profile.game.controllers[1] = Api::Input::UNCONNECTED; } else { profile.game.controllers[1] = Api::Input::ZAPPER; } break; case PERIPHERAL_POWERPAD: case PERIPHERAL_FAMILYTRAINER: if (system == Profile::System::FAMICOM || peripherals[i] == PERIPHERAL_FAMILYTRAINER) { profile.game.controllers[1] = Api::Input::UNCONNECTED; profile.game.controllers[4] = Api::Input::FAMILYTRAINER; } else { profile.game.controllers[1] = Api::Input::POWERPAD; } break; case PERIPHERAL_ARKANOID: if (system == Profile::System::FAMICOM) profile.game.controllers[4] = Api::Input::PADDLE; else profile.game.controllers[1] = Api::Input::PADDLE; break; case PERIPHERAL_SUBORKEYBOARD: profile.game.controllers[4] = Api::Input::SUBORKEYBOARD; break; case PERIPHERAL_SUBORMOUSE: profile.game.controllers[1] = Api::Input::MOUSE; break; case PERIPHERAL_FAMILYKEYBOARD: profile.game.controllers[4] = Api::Input::FAMILYKEYBOARD; break; case PERIPHERAL_PARTYTAP: profile.game.controllers[1] = Api::Input::UNCONNECTED; profile.game.controllers[4] = Api::Input::PARTYTAP; break; case PERIPHERAL_CRAZYCLIMBER: profile.game.controllers[4] = Api::Input::CRAZYCLIMBER; break; case PERIPHERAL_EXCITINGBOXING: profile.game.controllers[4] = Api::Input::EXCITINGBOXING; break; case PERIPHERAL_BANDAIHYPERSHOT: profile.game.controllers[4] = Api::Input::BANDAIHYPERSHOT; break; case PERIPHERAL_KONAMIHYPERSHOT: profile.game.controllers[0] = Api::Input::UNCONNECTED; profile.game.controllers[1] = Api::Input::UNCONNECTED; profile.game.controllers[4] = Api::Input::KONAMIHYPERSHOT; break; case PERIPHERAL_POKKUNMOGURAA: profile.game.controllers[1] = Api::Input::UNCONNECTED; profile.game.controllers[4] = Api::Input::POKKUNMOGURAA; break; case PERIPHERAL_OEKAKIDSTABLET: profile.game.controllers[0] = Api::Input::UNCONNECTED; profile.game.controllers[1] = Api::Input::UNCONNECTED; profile.game.controllers[4] = Api::Input::OEKAKIDSTABLET; break; case PERIPHERAL_MAHJONG: profile.game.controllers[0] = Api::Input::UNCONNECTED; profile.game.controllers[1] = Api::Input::UNCONNECTED; profile.game.controllers[4] = Api::Input::MAHJONG; break; case PERIPHERAL_TOPRIDERBIKE: profile.game.controllers[0] = Api::Input::UNCONNECTED; profile.game.controllers[1] = Api::Input::UNCONNECTED; profile.game.controllers[4] = Api::Input::TOPRIDER; break; case PERIPHERAL_HORITRACK: profile.game.controllers[4] = Api::Input::HORITRACK; break; case PERIPHERAL_PACHINKO: profile.game.controllers[4] = Api::Input::PACHINKO; break; case PERIPHERAL_ROB: profile.game.controllers[1] = Api::Input::ROB; break; case PERIPHERAL_DOREMIKKO: profile.game.controllers[4] = Api::Input::DOREMIKKOKEYBOARD; break; case PERIPHERAL_POWERGLOVE: profile.game.controllers[0] = Api::Input::POWERGLOVE; break; case PERIPHERAL_TURBOFILE: profile.game.controllers[4] = Api::Input::TURBOFILE; break; case PERIPHERAL_BARCODEWORLD: profile.game.controllers[4] = Api::Input::BARCODEWORLD; break; } } } profile.multiRegion = multiRegion; profile.system.type = static_cast(system); profile.system.cpu = static_cast(cpu); profile.system.ppu = static_cast(ppu); if (*board) profile.board.type = board; if (mapper != Profile::Board::NO_MAPPER) profile.board.mapper = mapper; profile.board.solderPads = solderPads; for (uint j=0; j < 2; ++j) { if (full || (j ? profile.board.GetChr() == GetChrSize() : profile.board.GetPrg() == GetPrgSize())) { const Roms& src = (j ? chr : prg); Profile::Board::Roms& dst = (j ? profile.board.chr : profile.board.prg); dst.resize( src.size() ); Profile::Board::Roms::iterator b(dst.begin()); for (Roms::const_iterator a(src.begin()), end(src.end()); a != end; ++a, ++b) { b->size = a->size; if (full) { b->name = a->name; b->package = a->package; b->hash = a->hash; } b->pins.resize( a->pins.size() ); Profile::Board::Pins::iterator d(b->pins.begin()); for (Rom::Pins::const_iterator c(a->pins.begin()), end(a->pins.end()); c != end; ++c, ++d) { d->number = c->number; d->function = c->function; } } } } for (uint j=0; j < 2; ++j) { if (full || (j ? profile.board.GetVram() == GetVramSize() : profile.board.GetWram() == GetWramSize())) { const Rams& src = (j ? vram : wram); Profile::Board::Rams& dst = (j ? profile.board.vram : profile.board.wram); dst.resize( src.size() ); Profile::Board::Rams::iterator b(dst.begin()); for (Rams::const_iterator a(src.begin()), end(src.end()); a != end; ++a, ++b) { b->id = a->id; b->size = a->size; b->battery = a->battery; if (full) b->package = a->package; b->pins.resize( a->pins.size() ); Profile::Board::Pins::iterator d(b->pins.begin()); for (Ram::Pins::const_iterator c(a->pins.begin()), end(a->pins.end()); c != end; ++c, ++d) { d->number = c->number; d->function = c->function; } } } } profile.board.chips.resize( chips.size() ); Profile::Board::Chips::iterator b(profile.board.chips.begin()); for (Chips::const_iterator a(chips.begin()), end(chips.end()); a != end; ++a, ++b) { b->type = a->type; b->package = a->package; b->battery = a->battery; b->pins.resize( a->pins.size() ); Profile::Board::Pins::iterator d(b->pins.begin()); for (Chip::Pins::const_iterator c(a->pins.begin()), end(a->pins.end()); c != end; ++c, ++d) { d->number = c->number; d->function = c->function; } } } private: bool operator == (const Item& item) const { return ( system == item.system && mapper == item.mapper && board == item.board && solderPads == item.solderPads && chips.size() == item.chips.size() && cpu == item.cpu && ppu == item.ppu && GetVramSize() == item.GetVramSize() && GetWramSize() == item.GetWramSize() && HasVRamBattery() == item.HasVRamBattery() && HasWRamBattery() == item.HasWRamBattery() && HasChipBattery() == item.HasChipBattery() && std::equal( chips.begin(), chips.end(), item.chips.begin() ) ); } bool Add(Item* const item) { item->multiRegion = this->multiRegion || ( ( this->system == Profile::System::NES_PAL || this->system == Profile::System::NES_PAL_A || this->system == Profile::System::NES_PAL_B || this->system == Profile::System::DENDY ) != ( item->system == Profile::System::NES_PAL || item->system == Profile::System::NES_PAL_A || item->system == Profile::System::NES_PAL_B || item->system == Profile::System::DENDY ) ); Item* it = this; for (;;) { if (*it == *item) return false; it->multiRegion = item->multiRegion; if (!it->sibling) break; it = it->sibling; } it->sibling = item; return true; } void Finalize(wcstring const lut) const { dump.by << lut; dump.date << lut; title << lut; altTitle << lut; clss << lut; subClss << lut; catalog << lut; developer << lut; portDeveloper << lut; publisher << lut; region << lut; revision << lut; pcb << lut; board << lut; cic << lut; for (uint i=0; i < 2; ++i) { for (Roms::const_iterator j((i ? chr : prg).begin()), end((i ? chr : prg).end()); j != end; ++j) { j->name << lut; j->package << lut; for (Ic::Pins::const_iterator k(j->pins.begin()), end(j->pins.end()); k != end; ++k) k->function << lut; } } for (uint i=0; i < 2; ++i) { for (Rams::const_iterator j((i ? wram : vram).begin()), end((i ? wram : vram).end()); j != end; ++j) j->package << lut; } for (Chips::const_iterator i(chips.begin()), end(chips.end()); i != end; ++i) { i->type << lut; i->package << lut; for (Ic::Pins::const_iterator j(i->pins.begin()), end(i->pins.end()); j != end; ++j) j->function << lut; } for (Properties::const_iterator i(properties.begin()), end(properties.end()); i != end; ++i) { i->name << lut; i->value << lut; } if (sibling) sibling->Finalize( lut ); } public: struct Less { bool operator () (const Item* a,const Item* b) const { return a->hash < b->hash; } bool operator () (const Item* a,const Hash& b) const { return a->hash < b; } bool operator () (const Hash& a,const Item* b) const { return a < b->hash; } }; class Builder { public: ~Builder(); dword operator << (wcstring); void operator << (Item*); private: struct Less { bool operator () (wcstring a,wcstring b) const { return std::wcscmp( a, b ) < 0; } bool operator () (const Item* a,const Item* b) const { return a->hash < b->hash; } }; typedef std::map StringMap; typedef std::set ItemMap; dword stringLength; StringMap stringMap; ItemMap itemMap; public: Builder() : stringLength(0) { (*this) << L""; } void Construct(Strings& strings,const Item**& itemsBegin,const Item**& itemsEnd) { NST_ASSERT( !strings.Size() && itemsBegin == NULL && itemsEnd == NULL ); if (const dword size = itemMap.size()) { strings.Resize( stringLength ); wchar_t* const NST_RESTRICT sdst = strings.Begin(); for (StringMap::const_iterator src(stringMap.begin()), end(stringMap.end()); src != end; ++src) std::wcscpy( sdst + src->second, src->first ); const Item** dst = new const Item* [size]; itemsBegin = dst; itemsEnd = dst + size; for (ItemMap::const_iterator src(itemMap.begin()), end(itemMap.end()); src != end; ++src, ++dst) { (*src)->Finalize( sdst ); *dst = *src; } itemMap.clear(); } } }; }; ImageDatabase::ImageDatabase() : enabled(true) { items.begin = NULL; items.end = NULL; items.hashing = HASHING_DETECT; } ImageDatabase::~ImageDatabase() { Unload(); } ImageDatabase::Entry ImageDatabase::Search(const Hash& hash,const FavoredSystem favoredSystem) const { if (items.begin) { const Hash searchHash ( ( items.hashing & HASHING_SHA1 ) ? hash.GetSha1() : NULL, ( items.hashing & HASHING_CRC ) ? hash.GetCrc32() : 0UL ); const Item** item = std::lower_bound( items.begin, items.end, searchHash, Item::Less() ); if (item != items.end && (*item)->GetHash() == searchHash) { for (const Item* it = *item; it; it = it->GetNextSibling()) { switch (it->GetSystem()) { case Profile::System::NES_NTSC: if (favoredSystem == FAVORED_NES_NTSC) return it; break; case Profile::System::NES_PAL: case Profile::System::NES_PAL_A: case Profile::System::NES_PAL_B: if (favoredSystem == FAVORED_NES_PAL) return it; break; case Profile::System::FAMICOM: if (favoredSystem == FAVORED_FAMICOM) return it; break; case Profile::System::DENDY: if (favoredSystem == FAVORED_DENDY) return it; break; case Profile::System::VS_UNISYSTEM: case Profile::System::VS_DUALSYSTEM: case Profile::System::PLAYCHOICE_10: default: break; } } return *item; } } return NULL; } wcstring ImageDatabase::Entry::GetTitle() const { return item ? item->GetTitle() : L""; } wcstring ImageDatabase::Entry::GetPublisher() const { return item ? item->GetPublisher() : L""; } wcstring ImageDatabase::Entry::GetDeveloper() const { return item ? item->GetDeveloper() : L""; } wcstring ImageDatabase::Entry::GetRegion() const { return item ? item->GetRegion() : L""; } wcstring ImageDatabase::Entry::GetRevision() const { return item ? item->GetRevision() : L""; } wcstring ImageDatabase::Entry::GetPcb() const { return item ? item->GetPcb() : L""; } wcstring ImageDatabase::Entry::GetBoard() const { return item ? item->GetBoard() : L""; } wcstring ImageDatabase::Entry::GetCic() const { return item ? item->GetCic() : L""; } uint ImageDatabase::Entry::NumPlayers() const { return item ? item->NumPlayers() : 0; } uint ImageDatabase::Entry::GetMapper() const { return item ? item->GetMapper() : Profile::Board::NO_MAPPER; } uint ImageDatabase::Entry::GetSolderPads() const { return item ? item->GetSolderPads() : 0; } ImageDatabase::Profile::System::Type ImageDatabase::Entry::GetSystem() const { return item ? item->GetSystem() : Profile::System::NES_NTSC; } bool ImageDatabase::Entry::IsMultiRegion() const { return item && item->IsMultiRegion(); } ImageDatabase::Profile::Dump::State ImageDatabase::Entry::GetDumpState() const { return item ? item->GetDumpState() : Profile::Dump::UNKNOWN; } const ImageDatabase::Hash* ImageDatabase::Entry::GetHash() const { return item ? &item->GetHash() : NULL; } dword ImageDatabase::Entry::GetPrg() const { return item ? item->GetPrgSize() : 0; } dword ImageDatabase::Entry::GetChr() const { return item ? item->GetChrSize() : 0; } dword ImageDatabase::Entry::GetWram() const { return item ? item->GetWramSize() : 0; } dword ImageDatabase::Entry::GetVram() const { return item ? item->GetVramSize() : 0; } bool ImageDatabase::Entry::HasBattery() const { return item && item->HasBattery(); } void ImageDatabase::Entry::Fill(Profile& profile,bool full) const { if (item) item->Fill( profile, full ); } Result ImageDatabase::Load(std::istream& baseStream,std::istream* overrideStream) { Unload(); try { Xml baseXml, overrideXml; Item::Builder builder; for (uint multi=0; multi < (overrideStream ? 2 : 1); ++multi) { Xml& xml = (multi ? overrideXml : baseXml); try { if (!xml.Read( multi ? *overrideStream : baseStream )) return RESULT_ERR_CORRUPT_FILE; } catch (...) { throw RESULT_ERR_CORRUPT_FILE; } if (!xml.GetRoot().IsType( L"database" )) return RESULT_ERR_INVALID_FILE; if (const Xml::Attribute attribute=xml.GetRoot().GetAttribute( L"version" )) { wcstring const version = attribute.GetValue(); if ( (version[0] < L'1' || version[0] > L'9') || (version[1] != L'.') || (version[2] < L'0' || version[2] > L'9') || (version[3] != L'\0') ) throw RESULT_ERR_INVALID_FILE; } const bool strict = !xml.GetRoot().GetAttribute( L"conformance" ).IsValue( L"loose" ); for (Xml::Node game(xml.GetRoot().GetFirstChild()); game.IsType( L"game" ); game=game.GetNextSibling()) { byte peripherals[4] = { Item::PERIPHERAL_UNSPECIFIED, Item::PERIPHERAL_UNSPECIFIED, Item::PERIPHERAL_UNSPECIFIED, Item::PERIPHERAL_UNSPECIFIED }; if (Xml::Node device=game.GetChild( L"peripherals" )) { uint i = 0; for (device=device.GetFirstChild(); i < 4 && device.IsType( L"device" ); device=device.GetNextSibling()) { if (const Xml::Attribute attribute = device.GetAttribute( L"type" )) { if (attribute.IsValue( L"3dglasses" )) peripherals[i++] = Item::PERIPHERAL_3DGLASSES; else if (attribute.IsValue( L"arkanoid" )) peripherals[i++] = Item::PERIPHERAL_ARKANOID; else if (attribute.IsValue( L"bandaihypershot" )) peripherals[i++] = Item::PERIPHERAL_BANDAIHYPERSHOT; else if (attribute.IsValue( L"barcodeworld" )) peripherals[i++] = Item::PERIPHERAL_BARCODEWORLD; else if (attribute.IsValue( L"crazyclimber" )) peripherals[i++] = Item::PERIPHERAL_CRAZYCLIMBER; else if (attribute.IsValue( L"doremikko" )) peripherals[i++] = Item::PERIPHERAL_DOREMIKKO; else if (attribute.IsValue( L"excitingboxing" )) peripherals[i++] = Item::PERIPHERAL_EXCITINGBOXING; else if (attribute.IsValue( L"familykeyboard" )) peripherals[i++] = Item::PERIPHERAL_FAMILYKEYBOARD; else if (attribute.IsValue( L"familyfunfitness" )) peripherals[i++] = Item::PERIPHERAL_POWERPAD; else if (attribute.IsValue( L"familytrainer" )) peripherals[i++] = Item::PERIPHERAL_FAMILYTRAINER; else if (attribute.IsValue( L"fourplayer" )) peripherals[i++] = Item::PERIPHERAL_FOURPLAYER; else if (attribute.IsValue( L"horitrack" )) peripherals[i++] = Item::PERIPHERAL_HORITRACK; else if (attribute.IsValue( L"konamihypershot" )) peripherals[i++] = Item::PERIPHERAL_KONAMIHYPERSHOT; else if (attribute.IsValue( L"mahjong" )) peripherals[i++] = Item::PERIPHERAL_MAHJONG; else if (attribute.IsValue( L"miraclepiano" )) peripherals[i++] = Item::PERIPHERAL_MIRACLEPIANO; else if (attribute.IsValue( L"oekakidstablet" )) peripherals[i++] = Item::PERIPHERAL_OEKAKIDSTABLET; else if (attribute.IsValue( L"pachinko" )) peripherals[i++] = Item::PERIPHERAL_PACHINKO; else if (attribute.IsValue( L"partytap" )) peripherals[i++] = Item::PERIPHERAL_PARTYTAP; else if (attribute.IsValue( L"pokkunmoguraa" )) peripherals[i++] = Item::PERIPHERAL_POKKUNMOGURAA; else if (attribute.IsValue( L"powerglove" )) peripherals[i++] = Item::PERIPHERAL_POWERGLOVE; else if (attribute.IsValue( L"powerpad" )) peripherals[i++] = Item::PERIPHERAL_POWERPAD; else if (attribute.IsValue( L"rob" )) peripherals[i++] = Item::PERIPHERAL_ROB; else if (attribute.IsValue( L"suborkeyboard" )) peripherals[i++] = Item::PERIPHERAL_SUBORKEYBOARD; else if (attribute.IsValue( L"subormouse" )) peripherals[i++] = Item::PERIPHERAL_SUBORMOUSE; else if (attribute.IsValue( L"topriderbike" )) peripherals[i++] = Item::PERIPHERAL_TOPRIDERBIKE; else if (attribute.IsValue( L"turbofile" )) peripherals[i++] = Item::PERIPHERAL_TURBOFILE; else if (attribute.IsValue( L"zapper" )) peripherals[i++] = Item::PERIPHERAL_ZAPPER; } } } for (Xml::Node image(game.GetFirstChild()); image; image=image.GetNextSibling()) { Profile::System::Type system = Profile::System::NES_NTSC; Profile::System::Cpu cpu = Profile::System::CPU_RP2A03; Profile::System::Ppu ppu = Profile::System::PPU_RP2C02; if (image.IsType( L"cartridge" )) { if (const Xml::Attribute attribute=image.GetAttribute( L"system" )) { if (attribute.IsValue( L"famicom" )) { system = Profile::System::FAMICOM; } else if (attribute.IsValue( L"nes-ntsc" )) { system = Profile::System::NES_NTSC; } else if (attribute.IsValue( L"nes-pal" )) { system = Profile::System::NES_PAL; cpu = Profile::System::CPU_RP2A07; ppu = Profile::System::PPU_RP2C07; } else if (attribute.IsValue( L"nes-pal-a" )) { system = Profile::System::NES_PAL_A; cpu = Profile::System::CPU_RP2A07; ppu = Profile::System::PPU_RP2C07; } else if (attribute.IsValue( L"nes-pal-b" )) { system = Profile::System::NES_PAL_B; cpu = Profile::System::CPU_RP2A07; ppu = Profile::System::PPU_RP2C07; } else if (attribute.IsValue( L"dendy" )) { system = Profile::System::DENDY; cpu = Profile::System::CPU_DENDY; ppu = Profile::System::PPU_DENDY; } else if (strict) { continue; } } else if (strict) { continue; } } else if (image.IsType( L"arcade" )) { ppu = Profile::System::PPU_RP2C03B; if (const Xml::Attribute attribute=image.GetAttribute( L"system" )) { if (attribute.IsValue( L"vs-unisystem" )) { system = Profile::System::VS_UNISYSTEM; } else if (attribute.IsValue( L"vs-dualsystem" )) { system = Profile::System::VS_DUALSYSTEM; } else if (attribute.IsValue( L"playchoice-10" )) { system = Profile::System::PLAYCHOICE_10; } else { continue; } } else { continue; } } else { continue; } if (system == Profile::System::VS_UNISYSTEM || system == Profile::System::VS_DUALSYSTEM) { if (const Xml::Attribute attribute=image.GetAttribute( L"ppu" )) { if (attribute.IsValue( L"rp2c03b" )) ppu = Profile::System::PPU_RP2C03B; else if (attribute.IsValue( L"rp2c03g" )) ppu = Profile::System::PPU_RP2C03G; else if (attribute.IsValue( L"rp2c04-0001" )) ppu = Profile::System::PPU_RP2C04_0001; else if (attribute.IsValue( L"rp2c04-0002" )) ppu = Profile::System::PPU_RP2C04_0002; else if (attribute.IsValue( L"rp2c04-0003" )) ppu = Profile::System::PPU_RP2C04_0003; else if (attribute.IsValue( L"rp2c04-0004" )) ppu = Profile::System::PPU_RP2C04_0004; else if (attribute.IsValue( L"rc2c03b" )) ppu = Profile::System::PPU_RC2C03B; else if (attribute.IsValue( L"rc2c03c" )) ppu = Profile::System::PPU_RC2C03C; else if (attribute.IsValue( L"rc2c05-01" )) ppu = Profile::System::PPU_RC2C05_01; else if (attribute.IsValue( L"rc2c05-02" )) ppu = Profile::System::PPU_RC2C05_02; else if (attribute.IsValue( L"rc2c05-03" )) ppu = Profile::System::PPU_RC2C05_03; else if (attribute.IsValue( L"rc2c05-04" )) ppu = Profile::System::PPU_RC2C05_04; else if (attribute.IsValue( L"rc2c05-05" )) ppu = Profile::System::PPU_RC2C05_05; } } Profile::Dump::State dump = Profile::Dump::OK; if (const Xml::Attribute attribute=image.GetAttribute( L"dump" )) { if (attribute.IsValue( L"bad" )) { if (strict) continue; dump = Profile::Dump::BAD; } else if (attribute.IsValue( L"unknown" )) { if (strict) continue; dump = Profile::Dump::UNKNOWN; } } if (items.hashing == HASHING_DETECT) { if (*image.GetAttribute( L"sha1" ).GetValue()) items.hashing |= HASHING_SHA1; if (*image.GetAttribute( L"crc" ).GetValue()) items.hashing |= HASHING_CRC; } const Hash hash ( ( items.hashing & HASHING_SHA1 ) ? image.GetAttribute( L"sha1" ).GetValue() : L"", ( items.hashing & HASHING_CRC ) ? image.GetAttribute( L"crc" ).GetValue() : L"" ); if (!hash) continue; if (const Xml::Node board=image.GetChild( L"board" )) { uint players = 0; if (const Xml::Attribute attribute=game.GetAttribute( L"players" )) { ulong value = attribute.GetUnsignedValue(); if (value >= MIN_PLAYERS && value <= MAX_PLAYERS) players = value; } uint mapper = Profile::Board::NO_MAPPER; if (const Xml::Attribute attribute=board.GetAttribute( L"mapper" )) { ulong value = attribute.GetUnsignedValue(); if (value <= MAX_MAPPER) mapper = value; } uint solderPads = 0; if (const Xml::Node pad=board.GetChild( L"pad" )) { solderPads = ( (pad.GetAttribute( L"h" ).IsValue( L"1" ) ? Profile::Board::SOLDERPAD_H : 0U) | (pad.GetAttribute( L"v" ).IsValue( L"1" ) ? Profile::Board::SOLDERPAD_V : 0U) ); } Item::Properties properties; if (Xml::Node node=image.GetChild( L"properties" )) { for (node=node.GetFirstChild(); node.IsType( L"property" ); node=node.GetNextSibling()) { properties.push_back ( Item::Property ( builder << node.GetAttribute(L"name").GetValue(), builder << node.GetAttribute(L"value").GetValue() ) ); } } Item::Roms prg, chr; Item::Rams wram, vram; Item::Chips chips; for (Xml::Node node=board.GetFirstChild(); node; node=node.GetNextSibling()) { dword size = 0; if (const Xml::Attribute attribute=node.GetAttribute( L"size" )) { wcstring end; const ulong value = attribute.GetUnsignedValue( end, 10 ); if (end[0] == L'\0') { size = value; } else if ((end[0] == L'k' || end[0] == L'K') && end[1] == L'\0' && value <= MAX_CHIP_SIZE/SIZE_1K) { size = value * SIZE_1K; } } Item::Ic::Pins pins; for (Xml::Node child(node.GetFirstChild()); child; child=child.GetNextSibling()) { if (child.IsType(L"pin")) { const ulong number = child.GetAttribute(L"number").GetUnsignedValue(); wcstring const function = child.GetAttribute(L"function").GetValue(); if (number >= MIN_IC_PINS && number <= MAX_IC_PINS && *function) pins.push_back( Item::Ic::Pin(number,builder << function) ); } } bool first; if (true == (first=node.IsType( L"prg" )) || node.IsType( L"chr" )) { if (size >= MIN_CHIP_SIZE && size <= MAX_CHIP_SIZE) { (first ? prg : chr).push_back ( Item::Rom ( node.GetAttribute( L"id" ).GetUnsignedValue(), builder << node.GetAttribute( L"name" ).GetValue(), size, builder << node.GetAttribute( L"package" ).GetValue(), pins, Hash(node.GetAttribute( L"sha1" ).GetValue(),node.GetAttribute( L"crc" ).GetValue()) ) ); } } else if (true == (first=node.IsType( L"wram" )) || node.IsType( L"vram" )) { if (size >= MIN_CHIP_SIZE && size <= MAX_CHIP_SIZE) { (first ? wram : vram).push_back ( Item::Ram ( node.GetAttribute( L"id" ).GetUnsignedValue(), size, node.GetAttribute( L"battery" ).IsValue( L"1" ), builder << node.GetAttribute( L"package" ).GetValue(), pins ) ); } } else if (node.IsType( L"chip" )) { chips.push_back ( Item::Chip ( builder << node.GetAttribute( L"type" ).GetValue(), node.GetAttribute( L"battery" ).IsValue( L"1" ), builder << node.GetAttribute( L"package" ).GetValue(), pins ) ); } } builder << new Item ( hash, builder << image.GetAttribute( L"dumper" ).GetValue(), builder << image.GetAttribute( L"datedumped" ).GetValue(), dump, builder << game.GetAttribute( L"name" ).GetValue(), builder << game.GetAttribute( L"altname" ).GetValue(), builder << game.GetAttribute( L"class" ).GetValue(), builder << game.GetAttribute( L"subclass" ).GetValue(), builder << game.GetAttribute( L"catalog" ).GetValue(), builder << game.GetAttribute( L"publisher" ).GetValue(), builder << game.GetAttribute( L"developer" ).GetValue(), builder << game.GetAttribute( L"portdeveloper" ).GetValue(), builder << game.GetAttribute( L"region" ).GetValue(), properties, players, peripherals, system, cpu, ppu, builder << image.GetAttribute( L"revision" ).GetValue(), builder << board.GetAttribute( L"type" ).GetValue(), builder << board.GetAttribute( L"pcb" ).GetValue(), mapper, prg, chr, wram, vram, chips, builder << board.GetChild( L"cic" ).GetAttribute( L"type" ).GetValue(), solderPads ); } } } } builder.Construct( strings, items.begin, items.end ); } catch (Result result) { Unload( true ); return result; } catch (const std::bad_alloc&) { Unload( true ); return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { Unload( true ); return RESULT_ERR_GENERIC; } Log() << "Database: " << (items.end - items.begin) << " items imported from " << (overrideStream ? "internal & external" : "internal") << " DB" NST_LINEBREAK; return RESULT_OK; } void ImageDatabase::Unload(const bool error) { if (const Item** it=items.begin) { do { delete *it; } while (++it != items.end); delete [] items.begin; items.begin = NULL; items.end = NULL; } items.hashing = HASHING_DETECT; strings.Destroy(); if (error) Log::Flush( "Database: error, aborting.." NST_LINEBREAK ); } ImageDatabase::Item::Builder::~Builder() { for (ItemMap::const_iterator it(itemMap.begin()), end(itemMap.end()); it != end; ++it) delete *it; } dword ImageDatabase::Item::Builder::operator << (wcstring string) { const std::pair entry ( stringMap.insert( std::pair(string,stringLength) ) ); if (entry.second) stringLength += std::wcslen(string) + 1; return entry.first->second; } void ImageDatabase::Item::Builder::operator << (Item* item) { std::pair entry; try { entry = itemMap.insert( item ); } catch (...) { delete item; throw; } if (!entry.second && !(*entry.first)->Add(item)) delete item; } ImageDatabase::Item::~Item() { if (const Item* item=sibling) { sibling = NULL; delete item; } } } } nestopia-1.51.1/source/core/NstImageDatabase.hpp000066400000000000000000000067571411157722000215350ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_IMAGEDATABASE_H #define NST_IMAGEDATABASE_H #include "NstVector.hpp" #include "api/NstApiCartridge.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class ImageDatabase { class Item; public: typedef Api::Cartridge::Profile Profile; typedef Profile::Hash Hash; ImageDatabase(); ~ImageDatabase(); class Entry : public ImplicitBool { public: void Fill(Profile&,bool=true) const; private: const Item* item; public: Entry(const void* i=NULL) : item(static_cast(i)) {} const void* Reference() const { return item; } bool operator ! () const { return !item; } const Hash* GetHash() const; wcstring GetTitle() const; wcstring GetPublisher() const; wcstring GetDeveloper() const; wcstring GetRegion() const; wcstring GetRevision() const; wcstring GetPcb() const; wcstring GetBoard() const; wcstring GetCic() const; bool IsMultiRegion() const; uint NumPlayers() const; uint GetMapper() const; uint GetSolderPads() const; Profile::System::Type GetSystem() const; Profile::Dump::State GetDumpState() const; dword GetPrg() const; dword GetChr() const; dword GetWram() const; dword GetVram() const; bool HasBattery() const; }; Entry Search(const Hash&,FavoredSystem) const; private: Result Load(std::istream&,std::istream*); void Unload(bool); typedef Vector Strings; enum { MIN_PLAYERS = 1, MAX_PLAYERS = 255, MAX_MAPPER = 255, MIN_CHIP_SIZE = 1, MAX_CHIP_SIZE = SIZE_16384K, MIN_IC_PINS = 1, MAX_IC_PINS = 127, HASHING_DETECT = 0x0, HASHING_SHA1 = 0x1, HASHING_CRC = 0x2 }; ibool enabled; struct { const Item** begin; const Item** end; uint hashing; } items; Strings strings; public: Result Load(std::istream& stream) { return Load( stream, NULL ); } Result Load(std::istream& baseStream,std::istream& overrideStream) { return Load( baseStream, &overrideStream ); } void Unload() { Unload( false ); } void Enable(bool state=true) { enabled = state; } bool Enabled() const { return enabled; } }; } } #endif nestopia-1.51.1/source/core/NstIoAccessor.hpp000066400000000000000000000076011411157722000211050ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_IO_ACCESSOR_H #define NST_IO_ACCESSOR_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Io { #ifdef NST_FASTDELEGATE class Accessor { public: template struct Type { typedef Data (NST_FASTCALL T::*Function)(Address); }; private: class Component {}; typedef Type::Function Function; Component* component; Function function; public: Accessor() {} template Accessor(T* c,typename Type::Function f) : component ( reinterpret_cast(c) ), function ( reinterpret_cast(f) ) { NST_COMPILE_ASSERT( sizeof(function) == sizeof(f) ); } template void Set(T* c,typename Type::Function f) { NST_COMPILE_ASSERT( sizeof(function) == sizeof(f) ); component = reinterpret_cast(c); function = reinterpret_cast(f); } Data Fetch(Address address) const { return (*component.*function)( address ); } }; #define NES_DECL_ACCESSOR(a_) Data NST_FASTCALL Access_##a_(Address) #define NES_ACCESSOR(o_,a_) Data NST_FASTCALL o_::Access_##a_(Address address) #else class Accessor { typedef void* Component; typedef Data (NST_REGCALL *Function)(Component,Address); Component component; Function function; public: Accessor() {} Accessor(Component c,Function t) : component ( c ), function ( t ) {} void Set(Component c,Function t) { component = c; function = t; } Data Fetch(Address address) const { return function( component, address ); } template struct Type { typedef Data (NST_REGCALL *Function)(Component,Address); }; }; #define NES_DECL_ACCESSOR(a_) \ \ NST_SINGLE_CALL Data NST_FASTCALL Access_M_##a_(Address); \ static NST_NO_INLINE Data NST_REGCALL Access_##a_(void*,Address) #define NES_ACCESSOR(o_,a_) \ \ NST_NO_INLINE Data NST_REGCALL o_::Access_##a_(void* p_,Address i_) \ { \ return static_cast(p_)->Access_M_##a_(i_); \ } \ \ NST_SINGLE_CALL Data NST_FASTCALL o_::Access_M_##a_(Address address) #endif } } } #endif nestopia-1.51.1/source/core/NstIoLine.hpp000066400000000000000000000121101411157722000202210ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_IO_LINE_H #define NST_IO_LINE_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Io { #ifdef NST_FASTDELEGATE class Line : public ImplicitBool { class Component {}; typedef void (NST_FASTCALL Component::*Toggler)(Address,Cycle); Component* component; Toggler toggler; NST_COMPILE_ASSERT( sizeof(Toggler) <= sizeof(void (*)(void*,Address,Cycle)) ); public: Line() {} template Line(T* c,void (NST_FASTCALL T::*t)(Address,Cycle)) : component ( reinterpret_cast(c) ), toggler ( reinterpret_cast(t) ) { NST_COMPILE_ASSERT( sizeof(toggler) == sizeof(t) ); } template void Set(T* c,void (NST_FASTCALL T::*t)(Address,Cycle)) { NST_COMPILE_ASSERT( sizeof(toggler) == sizeof(t) ); component = reinterpret_cast(c); toggler = reinterpret_cast(t); } void Unset() { component = NULL; toggler = NULL; } bool operator ! () const { return component == NULL; } void Toggle(Address address,Cycle cycle) const { (*component.*toggler)( address, cycle ); } }; #define NES_DECL_LINE(a_) void NST_FASTCALL Line_##a_(Address,Cycle) #define NES_LINE(o_,a_) void NST_FASTCALL o_::Line_##a_(Address address,Cycle cycle) #define NES_LINE_T(t_,o_,a_) t_ void NST_FASTCALL o_::Line_##a_(Address address,Cycle cycle) #else class Line : public ImplicitBool { typedef void* Component; typedef void (NST_REGCALL *Toggler)(Component,Address,Cycle); Component component; Toggler toggler; public: Line() {} Line(Component c,Toggler t) : component ( c ), toggler ( t ) {} void Set(Component c,Toggler t) { component = c; toggler = t; } void Unset() { component = NULL; toggler = NULL; } bool operator ! () const { return component == NULL; } void Toggle(Address address,Cycle cycle) const { toggler( component, address, cycle ); } }; #define NES_DECL_LINE(a_) \ \ NST_FORCE_INLINE void NST_FASTCALL Line_M_##a_(Address,Cycle); \ static NST_NO_INLINE void NST_REGCALL Line_##a_(void*,Address,Cycle) #define NES_LINE(o_,a_) \ \ NST_NO_INLINE void NST_REGCALL o_::Line_##a_(void* p_,Address a_,Cycle c_) \ { \ static_cast(p_)->Line_M_##a_(a_,c_); \ } \ \ NST_FORCE_INLINE void NST_FASTCALL o_::Line_M_##a_(Address address,Cycle cycle) #define NES_LINE_T(t_,o_,a_) \ \ t_ NST_NO_INLINE void NST_REGCALL o_::Line_##a_(void* p_,Address a_,Cycle c_) \ { \ static_cast(p_)->Line_M_##a_(a_,c_); \ } \ \ t_ NST_FORCE_INLINE void NST_FASTCALL o_::Line_M_##a_(Address address,Cycle cycle) #endif } } } #endif nestopia-1.51.1/source/core/NstIoMap.hpp000066400000000000000000000053021411157722000200540ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_IO_MAP_H #define NST_IO_MAP_H #include "NstIoPort.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Io { template class Map { public: enum { SIZE = N, OVERFLOW_SIZE = 0x100, FULL_SIZE = SIZE + OVERFLOW_SIZE }; protected: Port ports[FULL_SIZE]; public: class Section { Port* NST_RESTRICT port; const Port* const end; public: Section(Port* b,const Port* e) : port(b), end(e) {} template void Set(A a,B b,C c) { do { port->Set( a, b, c ); } while (++port != end); } template void Set(A a,B b) { do { port->Set( a, b ); } while (++port != end); } template void Set(A a) { do { port->Set( a ); } while (++port != end); } }; template Map(A a,B b,C c) { for (dword i=SIZE; i < FULL_SIZE; ++i) ports[i].Set( a, b, c ); } const Port& operator [] (Address address) const { NST_ASSERT( address < FULL_SIZE ); return ports[address]; } Port& operator () (Address address) { NST_ASSERT( address < FULL_SIZE ); return ports[address]; } Section operator () (Address first,Address last) { NST_ASSERT( first <= last && last < SIZE ); return Section( ports + first, ports + last + 1 ); } }; } } } #endif nestopia-1.51.1/source/core/NstIoPort.hpp000066400000000000000000000237571411157722000203010ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_IO_PORT_H #define NST_IO_PORT_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Io { #ifdef NST_FASTDELEGATE class Port { class Component {}; typedef Data (NST_FASTCALL Component::*Reader)(Address); typedef void (NST_FASTCALL Component::*Writer)(Address,Data); Component* component; Reader reader; Writer writer; NST_COMPILE_ASSERT ( sizeof( Reader ) <= sizeof( Data (*)(void*,Address) ) && sizeof( Writer ) <= sizeof( Data (*)(void*,Address,Data) ) ); public: Port() {} template Port(T* c,Data (NST_FASTCALL T::*r)(Address),void (NST_FASTCALL T::*w)(Address,Data)) : component ( reinterpret_cast(c) ), reader ( reinterpret_cast(r) ), writer ( reinterpret_cast(w) ) { NST_COMPILE_ASSERT( sizeof(reader) == sizeof(r) && sizeof(writer) == sizeof(w) ); } template void Set(T* c,Data (NST_FASTCALL T::*r)(Address),void (NST_FASTCALL T::*w)(Address,Data)) { NST_COMPILE_ASSERT( sizeof(reader) == sizeof(r) && sizeof(writer) == sizeof(w) ); component = reinterpret_cast(c); reader = reinterpret_cast(r); writer = reinterpret_cast(w); } template void Set(Data (NST_FASTCALL T::*r)(Address)) { NST_COMPILE_ASSERT( sizeof(reader) == sizeof(r) ); reader = reinterpret_cast(r); } template void Set(void (NST_FASTCALL T::*w)(Address,Data)) { NST_COMPILE_ASSERT( sizeof(writer) == sizeof(w) ); writer = reinterpret_cast(w); } template void Set(Data (NST_FASTCALL T::*r)(Address),void (NST_FASTCALL T::*w)(Address,Data)) { NST_COMPILE_ASSERT( sizeof(reader) == sizeof(r) && sizeof(writer) == sizeof(w) ); reader = reinterpret_cast(r); writer = reinterpret_cast(w); } uint Peek(Address address) const { return (*component.*reader)( address ); } void Poke(Address address,Data data) const { (*component.*writer)( address, data ); } bool operator == (const Port& p) const { return component == p.component && reader == p.reader && writer == p.writer; } }; #define NES_DECL_PEEK(a_) Data NST_FASTCALL Peek_##a_(Address) #define NES_DECL_POKE(a_) void NST_FASTCALL Poke_##a_(Address,Data) #define NES_PEEK(o_,a_) Data NST_FASTCALL o_::Peek_##a_(Address) #define NES_PEEK_A(o_,a_) Data NST_FASTCALL o_::Peek_##a_(Address address) #define NES_POKE(o_,a_) void NST_FASTCALL o_::Poke_##a_(Address,Data) #define NES_POKE_A(o_,a_) void NST_FASTCALL o_::Poke_##a_(Address address,Data) #define NES_POKE_D(o_,a_) void NST_FASTCALL o_::Poke_##a_(Address,Data data) #define NES_POKE_AD(o_,a_) void NST_FASTCALL o_::Poke_##a_(Address address,Data data) #define NES_DO_POKE(a_,p_,d_) Poke_##a_(p_,d_) #define NES_DO_PEEK(a_,p_) Peek_##a_(p_) #else class Port { typedef void* Component; typedef Data (NST_REGCALL *Reader)(Component,Address); typedef void (NST_REGCALL *Writer)(Component,Address,Data); Component component; Reader reader; Writer writer; public: Port() {} Port(Component c,Reader r,Writer w) : component ( c ), reader ( r ), writer ( w ) {} void Set(Component c,Reader r,Writer w) { component = c; reader = r; writer = w; } void Set(Reader r) { reader = r; } void Set(Writer w) { writer = w; } void Set(Reader r,Writer w) { reader = r; writer = w; } Data Peek(Address address) const { return reader( component, address ); } void Poke(Address address,Data data) const { writer( component, address, data ); } bool operator == (const Port& p) const { return component == p.component && reader == p.reader && writer == p.writer; } }; #define NES_DECL_PEEK(a_) \ \ NST_SINGLE_CALL Data NST_FASTCALL Peek_M_##a_(Address); \ static Data NST_REGCALL Peek_##a_(void*,Address) #define NES_DECL_POKE(a_) \ \ NST_SINGLE_CALL void NST_FASTCALL Poke_M_##a_(Address,Data); \ static void NST_REGCALL Poke_##a_(void*,Address,Data) #define NES_PEEK(o_,a_) \ \ Data NST_REGCALL o_::Peek_##a_(void* p_,Address i_) \ { \ return static_cast(p_)->Peek_M_##a_(i_); \ } \ \ NST_SINGLE_CALL Data NST_FASTCALL o_::Peek_M_##a_(Address) #define NES_PEEK_A(o_,a_) \ \ Data NST_REGCALL o_::Peek_##a_(void* p_,Address i_) \ { \ return static_cast(p_)->Peek_M_##a_(i_); \ } \ \ NST_SINGLE_CALL Data NST_FASTCALL o_::Peek_M_##a_(Address address) #define NES_POKE(o_,a_) \ \ void NST_REGCALL o_::Poke_##a_(void* p_,Address i_,Data j_) \ { \ static_cast(p_)->Poke_M_##a_(i_,j_); \ } \ \ NST_SINGLE_CALL void NST_FASTCALL o_::Poke_M_##a_(Address,Data) #define NES_POKE_A(o_,a_) \ \ void NST_REGCALL o_::Poke_##a_(void* p_,Address i_,Data j_) \ { \ static_cast(p_)->Poke_M_##a_(i_,j_); \ } \ \ NST_SINGLE_CALL void NST_FASTCALL o_::Poke_M_##a_(Address address,Data) #define NES_POKE_D(o_,a_) \ \ void NST_REGCALL o_::Poke_##a_(void* p_,Address i_,Data j_) \ { \ static_cast(p_)->Poke_M_##a_(i_,j_); \ } \ \ NST_SINGLE_CALL void NST_FASTCALL o_::Poke_M_##a_(Address,Data data) #define NES_POKE_AD(o_,a_) \ \ void NST_REGCALL o_::Poke_##a_(void* p_,Address i_,Data j_) \ { \ static_cast(p_)->Poke_M_##a_(i_,j_); \ } \ \ NST_SINGLE_CALL void NST_FASTCALL o_::Poke_M_##a_(Address address,Data data) #define NES_DO_POKE(a_,p_,d_) Poke_##a_(this,p_,d_) #define NES_DO_PEEK(a_,p_) Peek_##a_(this,p_) #endif } } } #endif nestopia-1.51.1/source/core/NstLog.cpp000066400000000000000000000076641411157722000176000ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include #include "NstAssert.hpp" #include "NstLog.hpp" #include "api/NstApiUser.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif struct Log::Object { std::string string; }; bool Log::enabled = true; Log::Log() : object( !Api::User::logCallback ? NULL : new (std::nothrow) Object ) { } Log::~Log() { if (object) { if (enabled) Api::User::logCallback( object->string.c_str(), object->string.size() ); delete object; } } bool Log::Available() { return Api::User::logCallback; } void Log::Append(cstring c,ulong n) { object->string.append( c, n ); } Log& Log::operator << (long value) { if (enabled && object) { char buffer[24]; const int length = std::sprintf( buffer, "%li", value ); NST_VERIFY( length > 0 ); if (length > 0) Append( buffer, length ); } return *this; } Log& Log::operator << (ulong value) { if (enabled && object) { char buffer[24]; const int length = std::sprintf( buffer, "%lu", value ); NST_VERIFY( length > 0 ); if (length > 0) Append( buffer, length ); } return *this; } Log& Log::operator << (long long value) { if (enabled && object) { char buffer[24]; // Windows CRT does not support C99/C++11 llu/lli/lld. #ifdef _WIN32 const int length = std::sprintf( buffer, "%I64d", value ); #else const int length = std::sprintf( buffer, "%lli", value ); #endif NST_VERIFY( length > 0 ); if (length > 0) Append( buffer, length ); } return *this; } Log& Log::operator << (unsigned long long value) { if (enabled && object) { char buffer[24]; #ifdef _WIN32 const int length = std::sprintf( buffer, "%I64u", value ); #else const int length = std::sprintf( buffer, "%llu", value ); #endif NST_VERIFY( length > 0 ); if (length > 0) Append( buffer, length ); } return *this; } Log& Log::operator << (cstring c) { if (enabled && object) object->string.append( c ); return *this; } Log& Log::operator << (char c) { if (enabled && object) object->string.append( 1, c ); return *this; } Log& Log::operator << (const Hex& hex) { if (enabled && object) { char buffer[16]; buffer[0] = '0'; buffer[1] = 'x'; const int length = std::sprintf( buffer + 2, hex.format, hex.value ); NST_VERIFY( length > 0 ); if (length > 0) Append( buffer, 2 + length ); } return *this; } void Log::Flush(cstring string,dword length) { if (enabled) Api::User::logCallback( string, length ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } nestopia-1.51.1/source/core/NstLog.hpp000066400000000000000000000054131411157722000175730ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_LOG_H #define NST_LOG_H #ifndef NST_CORE_H #include "NstCore.hpp" #endif #ifdef NST_PRAGMA_ONCE #pragma once #endif #ifndef NST_LINEBREAK #ifdef NST_WIN32 #define NST_LINEBREAK "\r\n" #else #define NST_LINEBREAK "\n" #endif #endif namespace Nes { namespace Core { class Log { public: Log(); ~Log(); struct Hex { const dword value; cstring const format; Hex(uint n,dword v) : value (v), format (n == 8 ? "%02X" : n == 16 ? "%04X" : "%08X") {} }; Log& operator << (char); Log& operator << (cstring); Log& operator << (const Hex&); Log& operator << (long); Log& operator << (ulong); Log& operator << (long long); Log& operator << (unsigned long long); static void Flush(cstring,dword); static bool Available(); private: void Append(cstring,ulong); struct Object; Object* const object; static bool enabled; public: Log& operator << (schar i) { return operator << ( long (i) ); } Log& operator << (uchar i) { return operator << ( ulong (i) ); } Log& operator << (short i) { return operator << ( long (i) ); } Log& operator << (ushort i) { return operator << ( ulong (i) ); } Log& operator << (int i) { return operator << ( long (i) ); } Log& operator << (uint i) { return operator << ( ulong (i) ); } class Suppressor { const bool state; public: Suppressor() : state(enabled) { enabled = false; } ~Suppressor() { enabled = state; } }; template static void Flush(const char (&c)[N]) { NST_COMPILE_ASSERT( N > 0 ); Flush( c, N-1 ); } }; } } #endif nestopia-1.51.1/source/core/NstMachine.cpp000066400000000000000000000315631411157722000204160ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // Copyright (C) 2018-2018 Phil Smith // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstMachine.hpp" #include "NstCartridge.hpp" #include "NstCheats.hpp" #include "NstHomebrew.hpp" #include "NstNsf.hpp" #include "NstImageDatabase.hpp" #include "input/NstInpDevice.hpp" #include "input/NstInpAdapter.hpp" #include "input/NstInpPad.hpp" #include "api/NstApiMachine.hpp" #include "api/NstApiUser.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Machine::Machine() : state (Api::Machine::NTSC), frame (0), extPort (new Input::AdapterTwo( *new Input::Pad(cpu,0), *new Input::Pad(cpu,1) )), expPort (new Input::Device( cpu )), image (NULL), cheats (NULL), homebrew (NULL), imageDatabase (NULL), ppu (cpu) { } Machine::~Machine() { Unload(); delete imageDatabase; delete cheats; delete homebrew; delete expPort; for (uint ports=extPort->NumPorts(), i=0; i < ports; ++i) delete &extPort->GetDevice(i); delete extPort; } Result Machine::Load ( std::istream& imageStream, FavoredSystem system, bool ask, std::istream* const patchStream, bool patchBypassChecksum, Result* patchResult, uint type ) { Unload(); Image::Context context ( static_cast(type), cpu, cpu.GetApu(), ppu, imageStream, patchStream, patchBypassChecksum, patchResult, system, ask, imageDatabase ); image = Image::Load( context ); switch (image->GetType()) { case Image::CARTRIDGE: state |= Api::Machine::CARTRIDGE; if ((static_cast(image)->GetProfile().system.type) == Api::Cartridge::Profile::System::VS_UNISYSTEM) { state |= Api::Machine::VS; } else if ((static_cast(image)->GetProfile().system.type) == Api::Cartridge::Profile::System::PLAYCHOICE_10) { state |= Api::Machine::PC10; } break; case Image::DISK: state |= Api::Machine::DISK; break; case Image::SOUND: state |= Api::Machine::SOUND; break; case Image::UNKNOWN: default: break; } UpdateModels(); Api::Machine::eventCallback( Api::Machine::EVENT_LOAD, context.result ); return context.result; } Result Machine::Unload() { if (!image) return RESULT_OK; const Result result = PowerOff(); tracker.Unload(); Image::Unload( image ); image = NULL; state &= (Api::Machine::NTSC|Api::Machine::PAL); Api::Machine::eventCallback( Api::Machine::EVENT_UNLOAD, result ); return result; } void Machine::UpdateModels() { const Region region = (state & Api::Machine::NTSC) ? REGION_NTSC : REGION_PAL; CpuModel cpuModel; PpuModel ppuModel; if (image) { image->GetDesiredSystem( region, &cpuModel, &ppuModel ); } else { cpuModel = (region == REGION_NTSC ? CPU_RP2A03 : CPU_RP2A07); ppuModel = (region == REGION_NTSC ? PPU_RP2C02 : PPU_RP2C07); } cpu.SetModel( cpuModel ); UpdateVideo( ppuModel, GetColorMode() ); renderer.EnableForcedFieldMerging( ppuModel != PPU_RP2C02 ); } Machine::ColorMode Machine::GetColorMode() const { return ( renderer.GetPaletteType() == Video::Renderer::PALETTE_YUV ? COLORMODE_YUV : renderer.GetPaletteType() == Video::Renderer::PALETTE_CUSTOM ? COLORMODE_CUSTOM : COLORMODE_RGB ); } Result Machine::UpdateColorMode() { return UpdateColorMode( GetColorMode() ); } Result Machine::UpdateColorMode(const ColorMode mode) { return UpdateVideo( ppu.GetModel(), mode ); } Result Machine::UpdateVideo(const PpuModel ppuModel,const ColorMode mode) { ppu.SetModel( ppuModel, mode == COLORMODE_YUV ); Video::Renderer::PaletteType palette; switch (mode) { case COLORMODE_RGB: switch (ppuModel) { case PPU_RP2C04_0001: palette = Video::Renderer::PALETTE_VS1; break; case PPU_RP2C04_0002: palette = Video::Renderer::PALETTE_VS2; break; case PPU_RP2C04_0003: palette = Video::Renderer::PALETTE_VS3; break; case PPU_RP2C04_0004: palette = Video::Renderer::PALETTE_VS4; break; default: palette = Video::Renderer::PALETTE_PC10; break; } break; case COLORMODE_CUSTOM: palette = Video::Renderer::PALETTE_CUSTOM; break; default: palette = Video::Renderer::PALETTE_YUV; break; } return renderer.SetPaletteType( palette ); } Result Machine::PowerOff(Result result) { if (state & Api::Machine::ON) { tracker.PowerOff(); if (image && !image->PowerOff() && NES_SUCCEEDED(result)) result = RESULT_WARN_SAVEDATA_LOST; ppu.PowerOff(); cpu.PowerOff(); state &= ~uint(Api::Machine::ON); frame = 0; Api::Machine::eventCallback( Api::Machine::EVENT_POWER_OFF, result ); } return result; } void Machine::Reset(bool hard) { if (state & Api::Machine::SOUND) hard = true; try { frame = 0; cpu.Reset( hard ); if (!(state & Api::Machine::SOUND)) { InitializeInputDevices(); cpu.Map( 0x4016 ).Set( this, &Machine::Peek_4016, &Machine::Poke_4016 ); cpu.Map( 0x4017 ).Set( this, &Machine::Peek_4017, &Machine::Poke_4017 ); extPort->Reset(); expPort->Reset(); bool acknowledged = true; if (image) { System desiredSystem = image->GetDesiredSystem((state & Api::Machine::NTSC) ? REGION_NTSC : REGION_PAL); if (desiredSystem == SYSTEM_FAMICOM || desiredSystem == SYSTEM_DENDY) acknowledged = false; } ppu.Reset( hard, acknowledged ); if (image) image->Reset( hard ); if (cheats) cheats->Reset(); if (homebrew) homebrew->Reset(); tracker.Reset(); } else { image->Reset( true ); } cpu.Boot( hard ); if (state & Api::Machine::ON) { Api::Machine::eventCallback( hard ? Api::Machine::EVENT_RESET_HARD : Api::Machine::EVENT_RESET_SOFT ); } else { state |= Api::Machine::ON; Api::Machine::eventCallback( Api::Machine::EVENT_POWER_ON ); } } catch (...) { PowerOff(); throw; } } void Machine::SetRamPowerState(uint state) { cpu.SetRamPowerState(state); } void Machine::SwitchMode() { NST_ASSERT( !(state & Api::Machine::ON) ); if (state & Api::Machine::NTSC) state = (state & ~uint(Api::Machine::NTSC)) | Api::Machine::PAL; else state = (state & ~uint(Api::Machine::PAL)) | Api::Machine::NTSC; UpdateModels(); Api::Machine::eventCallback( (state & Api::Machine::NTSC) ? Api::Machine::EVENT_MODE_NTSC : Api::Machine::EVENT_MODE_PAL ); } void Machine::InitializeInputDevices() const { if (state & Api::Machine::GAME) { const bool arcade = state & Api::Machine::VS; extPort->Initialize( arcade ); expPort->Initialize( arcade ); } } void Machine::SaveState(State::Saver& saver) const { NST_ASSERT( (state & (Api::Machine::GAME|Api::Machine::ON)) > Api::Machine::ON ); saver.Begin( AsciiId<'N','S','T'>::V | 0x1AUL << 24 ); saver.Begin( AsciiId<'N','F','O'>::V ).Write32( image->GetPrgCrc() ).Write32( frame ).End(); cpu.SaveState( saver, AsciiId<'C','P','U'>::V, AsciiId<'A','P','U'>::V ); ppu.SaveState( saver, AsciiId<'P','P','U'>::V ); image->SaveState( saver, AsciiId<'I','M','G'>::V ); saver.Begin( AsciiId<'P','R','T'>::V ); if (extPort->NumPorts() == 4) { static_cast(extPort)->SaveState ( saver, AsciiId<'4','S','C'>::V ); } for (uint i=0; i < extPort->NumPorts(); ++i) extPort->GetDevice( i ).SaveState( saver, Ascii<'0'>::V + i ); expPort->SaveState( saver, Ascii<'X'>::V ); saver.End(); saver.End(); } bool Machine::LoadState(State::Loader& loader,const bool resetOnError) { NST_ASSERT( (state & (Api::Machine::GAME|Api::Machine::ON)) > Api::Machine::ON ); try { if (loader.Begin() != (AsciiId<'N','S','T'>::V | 0x1AUL << 24)) throw RESULT_ERR_INVALID_FILE; while (const dword chunk = loader.Begin()) { switch (chunk) { case AsciiId<'N','F','O'>::V: { const dword crc = loader.Read32(); if ( loader.CheckCrc() && !(state & Api::Machine::DISK) && crc && crc != image->GetPrgCrc() && Api::User::questionCallback( Api::User::QUESTION_NST_PRG_CRC_FAIL_CONTINUE ) == Api::User::ANSWER_NO ) { for (uint i=0; i < 2; ++i) loader.End(); return false; } frame = loader.Read32(); break; } case AsciiId<'C','P','U'>::V: case AsciiId<'A','P','U'>::V: cpu.LoadState( loader, AsciiId<'C','P','U'>::V, AsciiId<'A','P','U'>::V, chunk ); break; case AsciiId<'P','P','U'>::V: ppu.LoadState( loader ); break; case AsciiId<'I','M','G'>::V: image->LoadState( loader ); break; case AsciiId<'P','R','T'>::V: extPort->Reset(); expPort->Reset(); while (const dword subId = loader.Begin()) { if (subId == AsciiId<'4','S','C'>::V) { if (extPort->NumPorts() == 4) static_cast(extPort)->LoadState( loader ); } else switch (const uint index = (subId >> 16 & 0xFF)) { case Ascii<'2'>::V: case Ascii<'3'>::V: if (extPort->NumPorts() != 4) break; case Ascii<'0'>::V: case Ascii<'1'>::V: extPort->GetDevice( index - Ascii<'0'>::V ).LoadState( loader, subId & 0xFF00FFFF ); break; case Ascii<'X'>::V: expPort->LoadState( loader, subId & 0xFF00FFFF ); break; } loader.End(); } break; } loader.End(); } loader.End(); } catch (...) { if (resetOnError) Reset( true ); throw; } return true; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Machine::Execute ( Video::Output* const video, Sound::Output* const sound, Input::Controllers* const input ) { NST_ASSERT( state & Api::Machine::ON ); if (!(state & Api::Machine::SOUND)) { if (state & Api::Machine::CARTRIDGE) static_cast(image)->BeginFrame( Api::Input(*this), input ); extPort->BeginFrame( input ); expPort->BeginFrame( input ); ppu.BeginFrame( tracker.IsFrameLocked() ); if (cheats) cheats->BeginFrame( tracker.IsFrameLocked() ); cpu.ExecuteFrame( sound ); ppu.EndFrame(); renderer.bgColor = ppu.output.bgColor; if (video) renderer.Blit( *video, ppu.GetScreen(), ppu.GetBurstPhase() ); cpu.EndFrame(); if (image) image->VSync(); extPort->EndFrame(); expPort->EndFrame(); frame++; } else { static_cast(image)->BeginFrame(); cpu.ExecuteFrame( sound ); cpu.EndFrame(); image->VSync(); } } NES_POKE_D(Machine,4016) { extPort->Poke( data ); expPort->Poke( data ); } NES_PEEK_A(Machine,4016) { cpu.Update( address ); return OPEN_BUS | extPort->Peek(0) | expPort->Peek(0); } NES_POKE_D(Machine,4017) { cpu.GetApu().WriteFrameCtrl( data ); } NES_PEEK_A(Machine,4017) { cpu.Update( address ); return OPEN_BUS | extPort->Peek(1) | expPort->Peek(1); } } } nestopia-1.51.1/source/core/NstMachine.hpp000066400000000000000000000060101411157722000204100ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // Copyright (C) 2018-2018 Phil Smith // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_MACHINE_H #define NST_MACHINE_H #include #include "NstCpu.hpp" #include "NstPpu.hpp" #include "NstTracker.hpp" #include "NstVideoRenderer.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Video { class Output; } namespace Sound { class Output; } namespace Input { class Device; class Adapter; class Controllers; } class Image; class Cheats; class Homebrew; class ImageDatabase; class Machine { public: Machine(); ~Machine(); void Execute ( Video::Output*, Sound::Output*, Input::Controllers* ); enum ColorMode { COLORMODE_YUV, COLORMODE_RGB, COLORMODE_CUSTOM }; Result Load ( std::istream&, FavoredSystem, bool, std::istream*, bool, Result*, uint ); Result Unload(); Result PowerOff(Result=RESULT_OK); void Reset(bool); void SetRamPowerState(uint); void SwitchMode(); bool LoadState(State::Loader&,bool); void SaveState(State::Saver&) const; void InitializeInputDevices() const; Result UpdateColorMode(); Result UpdateColorMode(ColorMode); private: void UpdateModels(); Result UpdateVideo(PpuModel,ColorMode); ColorMode GetColorMode() const; enum { OPEN_BUS = 0x40 }; NES_DECL_POKE( 4016 ); NES_DECL_PEEK( 4016 ); NES_DECL_POKE( 4017 ); NES_DECL_PEEK( 4017 ); uint state; dword frame; public: Cpu cpu; Input::Adapter* extPort; Input::Device* expPort; Image* image; Cheats* cheats; Homebrew* homebrew; ImageDatabase* imageDatabase; Tracker tracker; Ppu ppu; Video::Renderer renderer; uint Is(uint a) const { return state & a; } bool Is(uint a,uint b) const { return (state & a) && (state & b); } }; } } #endif nestopia-1.51.1/source/core/NstMemory.cpp000066400000000000000000000063671411157722000203260ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstState.hpp" #include "NstMemory.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Memory<0,0,0>::SaveState ( State::Saver& state, const dword baseChunk, const Ram* const NST_RESTRICT sources, const uint numSources, const byte* const NST_RESTRICT pages, const uint numPages ) const { NST_ASSERT( numSources >= 1 && numSources <= MAX_SOURCES && numPages ); state.Begin( baseChunk ); { byte data[MAX_SOURCES]; for (uint i=0; i < numSources; ++i) data[i] = (sources[i].Readable() ? 0x1U : 0x0U) | (sources[i].Writable() ? 0x2U : 0x0U); state.Begin( AsciiId<'A','C','C'>::V ).Write( data, numSources ).End(); } state.Begin( AsciiId<'B','N','K'>::V ).Write( pages, numPages * 3 ).End(); state.End(); } bool Memory<0,0,0>::LoadState ( State::Loader& state, Ram* const NST_RESTRICT sources, const uint numSources, byte* const NST_RESTRICT pages, const uint numPages ) const { NST_ASSERT( numSources >= 1 && numSources <= MAX_SOURCES && numPages ); bool paged = false; while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'A','C','C'>::V: { byte data[MAX_SOURCES]; state.Read( data, numSources ); for (uint i=0; i < numSources; ++i) { sources[i].ReadEnable( data[i] & 0x1U ); NST_VERIFY( sources[i].GetType() != Ram::ROM || !(data[i] & 0x2U) ); if (sources[i].GetType() != Ram::ROM) sources[i].WriteEnable( data[i] & 0x2U ); } break; } case AsciiId<'B','N','K'>::V: paged = true; state.Read( pages, numPages * 3 ); break; default: // deprecated for (uint i=0; i < numSources; ++i) { if (chunk == AsciiId<'R','M','0'>::R(0,0,i)) { NST_DEBUG_MSG("Memory::LoadState() deprecated!"); state.Uncompress( sources[i].Mem(), sources[i].Size() ); break; } } break; } state.End(); } return paged; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } nestopia-1.51.1/source/core/NstMemory.hpp000066400000000000000000000454021411157722000203240ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_MEMORY_H #define NST_MEMORY_H #include "NstRam.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { template class Pointer : public ImplicitBool< Pointer > { Pointer(const Pointer&); T* const ptr; public: explicit Pointer(T* t) : ptr(t) {} ~Pointer() { typedef char TypeComplete[sizeof(T)]; delete ptr; } T* operator -> () const { return ptr; } T& operator * () const { return *ptr; } bool operator ! () const { return !ptr; } }; namespace State { class Saver; class Loader; } template class Memory; template<> class Memory<0,0,0> { protected: enum { MAX_SOURCES = 2 }; void SaveState ( State::Saver&, dword, const Ram* NST_RESTRICT, uint, const byte* NST_RESTRICT, uint ) const; bool LoadState ( State::Loader&, Ram* NST_RESTRICT, uint, byte* NST_RESTRICT, uint ) const; template struct Pages { byte* mem[N]; byte ref[N]; }; template struct Unroller { template static NST_FORCE_INLINE void SwapBank ( Pages* const NST_RESTRICT pages, byte* const NST_RESTRICT mem, const dword mask, const dword bank, const uint offset=0, const uint source=0 ) { pages->mem[OFFSET+COUNT-I+offset] = mem + (bank & mask); pages->ref[OFFSET+COUNT-I+offset] = source; Unroller::SwapBank( pages, mem, mask, bank + SIZE, offset, source ); } template static NST_FORCE_INLINE void SwapBanks ( Pages* const NST_RESTRICT pages, byte* const NST_RESTRICT mem, const dword mask, const dword bank0, const dword bank1, const uint offset=0 ) { Unroller::SwapBank( pages, mem, mask, bank0, offset ); Unroller::SwapBank( pages, mem, mask, bank1, offset ); } template static NST_FORCE_INLINE void SwapBanks ( Pages* const NST_RESTRICT pages, byte* const NST_RESTRICT mem, const dword mask, const dword bank0, const dword bank1, const dword bank2, const dword bank3, const uint offset=0 ) { Unroller::SwapBank( pages, mem, mask, bank0, offset ); Unroller::SwapBank( pages, mem, mask, bank1, offset ); Unroller::SwapBank( pages, mem, mask, bank2, offset ); Unroller::SwapBank( pages, mem, mask, bank3, offset ); } template static NST_FORCE_INLINE void SwapBanks ( Pages* const NST_RESTRICT pages, byte* const NST_RESTRICT mem, const dword mask, const dword bank0, const dword bank1, const dword bank2, const dword bank3, const dword bank4, const dword bank5, const dword bank6, const dword bank7, const uint offset=0 ) { Unroller::SwapBank( pages, mem, mask, bank0, offset ); Unroller::SwapBank( pages, mem, mask, bank1, offset ); Unroller::SwapBank( pages, mem, mask, bank2, offset ); Unroller::SwapBank( pages, mem, mask, bank3, offset ); Unroller::SwapBank( pages, mem, mask, bank4, offset ); Unroller::SwapBank( pages, mem, mask, bank5, offset ); Unroller::SwapBank( pages, mem, mask, bank6, offset ); Unroller::SwapBank( pages, mem, mask, bank7, offset ); } }; }; template<> struct Memory<0,0,0>::Pages<1> { byte* mem[1]; dword ref[1]; }; template<> struct Memory<0,0,0>::Pages<2> { byte* mem[2]; word ref[2]; }; template struct Memory<0,0,0>::Unroller { template static NST_FORCE_INLINE void SwapBank(Pages*,byte*,dword,dword,uint,uint) {} }; template class Memory : Memory<0,0,0> { public: enum { NUM_SOURCES = V }; private: NST_COMPILE_ASSERT ( ((SPACE & (SPACE-1)) == 0) && ((U & (U-1)) == 0) && (SPACE % U == 0) && (V >= 1 && V <= MAX_SOURCES) ); enum { MEM_PAGE_SIZE = U, MEM_PAGE_SHIFT = ValueBits::VALUE-1, MEM_PAGE_MASK = MEM_PAGE_SIZE - 1, MEM_NUM_PAGES = SPACE / U }; typedef Memory<0,0,0>::Pages Pages; Pages pages; Ram sources[NUM_SOURCES]; public: bool Readable(uint page) const { return sources[pages.ref[page]].Readable(); } bool Writable(uint page) const { return sources[pages.ref[page]].Writable(); } const byte& Peek(uint address) const { return pages.mem[address >> MEM_PAGE_SHIFT][address & MEM_PAGE_MASK]; } byte* operator [] (uint page) { return pages.mem[page]; } const byte* operator [] (uint page) const { return pages.mem[page]; } void Poke(uint address,uint data) { const uint page = address >> MEM_PAGE_SHIFT; NST_VERIFY( Writable( page ) ); if (Writable( page )) pages.mem[page][address & MEM_PAGE_MASK] = data; } template void SwapBank(dword); template void SwapBanks(dword,dword); template void SwapBanks(dword,dword,dword,dword); template void SwapBanks(dword,dword,dword,dword,dword,dword,dword,dword); template void SwapBank(uint,dword); template void SwapBanks(uint,dword,dword); template void SwapBanks(uint,dword,dword,dword,dword); template void SwapBanks(uint,dword,dword,dword,dword,dword,dword,dword,dword); template void SwapPages(); void SaveState(State::Saver&,dword) const; void LoadState(State::Loader&); class SourceProxy { typedef Memory Ref; const uint source; Ref& ref; public: SourceProxy(uint s,Ref& r) : source(s), ref(r) { NST_ASSERT( s < NUM_SOURCES ); } template void SwapBank(dword) const; template void SwapBank(uint,dword) const; void ReadEnable(bool read) const { ref.sources[source].ReadEnable( read ); } void WriteEnable(bool write) const { ref.sources[source].WriteEnable( write ); } void SetSecurity(bool read,bool write) const { ref.sources[source].SetSecurity( read, write ); } bool Readable() const { return ref.sources[source].Readable(); } bool Writable() const { return ref.sources[source].Writable(); } Ram::Type GetType() const { return ref.sources[source].GetType(); } void Set(Ram::Type type,bool read,bool write,dword size,byte* mem) const { ref.sources[source].Set( type, read, write, size, mem ); } void Set(Ram::Type type,bool read,bool write,dword size) const { ref.sources[source].Set( type, read, write, size ); } void Set(const Ram& ram) const { ref.sources[source] = ram; } void Fill(uint value) const { ref.sources[source].Fill( value ); } byte* Mem(dword offset=0) const { return ref.sources[source].Mem(offset); } byte& operator [] (dword i) const { return ref.sources[source][i]; } dword Size() const { return ref.sources[source].Size(); } dword Masking() const { return ref.sources[source].Masking(); } bool Empty() const { return ref.sources[source].Size() == 0; } const Ram& Reference() const { return ref.sources[source]; } }; public: const SourceProxy Source(uint i=0) { NST_ASSERT( i < NUM_SOURCES ); return SourceProxy( i, *this ); } const Ram& Source(uint i=0) const { NST_ASSERT( i < NUM_SOURCES ); return sources[i]; } Memory() { } Memory(byte* mem,dword size,bool read,bool write) { Source().Set( mem, size, read, write ); } Memory(dword size,bool read,bool write) { Source().Set( size, read, write ); } template dword GetBank() const { NST_COMPILE_ASSERT( SIZE && (SIZE % MEM_PAGE_SIZE == 0) && (SPACE >= ADDRESS + SIZE) ); enum {MEM_PAGE = ADDRESS >> MEM_PAGE_SHIFT}; return dword(pages.mem[MEM_PAGE] - sources[pages.ref[MEM_PAGE]].Mem()) >> (ValueBits::VALUE-1); } template dword GetBank(uint address) const { NST_COMPILE_ASSERT( SIZE && (SIZE % MEM_PAGE_SIZE == 0) ); NST_ASSERT( SPACE >= address + SIZE ); address >>= MEM_PAGE_SHIFT; return dword(pages.mem[address] - sources[pages.ref[address]].Mem()) >> (ValueBits::VALUE-1); } }; template template void Memory::SwapBank(dword bank) { NST_COMPILE_ASSERT( (SPACE >= ADDRESS + SIZE) && SIZE && (SIZE % MEM_PAGE_SIZE == 0) ); enum { MEM_OFFSET = ValueBits::VALUE-1, MEM_PAGE_BEGIN = ADDRESS / MEM_PAGE_SIZE, MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE }; Memory<0,0,0>::Unroller::SwapBank ( &pages, sources[0].Mem(), sources[0].Masking(), bank << MEM_OFFSET ); } template template void Memory::SwapBank(uint address,dword bank) { NST_COMPILE_ASSERT( SIZE && (SIZE % MEM_PAGE_SIZE == 0) ); NST_ASSERT( SPACE >= address + SIZE ); enum { MEM_OFFSET = ValueBits::VALUE-1, MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE }; Memory<0,0,0>::Unroller<0,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBank ( &pages, sources[0].Mem(), sources[0].Masking(), bank << MEM_OFFSET, address >> MEM_PAGE_SHIFT ); } template template void Memory::SwapBanks(dword bank0,dword bank1) { NST_COMPILE_ASSERT( (SPACE >= ADDRESS + SIZE * 2) && SIZE && (SIZE % MEM_PAGE_SIZE == 0) ); enum { MEM_OFFSET = ValueBits::VALUE-1, MEM_PAGE_BEGIN = ADDRESS / MEM_PAGE_SIZE, MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE }; Memory<0,0,0>::Unroller::SwapBanks ( &pages, sources[0].Mem(), sources[0].Masking(), bank0 << MEM_OFFSET, bank1 << MEM_OFFSET ); } template template void Memory::SwapBanks(dword bank0,dword bank1,dword bank2,dword bank3) { NST_COMPILE_ASSERT( (SPACE >= ADDRESS + SIZE * 4) && SIZE && (SIZE % MEM_PAGE_SIZE == 0) ); enum { MEM_OFFSET = ValueBits::VALUE-1, MEM_PAGE_BEGIN = ADDRESS / MEM_PAGE_SIZE, MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE }; Memory<0,0,0>::Unroller::SwapBanks ( &pages, sources[0].Mem(), sources[0].Masking(), bank0 << MEM_OFFSET, bank1 << MEM_OFFSET, bank2 << MEM_OFFSET, bank3 << MEM_OFFSET ); } template template void Memory::SwapBanks(dword bank0,dword bank1,dword bank2,dword bank3,dword bank4,dword bank5,dword bank6,dword bank7) { NST_COMPILE_ASSERT( (SPACE >= ADDRESS + SIZE * 4) && SIZE && (SIZE % MEM_PAGE_SIZE == 0) ); enum { MEM_OFFSET = ValueBits::VALUE-1, MEM_PAGE_BEGIN = ADDRESS / MEM_PAGE_SIZE, MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE }; Memory<0,0,0>::Unroller::SwapBanks ( &pages, sources[0].Mem(), sources[0].Masking(), bank0 << MEM_OFFSET, bank1 << MEM_OFFSET, bank2 << MEM_OFFSET, bank3 << MEM_OFFSET, bank4 << MEM_OFFSET, bank5 << MEM_OFFSET, bank6 << MEM_OFFSET, bank7 << MEM_OFFSET ); } template template void Memory::SwapBanks(uint address,dword bank0,dword bank1) { NST_COMPILE_ASSERT( SIZE && (SIZE % MEM_PAGE_SIZE == 0) ); NST_ASSERT( SPACE >= address + SIZE * 2 ); enum { MEM_OFFSET = ValueBits::VALUE-1, MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE }; Memory<0,0,0>::Unroller<0,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBanks ( &pages, sources[0].Mem(), sources[0].Masking(), bank0 << MEM_OFFSET, bank1 << MEM_OFFSET, address >> MEM_PAGE_SHIFT ); } template template void Memory::SwapBanks(uint address,dword bank0,dword bank1,dword bank2,dword bank3) { NST_COMPILE_ASSERT( SIZE && (SIZE % MEM_PAGE_SIZE == 0) ); NST_ASSERT( SPACE >= address + SIZE * 4 ); enum { MEM_OFFSET = ValueBits::VALUE-1, MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE }; Memory<0,0,0>::Unroller<0,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBanks ( &pages, sources[0].Mem(), sources[0].Masking(), bank0 << MEM_OFFSET, bank1 << MEM_OFFSET, bank2 << MEM_OFFSET, bank3 << MEM_OFFSET, address >> MEM_PAGE_SHIFT ); } template template void Memory::SwapBanks(uint address,dword bank0,dword bank1,dword bank2,dword bank3,dword bank4,dword bank5,dword bank6,dword bank7) { NST_COMPILE_ASSERT( SIZE && (SIZE % MEM_PAGE_SIZE == 0) ); NST_ASSERT( SPACE >= address + SIZE * 4 ); enum { MEM_OFFSET = ValueBits::VALUE-1, MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE }; Memory<0,0,0>::Unroller<0,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBanks ( &pages, sources[0].Mem(), sources[0].Masking(), bank0 << MEM_OFFSET, bank1 << MEM_OFFSET, bank2 << MEM_OFFSET, bank3 << MEM_OFFSET, bank4 << MEM_OFFSET, bank5 << MEM_OFFSET, bank6 << MEM_OFFSET, bank7 << MEM_OFFSET, address >> MEM_PAGE_SHIFT ); } template template void Memory::SourceProxy::SwapBank(dword bank) const { NST_COMPILE_ASSERT( (SPACE >= ADDRESS + SIZE) && SIZE && (SIZE % MEM_PAGE_SIZE == 0) ); enum { MEM_OFFSET = ValueBits::VALUE-1, MEM_PAGE_BEGIN = ADDRESS / MEM_PAGE_SIZE, MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE }; Memory<0,0,0>::Unroller::SwapBank ( &ref.pages, ref.sources[source].Mem(), ref.sources[source].Masking(), bank << MEM_OFFSET, 0, source ); } template template void Memory::SourceProxy::SwapBank(uint address,dword bank) const { NST_COMPILE_ASSERT( SIZE && (SIZE % MEM_PAGE_SIZE == 0) ); NST_ASSERT( SPACE >= address + SIZE ); enum { MEM_OFFSET = ValueBits::VALUE-1, MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE }; Memory<0,0,0>::Unroller<0,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBank ( &ref.pages, ref.sources[source].Mem(), ref.sources[source].Masking(), bank << MEM_OFFSET, address >> MEM_PAGE_SHIFT, source ); } template template void Memory::SwapPages() { NST_COMPILE_ASSERT ( (A != B) && (SPACE >= A + SIZE) && (SPACE >= B + SIZE) && (SIZE && (SIZE % MEM_PAGE_SIZE) == 0) ); enum { MEM_A_BEGIN = A / MEM_PAGE_SIZE, MEM_B_BEGIN = B / MEM_PAGE_SIZE, MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE }; for (uint i=0; i < MEM_PAGE_COUNT; ++i) { byte* const mem = pages.mem[MEM_A_BEGIN+i]; const byte ref = pages.ref[MEM_A_BEGIN+i]; pages.mem[MEM_A_BEGIN+i] = pages.mem[MEM_B_BEGIN+i]; pages.ref[MEM_A_BEGIN+i] = pages.ref[MEM_B_BEGIN+i]; pages.mem[MEM_B_BEGIN+i] = mem; pages.ref[MEM_B_BEGIN+i] = ref; } } template void Memory::SaveState(State::Saver& state,const dword baseChunk) const { byte pageData[MEM_NUM_PAGES*3]; for (uint i=0; i < MEM_NUM_PAGES; ++i) { const uint bank = GetBank( i * MEM_PAGE_SIZE ); pageData[i*3+0] = pages.ref[i]; pageData[i*3+1] = bank & 0xFF; pageData[i*3+2] = bank >> 8; } Memory<0,0,0>::SaveState( state, baseChunk, sources, NUM_SOURCES, pageData, MEM_NUM_PAGES ); } template void Memory::LoadState(State::Loader& state) { byte pageData[MEM_NUM_PAGES*3]; if (Memory<0,0,0>::LoadState( state, sources, NUM_SOURCES, pageData, MEM_NUM_PAGES )) { for (uint i=0; i < MEM_NUM_PAGES; ++i) { if (pageData[i*3+0] < NUM_SOURCES) Source( pageData[i*3+0] ).template SwapBank( i * MEM_PAGE_SIZE, pageData[i*3+1] | uint(pageData[i*3+2]) << 8 ); else throw RESULT_ERR_CORRUPT_FILE; } } } } } #endif nestopia-1.51.1/source/core/NstNsf.cpp000066400000000000000000000702521411157722000175760ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstLog.hpp" #include "NstFds.hpp" #include "board/NstBoard.hpp" #include "board/NstBoardMmc5.hpp" #include "board/NstBoardKonami.hpp" #include "board/NstBoardNamcot.hpp" #include "board/NstBoardSunsoft.hpp" #include "api/NstApiNsf.hpp" #include "NstNsf.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif class Nsf::Chips : Apu::Channel { struct Mmc5 : Boards::Mmc5::Sound { uint mul[2]; byte exRam[SIZE_1K]; explicit Mmc5(Apu& a) : Sound(a,false) {} void Reset(); void ClearExRam(); using Sound::UpdateSettings; using Sound::GetSample; using Sound::Clock; }; struct Fds : Core::Fds::Sound { byte ram[SIZE_8K+SIZE_32K]; explicit Fds(Apu& a) : Sound(a,false) {} void Reset(); void SwapBank(const Prg&,uint,uint); using Sound::UpdateSettings; using Sound::GetSample; using Sound::Clock; }; struct N163 : Boards::Namcot::N163::Sound { explicit N163(Apu& a) : Sound(a,false) {} using Sound::Reset; using Sound::UpdateSettings; using Sound::GetSample; }; struct Vrc6 : Boards::Konami::Vrc6::Sound { explicit Vrc6(Apu& a) : Sound(a,false) {} using Sound::Reset; using Sound::UpdateSettings; using Sound::GetSample; }; struct Vrc7 : Boards::Konami::Vrc7::Sound { explicit Vrc7(Apu& a) : Sound(a,false) {} using Sound::Reset; using Sound::UpdateSettings; using Sound::GetSample; }; struct S5b : Boards::Sunsoft::S5b::Sound { explicit S5b(Apu& a) : Sound(a,false) {} using Sound::Reset; using Sound::UpdateSettings; using Sound::GetSample; }; template struct Chip : Pointer { Chip(Apu& a,uint t) : Pointer(t ? new T(a) : NULL) {} }; struct Clocks { void Reset(bool,bool); Cycle next; Cycle mmc5; Cycle fds; }; void Reset(); bool UpdateSettings(); Sample GetSample(); Cycle Clock(Cycle,Cycle,Cycle); Clocks clocks; public: Chips(uint,Apu&); Chip mmc5; Chip vrc6; Chip vrc7; Chip fds; Chip s5b; Chip n163; }; void Nsf::Chips::Mmc5::ClearExRam() { std::memset( exRam, 0, sizeof(exRam) ); } void Nsf::Chips::Mmc5::Reset() { mul[0] = 0; mul[1] = 0; ClearExRam(); Sound::Reset(); } void Nsf::Chips::Fds::Reset() { std::memset( ram, 0, sizeof(ram) ); Sound::Reset(); } void Nsf::Chips::Fds::SwapBank(const Prg& prg,uint page,uint bank) { std::memcpy( ram + SIZE_4K * page, prg.Source().Mem(bank * SIZE_4K), SIZE_4K ); } Nsf::Chips::Chips(const uint types,Apu& apu) : Channel ( apu ), mmc5 ( apu, types & Api::Nsf::CHIP_MMC5 ), vrc6 ( apu, types & Api::Nsf::CHIP_VRC6 ), vrc7 ( apu, types & Api::Nsf::CHIP_VRC7 ), fds ( apu, types & Api::Nsf::CHIP_FDS ), s5b ( apu, types & Api::Nsf::CHIP_S5B ), n163 ( apu, types & Api::Nsf::CHIP_N163 ) { Connect( UpdateSettings() ); } void Nsf::Chips::Clocks::Reset(bool mmc5Chip,bool fdsChip) { next = (mmc5Chip || fdsChip ? 0UL : Cpu::CYCLE_MAX); mmc5 = (mmc5Chip ? 0UL : Cpu::CYCLE_MAX); fds = (fdsChip ? 0UL : Cpu::CYCLE_MAX); } void Nsf::Chips::Reset() { clocks.Reset( mmc5, fds ); if ( mmc5 ) mmc5->Reset(); if ( vrc6 ) vrc6->Reset(); if ( vrc7 ) vrc7->Reset(); if ( fds ) fds->Reset(); if ( s5b ) s5b->Reset(); if ( n163 ) n163->Reset(); } bool Nsf::Chips::UpdateSettings() { clocks.Reset( mmc5, fds ); return ( ( mmc5 ? mmc5->UpdateSettings() : 0U ) | ( vrc6 ? vrc6->UpdateSettings() : 0U ) | ( vrc7 ? vrc7->UpdateSettings() : 0U ) | ( fds ? fds->UpdateSettings() : 0U ) | ( s5b ? s5b->UpdateSettings() : 0U ) | ( n163 ? n163->UpdateSettings() : 0U ) ); } Nsf::Nsf(Context& context) : Image (SOUND), cpu (context.cpu), apu (context.apu), chips (NULL), favoredSystem (context.favoredSystem), tuneMode (Api::Nsf::TUNE_MODE_NTSC) { if (context.patch && context.patchResult) *context.patchResult = RESULT_ERR_UNSUPPORTED; Stream::In stream( &context.stream ); uint version; { byte data[5+1+2+6]; stream.Read( data ); if ( data[0] != Ascii<'N'>::V || data[1] != Ascii<'E'>::V || data[2] != Ascii<'S'>::V || data[3] != Ascii<'M'>::V || data[4] != 0x1A ) throw RESULT_ERR_INVALID_FILE; if (!data[6] || data[9] < 0x60 || data[11] < 0x60 || data[13] < 0x60) throw RESULT_ERR_CORRUPT_FILE; songs.count = data[6]; songs.start = data[7] >= 1 && data[7] <= data[6] ? data[7] - 1 : 0; addressing.load = data[8] | uint( data[9] ) << 8; addressing.init = data[10] | uint( data[11] ) << 8; addressing.play = data[12] | uint( data[13] ) << 8; version = data[5]; } stream.Read( songs.info.name, 32 ); stream.Read( songs.info.artist, 32 ); stream.Read( songs.info.copyright, 32 ); songs.info.name[31] = '\0'; songs.info.artist[31] = '\0'; songs.info.copyright[31] = '\0'; speed.ntsc = stream.Read16(); stream.Read( banks ); addressing.bankSwitched = 0 != ( uint( banks[0] ) | uint( banks[1] ) | uint( banks[2] ) | uint( banks[3] ) | uint( banks[4] ) | uint( banks[5] ) | uint( banks[6] ) | uint( banks[7] ) ); speed.pal = stream.Read16(); songs.current = songs.start; switch (stream.Read8() & 0x3) { case 0x0: tuneMode = Api::Nsf::TUNE_MODE_NTSC; break; case 0x1: tuneMode = Api::Nsf::TUNE_MODE_PAL; break; default: tuneMode = Api::Nsf::TUNE_MODE_BOTH; break; } uint types = stream.Read8(); if (!(types & Api::Nsf::CHIP_FDS) && addressing.load < 0x8000) throw RESULT_ERR_CORRUPT_FILE; dword length = 0; while (length < SIZE_4096K && stream.SafeRead8() <= 0xFF) ++length; if (length <= HEADER_RESERVED_LENGTH) throw RESULT_ERR_CORRUPT_FILE; length -= HEADER_RESERVED_LENGTH; stream.Seek( -idword(length) ); { const uint offset = addressing.load & 0xFFFU; prg.Source().Set( Ram::ROM, true, false, offset + length ); prg.Source().Fill( JAM ); stream.Read( prg.Source().Mem() + offset, length ); } if (types & Api::Nsf::CHIP_ALL) chips = new Chips (types,apu); if (Log::Available()) { Log log; log << "Nsf: version " << version; if (*songs.info.name) log << NST_LINEBREAK "Nsf: name: " << songs.info.name; if (*songs.info.artist) log << NST_LINEBREAK "Nsf: artist: " << songs.info.artist; if (*songs.info.copyright) log << NST_LINEBREAK "Nsf: copyright: " << songs.info.copyright; log << NST_LINEBREAK "Nsf: starting song " << (songs.start+1U) << " of " << songs.count << ( tuneMode == Api::Nsf::TUNE_MODE_NTSC ? NST_LINEBREAK "Nsf: NTSC mode" : tuneMode == Api::Nsf::TUNE_MODE_PAL ? NST_LINEBREAK "Nsf: PAL mode" : NST_LINEBREAK "Nsf: PAL/NTSC mode" ) << NST_LINEBREAK "Nsf: " << (length / SIZE_1K) << (addressing.bankSwitched ? "k bank-switched " : "k flat ") << ((types & Api::Nsf::CHIP_FDS) ? "PRG-RAM" : "PRG-ROM") << NST_LINEBREAK "Nsf: load address - " << Log::Hex( 16, addressing.load ) << NST_LINEBREAK "Nsf: init address - " << Log::Hex( 16, addressing.init ) << NST_LINEBREAK "Nsf: play address - " << Log::Hex( 16, addressing.play ) << NST_LINEBREAK; if (types & Api::Nsf::CHIP_ALL) { if ( chips->mmc5 ) log << "Nsf: MMC5 sound chip present" NST_LINEBREAK; if ( chips->vrc6 ) log << "Nsf: VRC6 sound chip present" NST_LINEBREAK; if ( chips->vrc7 ) log << "Nsf: VRC7 sound chip present" NST_LINEBREAK; if ( chips->fds ) log << "Nsf: FDS sound chip present" NST_LINEBREAK; if ( chips->s5b ) log << "Nsf: Sunsoft5B sound chip present" NST_LINEBREAK; if ( chips->n163 ) log << "Nsf: N163 sound chip present" NST_LINEBREAK; } } } Nsf::~Nsf() { delete chips; } Region Nsf::GetDesiredRegion() const { return tuneMode == Api::Nsf::TUNE_MODE_PAL ? REGION_PAL : REGION_NTSC; } System Nsf::GetDesiredSystem(Region region,CpuModel* cpu,PpuModel* ppu) const { if ((region == REGION_PAL) && (favoredSystem == FAVORED_DENDY)) { if (cpu) *cpu = CPU_DENDY; if (ppu) *ppu = PPU_DENDY; return SYSTEM_DENDY; } else { return Image::GetDesiredSystem( region, cpu, ppu ); } } uint Nsf::GetChips() const { uint types = 0; if (chips) { if ( chips->vrc6 ) types |= Api::Nsf::CHIP_VRC6; if ( chips->vrc7 ) types |= Api::Nsf::CHIP_VRC7; if ( chips->fds ) types |= Api::Nsf::CHIP_FDS; if ( chips->mmc5 ) types |= Api::Nsf::CHIP_MMC5; if ( chips->n163 ) types |= Api::Nsf::CHIP_N163; if ( chips->s5b ) types |= Api::Nsf::CHIP_S5B; } return types; } void Nsf::Reset(bool) { cpu.Map( 0x38EC ).Set( this, &Nsf::Peek_38EC, &Nsf::Poke_Nop ); cpu.Map( 0x38ED ).Set( this, &Nsf::Peek_38ED, &Nsf::Poke_Nop ); cpu.Map( 0x38EE ).Set( this, &Nsf::Peek_38EE, &Nsf::Poke_Nop ); cpu.Map( 0x38EF ).Set( this, &Nsf::Peek_38EF, &Nsf::Poke_Nop ); cpu.Map( 0x38F0 ).Set( this, &Nsf::Peek_38F0, &Nsf::Poke_Nop ); cpu.Map( 0x38F1 ).Set( this, &Nsf::Peek_38F1, &Nsf::Poke_Nop ); cpu.Map( 0x38F2 ).Set( this, &Nsf::Peek_38F2, &Nsf::Poke_Nop ); cpu.Map( 0x38F3 ).Set( this, &Nsf::Peek_38F3, &Nsf::Poke_Nop ); cpu.Map( 0x38F4 ).Set( this, &Nsf::Peek_38F4, &Nsf::Poke_Nop ); cpu.Map( 0x38F5 ).Set( this, &Nsf::Peek_38F5, &Nsf::Poke_Nop ); cpu.Map( 0x38F6 ).Set( this, &Nsf::Peek_38F6, &Nsf::Poke_Nop ); cpu.Map( 0x38F7 ).Set( this, &Nsf::Peek_38F7, &Nsf::Poke_Nop ); cpu.Map( 0x38F8 ).Set( this, &Nsf::Peek_38F8, &Nsf::Poke_Nop ); cpu.Map( 0x38F9 ).Set( this, &Nsf::Peek_38F9, &Nsf::Poke_Nop ); cpu.Map( 0x38FA ).Set( this, &Nsf::Peek_38FA, &Nsf::Poke_Nop ); cpu.Map( 0x38FB ).Set( this, &Nsf::Peek_38FB, &Nsf::Poke_Nop ); cpu.Map( 0x38FC ).Set( this, &Nsf::Peek_38FC, &Nsf::Poke_Nop ); cpu.Map( 0x38FD ).Set( this, &Nsf::Peek_38FD, &Nsf::Poke_Nop ); cpu.Map( 0x38FE ).Set( this, &Nsf::Peek_38FE, &Nsf::Poke_Nop ); cpu.Map( 0x38FF ).Set( this, &Nsf::Peek_38FF, &Nsf::Poke_Nop ); cpu.Map( 0x4017 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_4017 ); const bool fds = chips && chips->fds; if (addressing.bankSwitched) { if (fds) { cpu.Map( 0x5FF6 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Fds_5FF6 ); cpu.Map( 0x5FF7 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Fds_5FF7 ); } cpu.Map( 0x5FF8 ).Set( this, &Nsf::Peek_Nop, fds ? &Nsf::Poke_Fds_5FF8 : &Nsf::Poke_5FF8 ); cpu.Map( 0x5FF9 ).Set( this, &Nsf::Peek_Nop, fds ? &Nsf::Poke_Fds_5FF9 : &Nsf::Poke_5FF9 ); cpu.Map( 0x5FFA ).Set( this, &Nsf::Peek_Nop, fds ? &Nsf::Poke_Fds_5FFA : &Nsf::Poke_5FFA ); cpu.Map( 0x5FFB ).Set( this, &Nsf::Peek_Nop, fds ? &Nsf::Poke_Fds_5FFB : &Nsf::Poke_5FFB ); cpu.Map( 0x5FFC ).Set( this, &Nsf::Peek_Nop, fds ? &Nsf::Poke_Fds_5FFC : &Nsf::Poke_5FFC ); cpu.Map( 0x5FFD ).Set( this, &Nsf::Peek_Nop, fds ? &Nsf::Poke_Fds_5FFD : &Nsf::Poke_5FFD ); cpu.Map( 0x5FFE ).Set( this, &Nsf::Peek_Nop, fds ? &Nsf::Poke_Fds_5FFE : &Nsf::Poke_5FFE ); cpu.Map( 0x5FFF ).Set( this, &Nsf::Peek_Nop, fds ? &Nsf::Poke_Fds_5FFF : &Nsf::Poke_5FFF ); } else if (!fds) { for (dword i=0x8000, j=0; i < 0x10000; j += (i >= (addressing.load & 0xF000U)), i += 0x1000) prg.SwapBank( i-0x8000, j ); } if (fds) { cpu.Map( 0x4040, 0x407F ).Set( this, &Nsf::Peek_Fds_4040, &Nsf::Poke_Fds_4040 ); cpu.Map( 0x4080 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Fds_4080 ); cpu.Map( 0x4082 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Fds_4082 ); cpu.Map( 0x4083 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Fds_4083 ); cpu.Map( 0x4084 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Fds_4084 ); cpu.Map( 0x4085 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Fds_4085 ); cpu.Map( 0x4086 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Fds_4086 ); cpu.Map( 0x4087 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Fds_4087 ); cpu.Map( 0x4088 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Fds_4088 ); cpu.Map( 0x4089 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Fds_4089 ); cpu.Map( 0x408A ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Fds_408A ); cpu.Map( 0x4090 ).Set( this, &Nsf::Peek_Fds_4090, &Nsf::Poke_Nop ); cpu.Map( 0x4092 ).Set( this, &Nsf::Peek_Fds_4092, &Nsf::Poke_Nop ); cpu.Map( 0x6000, 0xFFFF ).Set( this, &Nsf::Peek_Fds_Ram, &Nsf::Poke_Fds_Ram ); } else { cpu.Map( 0x6000, 0x7FFF ).Set( this, &Nsf::Peek_Wrk, &Nsf::Poke_Wrk ); cpu.Map( 0x8000, 0x8FFF ).Set( this, &Nsf::Peek_Prg_8, &Nsf::Poke_Nop ); cpu.Map( 0x9000, 0x9FFF ).Set( this, &Nsf::Peek_Prg_9, &Nsf::Poke_Nop ); cpu.Map( 0xA000, 0xAFFF ).Set( this, &Nsf::Peek_Prg_A, &Nsf::Poke_Nop ); cpu.Map( 0xB000, 0xBFFF ).Set( this, &Nsf::Peek_Prg_B, &Nsf::Poke_Nop ); cpu.Map( 0xC000, 0xCFFF ).Set( this, &Nsf::Peek_Prg_C, &Nsf::Poke_Nop ); cpu.Map( 0xD000, 0xDFFF ).Set( this, &Nsf::Peek_Prg_D, &Nsf::Poke_Nop ); cpu.Map( 0xE000, 0xEFFF ).Set( this, &Nsf::Peek_Prg_E, &Nsf::Poke_Nop ); cpu.Map( 0xF000, 0xFFFF ).Set( this, &Nsf::Peek_Prg_F, &Nsf::Poke_Nop ); } if (chips) { if (chips->mmc5) { cpu.Map( 0x5000 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Mmc5_5000 ); cpu.Map( 0x5002 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Mmc5_5002 ); cpu.Map( 0x5003 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Mmc5_5003 ); cpu.Map( 0x5004 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Mmc5_5004 ); cpu.Map( 0x5006 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Mmc5_5006 ); cpu.Map( 0x5007 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Mmc5_5007 ); cpu.Map( 0x5010 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Mmc5_5010 ); cpu.Map( 0x5011 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Mmc5_5011 ); cpu.Map( 0x5015 ).Set( this, &Nsf::Peek_Mmc5_5015, &Nsf::Poke_Mmc5_5015 ); cpu.Map( 0x5205 ).Set( this, &Nsf::Peek_Mmc5_5205, &Nsf::Poke_Mmc5_5205 ); cpu.Map( 0x5206 ).Set( this, &Nsf::Peek_Mmc5_5206, &Nsf::Poke_Mmc5_5206 ); cpu.Map( 0x5C00, 0x5FF5 ).Set( this, &Nsf::Peek_Mmc5_5C00, &Nsf::Poke_Mmc5_5C00 ); } if (chips->vrc6) { cpu.Map( 0x9000 ).Set( &Nsf::Poke_Vrc6_9000 ); cpu.Map( 0x9001 ).Set( &Nsf::Poke_Vrc6_9001 ); cpu.Map( 0x9002 ).Set( &Nsf::Poke_Vrc6_9002 ); cpu.Map( 0xA000 ).Set( &Nsf::Poke_Vrc6_A000 ); cpu.Map( 0xA001 ).Set( &Nsf::Poke_Vrc6_A001 ); cpu.Map( 0xA002 ).Set( &Nsf::Poke_Vrc6_A002 ); cpu.Map( 0xB000 ).Set( &Nsf::Poke_Vrc6_B000 ); cpu.Map( 0xB001 ).Set( &Nsf::Poke_Vrc6_B001 ); cpu.Map( 0xB002 ).Set( &Nsf::Poke_Vrc6_B002 ); } if (chips->vrc7) { cpu.Map( 0x9010 ).Set( &Nsf::Poke_Vrc7_9010 ); cpu.Map( 0x9030 ).Set( &Nsf::Poke_Vrc7_9030 ); } if (chips->n163) { cpu.Map( 0x4800 ).Set( this, &Nsf::Peek_N163_48, &Nsf::Poke_N163_48 ); cpu.Map( 0xF800 ).Set( &Nsf::Poke_N163_F8 ); } if (chips->s5b) { cpu.Map( 0xC000 ).Set( &Nsf::Poke_S5b_C ); cpu.Map( 0xE000 ).Set( &Nsf::Poke_S5b_E ); } } cpu.Map( 0xFFFA ).Set( &Nsf::Peek_FFFA ); cpu.Map( 0xFFFB ).Set( &Nsf::Peek_FFFB ); cpu.Map( 0xFFFC ).Set( &Nsf::Peek_FFFC ); cpu.Map( 0xFFFD ).Set( &Nsf::Peek_FFFD ); routine.reset = Routine::RESET; routine.nmi = Routine::NMI; cpu.SetFrameCycles( cpu.GetModel() == CPU_RP2A03 ? PPU_RP2C02_HVSYNC : cpu.GetModel() == CPU_RP2A07 ? PPU_RP2C07_HVSYNC : PPU_DENDY_HVSYNC ); } bool Nsf::PowerOff() { StopSong(); return true; } Result Nsf::SelectSong(const uint song) { if (song < songs.count) { if (songs.current != song) { songs.current = song; if (routine.playing) { routine.nmi = Routine::NMI; apu.ClearBuffers(); } Api::Nsf::eventCallback( Api::Nsf::EVENT_SELECT_SONG ); return RESULT_OK; } return RESULT_NOP; } return RESULT_ERR_INVALID_PARAM; } Result Nsf::PlaySong() { if (!routine.playing) { routine.nmi = Routine::NMI; routine.playing = true; Api::Nsf::eventCallback( Api::Nsf::EVENT_PLAY_SONG ); return RESULT_OK; } return RESULT_NOP; } Result Nsf::StopSong() { if (routine.playing) { routine.playing = false; routine.nmi = Routine::NMI; apu.ClearBuffers(); Api::Nsf::eventCallback( Api::Nsf::EVENT_STOP_SONG ); return RESULT_OK; } return RESULT_NOP; } void Nsf::InitSong() { std::memset( wrk, 0x00, SIZE_8K ); if (chips && chips->mmc5) chips->mmc5->ClearExRam(); const bool fds = chips && chips->fds; if (addressing.bankSwitched) { if (fds) { for (uint i=0; i < 2; ++i) cpu.Poke( 0x5FF6+i, banks[6+i] ); } for (uint i=0; i < 8; ++i) cpu.Poke( 0x5FF8+i, banks[i] ); } else if (fds) { for (dword i=0x6000, j=0; i < 0x10000; j += (i >= (addressing.load & 0xF000U)), i += 0x1000) std::memcpy( chips->fds->ram + (i-0x6000), prg.Source().Mem(j * 0x1000), 0x1000 ); } if (fds) { cpu.Poke( 0x4089, 0x80 ); cpu.Poke( 0x408A, 0xE8 ); } apu.ClearBuffers(); std::memset( cpu.GetRam(), 0x00, Cpu::RAM_SIZE ); for (uint i=0x4000; i <= 0x4013; ++i) cpu.Poke( i, 0x00 ); cpu.Poke( 0x4015, 0x0F ); cpu.Poke( 0x4017, 0xC0 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Nsf::BeginFrame() { routine.jmp = (routine.playing ? 0xFA : 0xFD); if (routine.nmi) cpu.DoNMI(0); } Cycle Nsf::Chips::Clock(Cycle rateCycles,Cycle rateClock,const Cycle targetCycles) { if (clocks.next != Cpu::CYCLE_MAX) { NST_ASSERT( (mmc5 || fds) && (clocks.mmc5 != Cpu::CYCLE_MAX || clocks.fds != Cpu::CYCLE_MAX) ); if (clocks.mmc5 == clocks.next) clocks.mmc5 = mmc5->Clock( rateCycles, rateClock, targetCycles ) - rateCycles; if (clocks.fds == clocks.next) clocks.fds = fds->Clock( rateCycles, rateClock, targetCycles ) - rateCycles; clocks.next = NST_MIN(clocks.mmc5,clocks.fds); rateCycles += clocks.next; return rateCycles; } else { NST_ASSERT( !mmc5 && !fds ); return Channel::Clock( rateCycles, rateClock, targetCycles ); } } Nsf::Chips::Sample Nsf::Chips::GetSample() { return ( (mmc5 ? mmc5->GetSample() : 0) + (vrc6 ? vrc6->GetSample() : 0) + (vrc7 ? vrc7->GetSample() : 0) + (fds ? fds->GetSample() : 0) + (s5b ? s5b->GetSample() : 0) + (n163 ? n163->GetSample() : 0) ); } inline uint Nsf::FetchLast(uint offset) const { NST_ASSERT( offset <= 0xFFF ); return offset[chips && chips->fds ? chips->fds->ram + (sizeof(array(chips->fds->ram))-SIZE_4K) : prg[7]]; } NES_PEEK(Nsf,FFFA) { return routine.nmi ? routine.nmi &= Routine::NMI_B, routine.playing ? 0xEC : 0xFD : FetchLast(0xFFA); } NES_PEEK(Nsf,FFFB) { return routine.nmi ? routine.nmi &= Routine::NMI_A, 0x38 : FetchLast(0xFFB); } NES_PEEK(Nsf,FFFC) { return routine.reset ? routine.reset &= Routine::RESET_B, 0xFD : FetchLast(0xFFC); } NES_PEEK(Nsf,FFFD) { return routine.reset ? routine.reset &= Routine::RESET_A, 0x38 : FetchLast(0xFFD); } NES_PEEK(Nsf,38EC) { NST_VERIFY( routine.playing ); InitSong(); return LDA; } NES_PEEK(Nsf,38ED) { NST_VERIFY( routine.playing ); return songs.current; } NES_PEEK(Nsf,38EE) { NST_VERIFY( routine.playing ); return LDX; } NES_PEEK(Nsf,38EF) { NST_VERIFY( routine.playing ); return 0xFC; } NES_PEEK(Nsf,38F0) { NST_VERIFY( routine.playing ); return TXS; } NES_PEEK(Nsf,38F1) { NST_VERIFY( routine.playing ); return LDX; } NES_PEEK(Nsf,38F2) { NST_VERIFY( routine.playing ); return cpu.GetModel() == CPU_RP2A07; } NES_PEEK(Nsf,38F3) { NST_VERIFY( routine.playing ); return JSR; } NES_PEEK(Nsf,38F4) { NST_VERIFY( routine.playing ); return addressing.init & 0xFFU; } NES_PEEK(Nsf,38F5) { NST_VERIFY( routine.playing ); return addressing.init >> 8; } NES_PEEK(Nsf,38F6) { NST_VERIFY( routine.playing ); return SEI; } NES_PEEK(Nsf,38F7) { NST_VERIFY( routine.playing ); routine.jmp = 0xFD; return JMP; } NES_PEEK(Nsf,38F8) { NST_VERIFY( routine.playing ); return 0xFD; } NES_PEEK(Nsf,38F9) { NST_VERIFY( routine.playing ); return 0x38; } NES_PEEK(Nsf,38FA) { NST_VERIFY( routine.playing ); routine.jmp = 0xFD; return JSR; } NES_PEEK(Nsf,38FB) { NST_VERIFY( routine.playing ); return addressing.play & 0xFFU; } NES_PEEK(Nsf,38FC) { NST_VERIFY( routine.playing ); return addressing.play >> 8; } NES_PEEK(Nsf,38FD) { return JMP; } NES_PEEK(Nsf,38FE) { return routine.jmp; } NES_PEEK(Nsf,38FF) { return 0x38; } NES_POKE_D(Nsf,4017) { apu.WriteFrameCtrl( data ); } NES_PEEK_A (Nsf,Nop) { return address >> 8; } NES_POKE (Nsf,Nop) {} NES_PEEK_A (Nsf,Prg_8) { return prg[0][address - 0x8000]; } NES_PEEK_A (Nsf,Prg_9) { return prg[1][address - 0x9000]; } NES_PEEK_A (Nsf,Prg_A) { return prg[2][address - 0xA000]; } NES_PEEK_A (Nsf,Prg_B) { return prg[3][address - 0xB000]; } NES_PEEK_A (Nsf,Prg_C) { return prg[4][address - 0xC000]; } NES_PEEK_A (Nsf,Prg_D) { return prg[5][address - 0xD000]; } NES_PEEK_A (Nsf,Prg_E) { return prg[6][address - 0xE000]; } NES_PEEK_A (Nsf,Prg_F) { return prg[7][address - 0xF000]; } NES_PEEK_A (Nsf,Wrk) { return wrk[address - 0x6000]; } NES_POKE_AD (Nsf,Wrk) { wrk[address - 0x6000] = data; } NES_POKE_D (Nsf,5FF8) { prg.SwapBank( data ); } NES_POKE_D (Nsf,5FF9) { prg.SwapBank( data ); } NES_POKE_D (Nsf,5FFA) { prg.SwapBank( data ); } NES_POKE_D (Nsf,5FFB) { prg.SwapBank( data ); } NES_POKE_D (Nsf,5FFC) { prg.SwapBank( data ); } NES_POKE_D (Nsf,5FFD) { prg.SwapBank( data ); } NES_POKE_D (Nsf,5FFE) { prg.SwapBank( data ); } NES_POKE_D (Nsf,5FFF) { prg.SwapBank( data ); } NES_PEEK_A (Nsf,Fds_4040) { return chips->fds->ReadWaveData( address ); } NES_POKE_AD (Nsf,Fds_4040) { chips->fds->WriteWaveData( address, data ); } NES_POKE_D (Nsf,Fds_4080) { chips->fds->WriteReg0( data ); } NES_POKE_D (Nsf,Fds_4082) { chips->fds->WriteReg1( data ); } NES_POKE_D (Nsf,Fds_4083) { chips->fds->WriteReg2( data ); } NES_POKE_D (Nsf,Fds_4084) { chips->fds->WriteReg3( data ); } NES_POKE_D (Nsf,Fds_4085) { chips->fds->WriteReg4( data ); } NES_POKE_D (Nsf,Fds_4086) { chips->fds->WriteReg5( data ); } NES_POKE_D (Nsf,Fds_4087) { chips->fds->WriteReg6( data ); } NES_POKE_D (Nsf,Fds_4088) { chips->fds->WriteReg7( data ); } NES_POKE_D (Nsf,Fds_4089) { chips->fds->WriteReg8( data ); } NES_POKE_D (Nsf,Fds_408A) { chips->fds->WriteReg9( data ); } NES_PEEK (Nsf,Fds_4090) { return chips->fds->ReadVolumeGain(); } NES_PEEK (Nsf,Fds_4092) { return chips->fds->ReadSweepGain(); } NES_POKE_D (Nsf,Fds_5FF6) { chips->fds->SwapBank( prg, 0, data ); } NES_POKE_D (Nsf,Fds_5FF7) { chips->fds->SwapBank( prg, 1, data ); } NES_POKE_D (Nsf,Fds_5FF8) { chips->fds->SwapBank( prg, 2, data ); } NES_POKE_D (Nsf,Fds_5FF9) { chips->fds->SwapBank( prg, 3, data ); } NES_POKE_D (Nsf,Fds_5FFA) { chips->fds->SwapBank( prg, 4, data ); } NES_POKE_D (Nsf,Fds_5FFB) { chips->fds->SwapBank( prg, 5, data ); } NES_POKE_D (Nsf,Fds_5FFC) { chips->fds->SwapBank( prg, 6, data ); } NES_POKE_D (Nsf,Fds_5FFD) { chips->fds->SwapBank( prg, 7, data ); } NES_POKE_D (Nsf,Fds_5FFE) { chips->fds->SwapBank( prg, 8, data ); } NES_POKE_D (Nsf,Fds_5FFF) { chips->fds->SwapBank( prg, 9, data ); } NES_PEEK_A (Nsf,Fds_Ram) { return chips->fds->ram[address - 0x6000]; } NES_POKE_AD (Nsf,Fds_Ram) { chips->fds->ram[address - 0x6000] = data; } NES_POKE_D (Nsf,Mmc5_5000) { chips->mmc5->WriteSquareReg0( 0, data ); } NES_POKE_D (Nsf,Mmc5_5002) { chips->mmc5->WriteSquareReg1( 0, data ); } NES_POKE_D (Nsf,Mmc5_5003) { chips->mmc5->WriteSquareReg2( 0, data ); } NES_POKE_D (Nsf,Mmc5_5004) { chips->mmc5->WriteSquareReg0( 1, data ); } NES_POKE_D (Nsf,Mmc5_5006) { chips->mmc5->WriteSquareReg1( 1, data ); } NES_POKE_D (Nsf,Mmc5_5007) { chips->mmc5->WriteSquareReg2( 1, data ); } NES_POKE_D (Nsf,Mmc5_5010) { chips->mmc5->WritePcmReg0( data ); } NES_POKE_D (Nsf,Mmc5_5011) { chips->mmc5->WritePcmReg1( data ); } NES_POKE_D (Nsf,Mmc5_5015) { chips->mmc5->WriteCtrl( data ); } NES_PEEK (Nsf,Mmc5_5015) { return chips->mmc5->ReadCtrl(); } NES_PEEK (Nsf,Mmc5_5205) { return (chips->mmc5->mul[0] * chips->mmc5->mul[1]) >> 0 & 0xFF; } NES_PEEK (Nsf,Mmc5_5206) { return (chips->mmc5->mul[0] * chips->mmc5->mul[1]) >> 8 & 0xFF; } NES_POKE_D (Nsf,Mmc5_5205) { chips->mmc5->mul[0] = data; } NES_POKE_D (Nsf,Mmc5_5206) { chips->mmc5->mul[1] = data; } NES_PEEK_A (Nsf,Mmc5_5C00) { return chips->mmc5->exRam[address - 0x5C00]; } NES_POKE_AD (Nsf,Mmc5_5C00) { chips->mmc5->exRam[address - 0x5C00] = data; } NES_POKE_D (Nsf,Vrc6_9000) { chips->vrc6->WriteSquareReg0( 0, data ); } NES_POKE_D (Nsf,Vrc6_9001) { chips->vrc6->WriteSquareReg1( 0, data ); } NES_POKE_D (Nsf,Vrc6_9002) { chips->vrc6->WriteSquareReg2( 0, data ); } NES_POKE_D (Nsf,Vrc6_A000) { chips->vrc6->WriteSquareReg0( 1, data ); } NES_POKE_D (Nsf,Vrc6_A001) { chips->vrc6->WriteSquareReg1( 1, data ); } NES_POKE_D (Nsf,Vrc6_A002) { chips->vrc6->WriteSquareReg2( 1, data ); } NES_POKE_D (Nsf,Vrc6_B000) { chips->vrc6->WriteSawReg0( data ); } NES_POKE_D (Nsf,Vrc6_B001) { chips->vrc6->WriteSawReg1( data ); } NES_POKE_D (Nsf,Vrc6_B002) { chips->vrc6->WriteSawReg2( data ); } NES_POKE_D (Nsf,Vrc7_9010) { chips->vrc7->SelectReg( data ); } NES_POKE_D (Nsf,Vrc7_9030) { chips->vrc7->WriteReg( data ); } NES_POKE_D (Nsf,S5b_C) { chips->s5b->SelectReg( data ); } NES_POKE_D (Nsf,S5b_E) { chips->s5b->WriteReg( data ); } NES_PEEK (Nsf,N163_48) { return chips->n163->ReadData(); } NES_POKE_D (Nsf,N163_48) { chips->n163->WriteData( data ); } NES_POKE_D (Nsf,N163_F8) { chips->n163->WriteAddress( data ); } } } nestopia-1.51.1/source/core/NstNsf.hpp000066400000000000000000000162101411157722000175750ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_NSF_H #define NST_NSF_H #include "NstImage.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class Nsf : public Image { public: explicit Nsf(Context&); void BeginFrame(); uint GetChips() const; Result SelectSong(uint); Result PlaySong(); Result StopSong(); private: ~Nsf(); void Reset(bool); bool PowerOff(); void InitSong(); Region GetDesiredRegion() const; System GetDesiredSystem(Region,CpuModel*,PpuModel*) const; inline uint FetchLast(uint) const; typedef Memory Prg; enum { JAM = 0x02, JMP = 0x4C, JSR = 0x20, SEI = 0x78, LDA = 0xA9, LDX = 0xA2, TXS = 0x9A }; NES_DECL_PEEK( 38EC ); NES_DECL_PEEK( 38ED ); NES_DECL_PEEK( 38EE ); NES_DECL_PEEK( 38EF ); NES_DECL_PEEK( 38F0 ); NES_DECL_PEEK( 38F1 ); NES_DECL_PEEK( 38F2 ); NES_DECL_PEEK( 38F3 ); NES_DECL_PEEK( 38F4 ); NES_DECL_PEEK( 38F5 ); NES_DECL_PEEK( 38F6 ); NES_DECL_PEEK( 38F7 ); NES_DECL_PEEK( 38F8 ); NES_DECL_PEEK( 38F9 ); NES_DECL_PEEK( 38FA ); NES_DECL_PEEK( 38FB ); NES_DECL_PEEK( 38FC ); NES_DECL_PEEK( 38FD ); NES_DECL_PEEK( 38FE ); NES_DECL_PEEK( 38FF ); NES_DECL_POKE( 4017 ); NES_DECL_POKE( 5FF8 ); NES_DECL_POKE( 5FF9 ); NES_DECL_POKE( 5FFA ); NES_DECL_POKE( 5FFB ); NES_DECL_POKE( 5FFC ); NES_DECL_POKE( 5FFD ); NES_DECL_POKE( 5FFE ); NES_DECL_POKE( 5FFF ); NES_DECL_PEEK( Prg_8 ); NES_DECL_PEEK( Prg_9 ); NES_DECL_PEEK( Prg_A ); NES_DECL_PEEK( Prg_B ); NES_DECL_PEEK( Prg_C ); NES_DECL_PEEK( Prg_D ); NES_DECL_PEEK( Prg_E ); NES_DECL_PEEK( Prg_F ); NES_DECL_PEEK( Wrk ); NES_DECL_POKE( Wrk ); NES_DECL_PEEK( Fds_4040 ); NES_DECL_POKE( Fds_4040 ); NES_DECL_POKE( Fds_4080 ); NES_DECL_POKE( Fds_4082 ); NES_DECL_POKE( Fds_4083 ); NES_DECL_POKE( Fds_4084 ); NES_DECL_POKE( Fds_4085 ); NES_DECL_POKE( Fds_4086 ); NES_DECL_POKE( Fds_4087 ); NES_DECL_POKE( Fds_4088 ); NES_DECL_POKE( Fds_4089 ); NES_DECL_POKE( Fds_408A ); NES_DECL_PEEK( Fds_4090 ); NES_DECL_PEEK( Fds_4092 ); NES_DECL_POKE( Fds_5FF6 ); NES_DECL_POKE( Fds_5FF7 ); NES_DECL_POKE( Fds_5FF8 ); NES_DECL_POKE( Fds_5FF9 ); NES_DECL_POKE( Fds_5FFA ); NES_DECL_POKE( Fds_5FFB ); NES_DECL_POKE( Fds_5FFC ); NES_DECL_POKE( Fds_5FFD ); NES_DECL_POKE( Fds_5FFE ); NES_DECL_POKE( Fds_5FFF ); NES_DECL_PEEK( Fds_Ram ); NES_DECL_POKE( Fds_Ram ); NES_DECL_POKE( Mmc5_5000 ); NES_DECL_POKE( Mmc5_5002 ); NES_DECL_POKE( Mmc5_5003 ); NES_DECL_POKE( Mmc5_5004 ); NES_DECL_POKE( Mmc5_5006 ); NES_DECL_POKE( Mmc5_5007 ); NES_DECL_POKE( Mmc5_5010 ); NES_DECL_POKE( Mmc5_5011 ); NES_DECL_POKE( Mmc5_5015 ); NES_DECL_PEEK( Mmc5_5015 ); NES_DECL_PEEK( Mmc5_5205 ); NES_DECL_PEEK( Mmc5_5206 ); NES_DECL_POKE( Mmc5_5205 ); NES_DECL_POKE( Mmc5_5206 ); NES_DECL_PEEK( Mmc5_5C00 ); NES_DECL_POKE( Mmc5_5C00 ); NES_DECL_POKE( Vrc6_9000 ); NES_DECL_POKE( Vrc6_9001 ); NES_DECL_POKE( Vrc6_9002 ); NES_DECL_POKE( Vrc6_A000 ); NES_DECL_POKE( Vrc6_A001 ); NES_DECL_POKE( Vrc6_A002 ); NES_DECL_POKE( Vrc6_B000 ); NES_DECL_POKE( Vrc6_B001 ); NES_DECL_POKE( Vrc6_B002 ); NES_DECL_POKE( Vrc7_9010 ); NES_DECL_POKE( Vrc7_9030 ); NES_DECL_PEEK( N163_48 ); NES_DECL_POKE( N163_48 ); NES_DECL_POKE( N163_F8 ); NES_DECL_POKE( S5b_C ); NES_DECL_POKE( S5b_E ); NES_DECL_PEEK( FFFA ); NES_DECL_PEEK( FFFB ); NES_DECL_PEEK( FFFC ); NES_DECL_PEEK( FFFD ); NES_DECL_PEEK( Nop ); NES_DECL_POKE( Nop ); enum Header { HEADER_SIZE = 128, HEADER_RESERVED_LENGTH = 4 }; class Chips; struct Songs { byte start; byte current; byte count; const byte padding; struct { char name[32]; char artist[32]; char copyright[32]; } info; Songs() : start (0), current (0), count (0), padding (0) {} }; struct Speed { word ntsc; word pal; Speed() : ntsc (0), pal (0) {} }; struct Addressing { word play; word init; word load; word bankSwitched; Addressing() : play (0x0000), init (0x0000), load (0x0000), bankSwitched (false) {} }; struct Routine { enum { RESET_A = 0x1, RESET_B = 0x2, RESET = RESET_A|RESET_B, NMI_A = 0x1, NMI_B = 0x2, NMI = NMI_A|NMI_B }; bool playing; byte nmi; byte reset; byte jmp; Routine() : playing (false), nmi (0), reset (0), jmp (0x00) {} }; Prg prg; Routine routine; Cpu& cpu; Apu& apu; Chips* chips; FavoredSystem favoredSystem; Songs songs; Addressing addressing; Speed speed; uint tuneMode; byte banks[8]; byte wrk[SIZE_8K]; public: cstring GetName() const { return songs.info.name; } cstring GetArtist() const { return songs.info.artist; } cstring GetCopyright() const { return songs.info.copyright; } uint GetTuneMode() const { return tuneMode; } uint NumSongs() const { return songs.count; } uint CurrentSong() const { return songs.current; } uint StartingSong() const { return songs.start; } bool UsesBankSwitching() const { return addressing.bankSwitched; } bool IsPlaying() const { return routine.playing; } uint GetInitAddress() const { return addressing.init; } uint GetLoadAddress() const { return addressing.load; } uint GetPlayAddress() const { return addressing.play; } }; } } #endif nestopia-1.51.1/source/core/NstPatcher.cpp000066400000000000000000000104671411157722000204400ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstVector.hpp" #include "NstPatcher.hpp" #include "NstPatcherIps.hpp" #include "NstPatcherUps.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Patcher::Patcher(bool b) : ips (NULL), ups (NULL), bypassChecksum (b) { } Patcher::~Patcher() { Destroy(); } void Patcher::Destroy() { delete ips; ips = NULL; delete ups; ups = NULL; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif Result Patcher::Load(std::istream& stream) { Destroy(); if (Ips::IsIps( stream )) { ips = new (std::nothrow) Ips; return ips ? ips->Load( stream ) : RESULT_ERR_OUT_OF_MEMORY; } if (Ups::IsUps( stream )) { ups = new (std::nothrow) Ups; return ups ? ups->Load( stream, bypassChecksum ) : RESULT_ERR_OUT_OF_MEMORY; } return RESULT_ERR_INVALID_FILE; } Result Patcher::Load(std::istream& patchStream,std::istream& srcStream) { Result result = Load( patchStream ); if (NES_SUCCEEDED(result)) { result = Test( srcStream ); if (NES_FAILED(result)) Destroy(); } return result; } Result Patcher::Save(std::ostream& stream) const { return ( ips ? ips->Save( stream ) : ups ? ups->Save( stream ) : RESULT_ERR_NOT_READY ); } Result Patcher::Test(std::istream& stream) const { return ( ips ? ips->Test( stream ) : ups ? ups->Test( stream, bypassChecksum ) : RESULT_ERR_NOT_READY ); } Result Patcher::Test(const Block* const blocks,const uint numBlocks) const { NST_ASSERT( blocks || !numBlocks ); if (numBlocks > 1) { Vector buffer; try { dword size = 0; for (uint i=0; i < numBlocks; ++i) size += blocks[i].size; buffer.Reserve( size ); } catch (...) { return RESULT_ERR_OUT_OF_MEMORY; } for (uint i=0; i < numBlocks; ++i) buffer.Append( blocks[i].data, blocks[i].size ); return Test( buffer.Begin(), buffer.Size() ); } else { return Test( blocks ? blocks->data : NULL, blocks ? blocks->size : 0 ); } } Result Patcher::Test(const byte* const data,const dword size) const { return ( ips ? ips->Test( data, size ) : ups ? ups->Test( data, size, bypassChecksum ) : RESULT_ERR_NOT_READY ); } bool Patcher::Patch(const byte* const src,byte* const dst,const dword size,const dword offset) const { return ( ips ? ips->Patch( src, dst, size, offset ) : ups ? ups->Patch( src, dst, size, offset ) : false ); } Result Patcher::Create(const Type type,const byte* const src,const byte* const dst,const dword length) { Destroy(); switch (type) { case IPS: ips = new (std::nothrow) Ips; return ips ? ips->Create( src, dst, length ) : RESULT_ERR_OUT_OF_MEMORY; case UPS: ups = new (std::nothrow) Ups; return ups ? ups->Create( src, dst, length ) : RESULT_ERR_OUT_OF_MEMORY; } return RESULT_ERR_UNSUPPORTED; } bool Patcher::Empty() const { return ( ips ? ips->Empty() : ups ? ups->Empty() : true ); } } } nestopia-1.51.1/source/core/NstPatcher.hpp000066400000000000000000000040501411157722000204340ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_PATCHER_H #define NST_PATCHER_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include namespace Nes { namespace Core { class Ips; class Ups; class Patcher { public: explicit Patcher(bool=false); ~Patcher(); enum Type { IPS, UPS }; struct Block { const byte* data; dword size; }; Result Load(std::istream&); Result Load(std::istream&,std::istream&); Result Test(std::istream&) const; Result Test(const byte*,dword) const; Result Test(const Block*,uint) const; Result Save(std::ostream&) const; Result Create(Type,const byte*,const byte*,dword); bool Patch(const byte*,byte*,dword,dword=0) const; void Destroy(); bool Empty() const; private: Ips* ips; Ups* ups; const bool bypassChecksum; public: template Result Test(const Block (&blocks)[N]) { NST_COMPILE_ASSERT( N > 0 ); return Test( blocks, N ); } }; } } #endif nestopia-1.51.1/source/core/NstPatcherIps.cpp000066400000000000000000000163061411157722000211120ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include #include "NstStream.hpp" #include "NstPatcherIps.hpp" namespace Nes { namespace Core { Ips::~Ips() { Destroy(); } bool Ips::IsIps(std::istream& stream) { try { byte data[5]; Stream::In(&stream).Peek( data, 5 ); return ( data[0] == Ascii<'P'>::V && data[1] == Ascii<'A'>::V && data[2] == Ascii<'T'>::V && data[3] == Ascii<'C'>::V && data[4] == Ascii<'H'>::V ); } catch (...) { return false; } } Result Ips::Load(std::istream& stdStream) { Destroy(); if (!IsIps(stdStream)) return RESULT_ERR_INVALID_FILE; try { Stream::In stream( &stdStream ); stream.Seek( 5 ); while (!stream.Eof()) { byte data[4]; stream.Read( data, 3 ); if ( data[0] == Ascii<'E'>::V && data[1] == Ascii<'O'>::V && data[2] == Ascii<'F'>::V ) break; blocks.push_back(Block()); Block& block = blocks.back(); block.data = NULL; block.offset = dword(data[0]) << 16 | uint(data[1]) << 8 | data[2]; stream.Read( data, 2 ); block.length = uint(data[0]) << 8 | data[1]; if (block.length) { block.fill = NO_FILL; block.data = new byte [block.length]; stream.Read( block.data, block.length ); } else { stream.Read( data, 2 ); block.length = uint(data[0]) << 8 | data[1]; if (block.length) block.fill = stream.Read8(); else throw RESULT_ERR_CORRUPT_FILE; } } } catch (Result result) { Destroy(); return result; } catch (const std::bad_alloc&) { Destroy(); return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { Destroy(); return RESULT_ERR_GENERIC; } return RESULT_OK; } Result Ips::Save(std::ostream& stdStream) const { try { Stream::Out stream( &stdStream ); byte data[8]; data[0] = Ascii<'P'>::V; data[1] = Ascii<'A'>::V; data[2] = Ascii<'T'>::V; data[3] = Ascii<'C'>::V; data[4] = Ascii<'H'>::V; stream.Write( data, 5 ); for (Blocks::const_iterator it(blocks.begin()), end(blocks.end()); it != end; ++it) { data[0] = it->offset >> 16 & 0xFF; data[1] = it->offset >> 8 & 0xFF; data[2] = it->offset >> 0 & 0xFF; stream.Write( data, 3 ); if (it->fill != NO_FILL) { data[0] = 0; data[1] = 0; stream.Write( data, 2 ); } data[0] = it->length >> 8 & 0xFF; data[1] = it->length >> 0 & 0xFF; stream.Write( data, 2 ); if (it->fill == NO_FILL) stream.Write( it->data, it->length ); else stream.Write8( it->fill ); } data[0] = Ascii<'E'>::V; data[1] = Ascii<'O'>::V; data[2] = Ascii<'F'>::V; stream.Write( data, 3 ); } catch (Result result) { return result; } catch (const std::bad_alloc&) { return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { return RESULT_ERR_GENERIC; } return RESULT_OK; } Result Ips::Test(std::istream&) const { return RESULT_OK; } Result Ips::Test(const byte*,dword) const { return RESULT_OK; } bool Ips::Patch(const byte* const src,byte* const dst,const dword length,const dword offset) const { NST_ASSERT( !length || (src && dst) ); bool patched = false; if (length) { if (src != dst) std::memcpy( dst, src, length ); for (Blocks::const_iterator it(blocks.begin()), end(blocks.end()); it != end; ++it) { NST_ASSERT( it->length ); if (it->offset < offset) continue; if (it->offset >= offset + length) break; const dword pos = it->offset - offset; const dword part = NST_MIN(it->length,length-pos); if (it->fill == NO_FILL) std::memcpy( dst + pos, it->data, part ); else std::memset( dst + pos, it->fill, part ); patched = true; } } return patched; } Result Ips::Create(const byte* const src,const byte* const dst,const dword length) { NST_ASSERT( !length || (src && dst) ); Destroy(); try { for (dword i=0; i < length; ) { dword j = i++; if (src[j] == dst[j]) continue; for (dword k=0; i < length; ++i) { if (src[i] != dst[i]) { k = 0; } else if (k++ == MIN_EQUAL) { i -= MIN_EQUAL; break; } } do { if (j == AsciiId<'F','O','E'>::V) --j; blocks.push_back(Block()); Block& block = blocks.back(); block.data = NULL; block.offset = j; uint c = dst[j]; dword k = j; const dword stop = NST_MIN(j + MAX_BLOCK,i); while (++k != stop && c == dst[k]); if (k - j >= MIN_BEG_RUN) { block.fill = c; block.length = k - j; } else { dword l = k; if (k + 1 < stop) { c = dst[k]; for (l=k++; k < stop; ++k) { if (c != dst[k]) { c = dst[k]; l = k; } else if (k - l == MIN_MID_RUN) { k = l; break; } } } if (k == stop && k - l >= MIN_END_RUN) k = l; if (k == AsciiId<'F','O','E'>::V) ++k; block.fill = NO_FILL; block.length = k - j; block.data = new byte [block.length]; std::memcpy( block.data, dst + j, block.length ); } j = k; } while (j != i); } } catch (Result result) { Destroy(); return result; } catch (const std::bad_alloc&) { Destroy(); return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { Destroy(); return RESULT_ERR_GENERIC; } return RESULT_OK; } void Ips::Destroy() { for (Blocks::iterator it(blocks.begin()), end(blocks.end()); it != end; ++it) delete [] it->data; blocks.clear(); } } } nestopia-1.51.1/source/core/NstPatcherIps.hpp000066400000000000000000000037771411157722000211270ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_IPS_H #define NST_IPS_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include namespace Nes { namespace Core { class Ips { public: ~Ips(); enum { MAX_LENGTH = 0xFFFFFF }; static bool IsIps(std::istream&); Result Load(std::istream&); Result Test(std::istream&) const; Result Test(const byte*,dword) const; Result Save(std::ostream&) const; Result Create(const byte*,const byte*,dword); bool Patch(const byte*,byte*,dword,dword=0) const; void Destroy(); private: enum { MIN_EQUAL = 5, MIN_BEG_RUN = 9, MIN_MID_RUN = 13, MIN_END_RUN = 9, NO_FILL = 0xFFFF, MAX_BLOCK = 0xFFFF }; struct Block { byte* data; dword offset; word length; word fill; }; typedef std::vector Blocks; Blocks blocks; public: bool Empty() const { return blocks.empty(); } }; } } #endif nestopia-1.51.1/source/core/NstPatcherUps.cpp000066400000000000000000000205741411157722000211300ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include #include "NstVector.hpp" #include "NstCrc32.hpp" #include "NstStream.hpp" #include "NstPatcherUps.hpp" namespace Nes { namespace Core { class Ups::Reader { public: uint Read(); dword ReadInt(); dword ReadCrc(); private: Stream::In stream; dword remaining; dword crc; public: explicit Reader(std::istream& stdStream) : stream (&stdStream), remaining (stream.Length()), crc (0) {} void ReadSignature() { if ( Read() != Ascii<'U'>::V || Read() != Ascii<'P'>::V || Read() != Ascii<'S'>::V || Read() != Ascii<'1'>::V ) throw RESULT_ERR_INVALID_FILE; } dword Remaining() const { return remaining; } dword Crc() const { return crc; } }; class Ups::Writer { public: void Write(uint); void Write(const byte* NST_RESTRICT,dword); void WriteInt(dword); void WriteCrc(dword); private: Stream::Out stream; dword crc; public: explicit Writer(std::ostream& stdStream) : stream (&stdStream), crc (0) {} void WriteSignature() { const byte data[] = { Ascii<'U'>::V, Ascii<'P'>::V, Ascii<'S'>::V, Ascii<'1'>::V }; Write( data, sizeof(data) ); } dword Crc() const { return crc; } }; #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Ups::Ups() : srcSize (0), srcCrc (0), dstSize (0), dstCrc (0), patch (NULL) { } Ups::~Ups() { Destroy(); } void Ups::Destroy() { srcSize = 0; srcCrc = 0; dstSize = 0; dstCrc = 0; delete [] patch; patch = NULL; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif bool Ups::IsUps(std::istream& stream) { try { return Stream::In(&stream).Peek32() == AsciiId<'U','P','S','1'>::V; } catch (...) { return false; } } Result Ups::Load(std::istream& stdStream,const bool bypassChecksum) { Destroy(); try { Reader reader( stdStream ); reader.ReadSignature(); srcSize = reader.ReadInt(); dstSize = reader.ReadInt(); const dword size = NST_MAX(srcSize,dstSize) + 1; patch = new byte [size]; std::memset( patch, 0, size ); for (dword i=0; reader.Remaining() > 4+4+4; ++i) { i += reader.ReadInt(); if (i > MAX_OFFSET) throw RESULT_ERR_OUT_OF_MEMORY; while (const uint data = reader.Read()) { if (i < dstSize) patch[i++] = data; else throw RESULT_ERR_CORRUPT_FILE; } } srcCrc = reader.ReadCrc(); dstCrc = reader.ReadCrc(); const dword crc = reader.Crc(); const dword fileCrc = reader.ReadCrc(); if (!bypassChecksum && crc != fileCrc) throw RESULT_ERR_INVALID_CRC; } catch (Result result) { Destroy(); return result; } catch (const std::bad_alloc&) { Destroy(); return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { Destroy(); return RESULT_ERR_CORRUPT_FILE; } return RESULT_OK; } Result Ups::Save(std::ostream& stdStream) const { try { Writer writer( stdStream ); writer.WriteSignature(); writer.WriteInt( srcSize ); writer.WriteInt( dstSize ); for (dword i=0, offset=0, n=dstSize; i < n; ++i) { if (patch[i]) { writer.WriteInt( i - offset ); offset = i; while (patch[++i]); NST_ASSERT( i <= n ); writer.Write( patch + offset, i - offset ); writer.Write( 0 ); offset = i + 1; } } writer.WriteCrc( srcCrc ); writer.WriteCrc( dstCrc ); writer.WriteCrc( writer.Crc() ); } catch (Result result) { return result; } catch (const std::bad_alloc&) { return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { return RESULT_ERR_GENERIC; } return RESULT_OK; } Result Ups::Test(std::istream& stdStream,const bool bypassChecksum) const { Vector buffer( srcSize ); try { Stream::In stream( &stdStream ); if (stream.Length() < buffer.Size()) return RESULT_ERR_CORRUPT_FILE; if (buffer.Size()) stream.Peek( buffer.Begin(), buffer.Size() ); } catch (Result result) { return result; } catch (const std::bad_alloc&) { return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { return RESULT_ERR_CORRUPT_FILE; } return Test( buffer.Begin(), buffer.Size(), bypassChecksum ); } Result Ups::Test(const byte* const NST_RESTRICT src,const dword size,const bool bypassChecksum) const { NST_ASSERT( !size || src ); if (size < srcSize) return RESULT_ERR_CORRUPT_FILE; if (!bypassChecksum) { if (Crc32::Compute( src, srcSize ) != srcCrc) return RESULT_ERR_INVALID_CRC; dword crc = 0; for (dword i=0, n=dstSize; i < n; ++i) crc = Crc32::Compute( (i < size ? src[i] : 0U) ^ patch[i], crc ); if (crc != dstCrc) return RESULT_ERR_INVALID_CRC; } return RESULT_OK; } bool Ups::Patch(const byte* const src,byte* const dst,const dword size,dword offset) const { NST_ASSERT( !size || (src && dst) ); uint patched = 0; if (dstSize || src != dst) { for (dword i=0, end=dstSize; i < size; ++i) dst[i] = src[i] ^ (offset < end ? patched |= patch[offset], patch[offset++] : 0U); } return patched; } Result Ups::Create(const byte* const src,const byte* const dst,const dword size) { NST_ASSERT( !size || (src && dst) ); Destroy(); if (size) { patch = new (std::nothrow) byte [size]; if (!patch) return RESULT_ERR_OUT_OF_MEMORY; srcSize = size; dstSize = size; srcCrc = Crc32::Compute( src, size ); dstCrc = Crc32::Compute( dst, size ); for (dword i=0; i < size; ++i) patch[i] = uint(src[i]) ^ uint(dst[i]); } return RESULT_OK; } uint Ups::Reader::Read() { if (remaining) remaining--; else throw 1; const uint data = stream.Read8(); crc = Crc32::Compute( data, crc ); return data; } dword Ups::Reader::ReadInt() { dword v = 0, s = 0; for (;;) { uint b = Read(); v += (b & 0x7F) << s; if (v > MAX_SIZE) throw 1; if (b & 0x80) break; s += 7; v += 0x1UL << s; } return v; } dword Ups::Reader::ReadCrc() { dword crc = 0; for (uint i=0; i < 32; i += 8) crc |= dword(Read()) << i; return crc; } void Ups::Writer::Write(const uint data) { crc = Crc32::Compute( data, crc ); stream.Write8( data ); } void Ups::Writer::Write(const byte* const NST_RESTRICT data,const dword size) { crc = Crc32::Compute( data, size, crc ); stream.Write( data, size ); } void Ups::Writer::WriteCrc(const dword crc) { for (uint i=0; i < 32; i += 8) Write( crc >> i & 0xFF ); } void Ups::Writer::WriteInt(dword v) { for (;;) { uint x = v & 0x7F; v >>= 7; if (!v) { Write( 0x80 | x ); break; } Write( x ); v--; } } } } nestopia-1.51.1/source/core/NstPatcherUps.hpp000066400000000000000000000035501411157722000211300ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_UPS_H #define NST_UPS_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class Ups { public: Ups(); ~Ups(); static bool IsUps(std::istream&); Result Load(std::istream&,bool); Result Save(std::ostream&) const; Result Test(std::istream&,bool) const; Result Test(const byte* NST_RESTRICT,dword,bool) const; Result Create(const byte*,const byte*,dword); bool Patch(const byte*,byte*,dword,dword=0) const; void Destroy(); private: class Reader; class Writer; enum { MAX_SIZE = SIZE_16384K, MAX_OFFSET = SIZE_16384K }; dword srcSize; dword srcCrc; dword dstSize; dword dstCrc; byte* patch; public: bool Empty() const { return dstSize == 0; } }; } } #endif nestopia-1.51.1/source/core/NstPins.cpp000066400000000000000000000040671411157722000177620ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include #include "NstCore.hpp" #include "NstPins.hpp" #ifndef ANDROID #include #endif namespace Nes { namespace Core { wcstring Pins::ConstPinsProxy::ComponentProxy::Init(wcstring s) { while (*s && *s != L' ') s++; return s; } Pins::ConstPinsProxy::ComponentProxy::ComponentProxy(wcstring s) : component(s), end(Init(s)) { } bool Pins::ConstPinsProxy::ComponentProxy::operator == (wcstring s) const { return ulong(end - component) == wcslen(s) && Core::StringCompare( component, s, end - component ) == 0; } uint Pins::ConstPinsProxy::ComponentProxy::LineProxy::Init(wchar_t c,wcstring s) { if (*s == L' ' && Core::StringCompare(s+1,&c,1) == 0) { const ulong line = std::wcstoul( s+2, NULL, 10 ); if (errno != ERANGE && line < ~0U) return line; } return ~0U; } Pins::ConstPinsProxy::ComponentProxy::LineProxy::LineProxy(wchar_t c,wcstring s) : line(Init(c,s)) { } } } nestopia-1.51.1/source/core/NstPins.hpp000066400000000000000000000064011411157722000177610ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_PINS_H #define NST_PINS_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstProperties.hpp" namespace Nes { namespace Core { class Pins : public Properties { public: class PinsProxy : public Properties::Proxy { public: PinsProxy(Container*& c,uint i) : Proxy(c,i) {} void operator = (wcstring s) { *static_cast(this) = s; } }; class ConstPinsProxy : public Properties::ConstProxy { public: ConstPinsProxy(const Container* c,uint i) : ConstProxy(c,i) {} ConstPinsProxy(PinsProxy p) : ConstProxy(p) {} class ComponentProxy : public ImplicitBool { static wcstring Init(wcstring); wcstring const component; wcstring const end; public: explicit ComponentProxy(wcstring); bool operator == (wcstring) const; class LineProxy : public ImplicitBool { static uint Init(wchar_t,wcstring); const uint line; public: LineProxy(wchar_t,wcstring); bool operator == (uint l) const { return line == l; } bool operator != (uint l) const { return line != l; } uint operator * () const { return line; } bool operator ! () const { return line == ~0U; } }; bool operator != (wcstring s) const { return !(*this == s); } bool operator ! () const { return !(end - component); } LineProxy A() const { return LineProxy( L'A', end ); } LineProxy D() const { return LineProxy( L'D', end ); } }; ComponentProxy C(wcstring c) const { return ComponentProxy(function); } }; Pins() {} Pins(const Pins& pins) : Properties(pins) {} Pins& operator = (const Pins& pins) { *static_cast(this) = pins; return *this; } PinsProxy operator [] (uint i) { return PinsProxy( container, i ); } ConstPinsProxy operator [] (uint i) const { return ConstPinsProxy( container, i ); } }; } } #endif nestopia-1.51.1/source/core/NstPpu.cpp000066400000000000000000002166361411157722000176240ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstCpu.hpp" #include "NstPpu.hpp" #include "NstState.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif const byte Ppu::yuvMaps[4][0x40] = { { 0x35, 0x23, 0x16, 0x22, 0x1C, 0x09, 0x2D, 0x15, 0x20, 0x00, 0x27, 0x05, 0x04, 0x28, 0x08, 0x20, 0x21, 0x27, 0x07, 0x29, 0x3C, 0x32, 0x36, 0x12, 0x28, 0x2B, 0x0D, 0x08, 0x10, 0x3D, 0x24, 0x01, 0x01, 0x31, 0x33, 0x2A, 0x2C, 0x0C, 0x1B, 0x14, 0x0D, 0x07, 0x34, 0x06, 0x13, 0x02, 0x26, 0x0D, 0x0D, 0x19, 0x10, 0x0A, 0x39, 0x03, 0x37, 0x17, 0x09, 0x11, 0x1A, 0x1D, 0x38, 0x25, 0x18, 0x3A }, { 0x0D, 0x27, 0x18, 0x39, 0x3A, 0x25, 0x1C, 0x31, 0x16, 0x13, 0x38, 0x34, 0x20, 0x23, 0x3C, 0x1A, 0x09, 0x21, 0x06, 0x10, 0x1B, 0x29, 0x08, 0x22, 0x2D, 0x24, 0x01, 0x2B, 0x32, 0x08, 0x0D, 0x03, 0x04, 0x36, 0x26, 0x33, 0x11, 0x07, 0x10, 0x02, 0x14, 0x28, 0x00, 0x09, 0x12, 0x0D, 0x28, 0x20, 0x27, 0x1D, 0x2A, 0x17, 0x0C, 0x01, 0x15, 0x19, 0x0D, 0x2C, 0x07, 0x37, 0x35, 0x05, 0x0A, 0x3D }, { 0x14, 0x25, 0x3A, 0x10, 0x1A, 0x20, 0x31, 0x09, 0x01, 0x0D, 0x36, 0x08, 0x15, 0x10, 0x27, 0x3C, 0x22, 0x1C, 0x05, 0x12, 0x19, 0x18, 0x17, 0x1B, 0x00, 0x03, 0x0D, 0x02, 0x16, 0x06, 0x34, 0x35, 0x23, 0x09, 0x01, 0x37, 0x1D, 0x27, 0x26, 0x20, 0x29, 0x04, 0x21, 0x24, 0x11, 0x3D, 0x0D, 0x07, 0x2C, 0x08, 0x39, 0x33, 0x07, 0x2A, 0x28, 0x2D, 0x0A, 0x0D, 0x32, 0x38, 0x13, 0x2B, 0x28, 0x0C }, { 0x18, 0x03, 0x1C, 0x28, 0x0D, 0x35, 0x01, 0x17, 0x10, 0x07, 0x2A, 0x01, 0x36, 0x37, 0x1A, 0x39, 0x25, 0x08, 0x12, 0x34, 0x0D, 0x2D, 0x06, 0x26, 0x27, 0x1B, 0x22, 0x19, 0x04, 0x0D, 0x3A, 0x21, 0x05, 0x0A, 0x07, 0x02, 0x13, 0x14, 0x00, 0x15, 0x0C, 0x10, 0x11, 0x09, 0x1D, 0x38, 0x3D, 0x24, 0x33, 0x20, 0x08, 0x16, 0x28, 0x2B, 0x20, 0x3C, 0x0D, 0x27, 0x23, 0x31, 0x29, 0x32, 0x2C, 0x09 } }; Ppu::Tiles::Tiles() : padding0(0), padding1(0) {} Ppu::Oam::Oam() : limit(buffer + STD_LINE_SPRITES*4), spriteLimit(true) {} Ppu::Output::Output(Video::Screen::Pixel* p) : pixels(p) {} Ppu::TileLut::TileLut() { for (uint i=0; i < 0x400; ++i) { block[i][0] = (i & 0xC0) ? (i >> 6 & 0xC) | (i >> 6 & 0x3) : 0; block[i][1] = (i & 0x30) ? (i >> 6 & 0xC) | (i >> 4 & 0x3) : 0; block[i][2] = (i & 0x0C) ? (i >> 6 & 0xC) | (i >> 2 & 0x3) : 0; block[i][3] = (i & 0x03) ? (i >> 6 & 0xC) | (i >> 0 & 0x3) : 0; } } Ppu::Ppu(Cpu& c) : cpu (c), output (screen.pixels), model (PPU_RP2C02), rgbMap (NULL), yuvMap (NULL) { cycles.one = PPU_RP2C02_CC; PowerOff(); } void Ppu::PowerOff() { Reset( true, false, false ); } void Ppu::Reset(bool hard,bool acknowledged) { Reset( hard, acknowledged, true ); } void Ppu::Reset(const bool hard,const bool acknowledged,const bool map) { if (map) { for (uint i=0x2000; i < 0x4000; i += 0x8) { cpu.Map( i+0 ).Set( this, i != 0x3000 ? &Ppu::Peek_2xxx : &Ppu::Peek_3000, &Ppu::Poke_2000 ); cpu.Map( i+1 ).Set( this, &Ppu::Peek_2xxx, &Ppu::Poke_2001 ); cpu.Map( i+2 ).Set( this, &Ppu::Peek_2002, &Ppu::Poke_2xxx ); cpu.Map( i+3 ).Set( this, &Ppu::Peek_2xxx, &Ppu::Poke_2003 ); cpu.Map( i+4 ).Set( this, &Ppu::Peek_2004, &Ppu::Poke_2004 ); cpu.Map( i+5 ).Set( this, &Ppu::Peek_2xxx, &Ppu::Poke_2005 ); cpu.Map( i+6 ).Set( this, &Ppu::Peek_2xxx, &Ppu::Poke_2006 ); cpu.Map( i+7 ).Set( this, &Ppu::Peek_2007, &Ppu::Poke_2007 ); } if (model == PPU_RC2C05_01 || model == PPU_RC2C05_04) { for (uint i=0x2002; i < 0x4000; i += 0x8) cpu.Map( i ).Set( &Ppu::Peek_2002_RC2C05_01_04 ); } else if (model == PPU_RC2C05_02) { for (uint i=0x2002; i < 0x4000; i += 0x8) cpu.Map( i ).Set( &Ppu::Peek_2002_RC2C05_02 ); } else if (model == PPU_RC2C05_03) { for (uint i=0x2002; i < 0x4000; i += 0x8) cpu.Map( i ).Set( &Ppu::Peek_2002_RC2C05_03 ); } else if (model == PPU_RC2C05_05) { for (uint i=0x2000; i < 0x4000; i += 0x8) { cpu.Map( i+0 ).Set( &Ppu::Poke_2001 ); cpu.Map( i+1 ).Set( &Ppu::Poke_2000 ); } } cpu.Map( 0x4014U ).Set( this, &Ppu::Peek_4014, &Ppu::Poke_4014 ); } if (hard) { static const byte powerUpPalette[] = { 0x09,0x01,0x00,0x01,0x00,0x02,0x02,0x0D, 0x08,0x10,0x08,0x24,0x00,0x00,0x04,0x2C, 0x09,0x01,0x34,0x03,0x00,0x04,0x00,0x14, 0x08,0x3A,0x00,0x02,0x00,0x20,0x2C,0x08 }; std::memcpy( palette.ram, powerUpPalette, Palette::SIZE ); std::memset( oam.ram, Oam::GARBAGE, Oam::SIZE ); std::memset( nameTable.ram, NameTable::GARBAGE, NameTable::SIZE ); io.latch = 0; io.buffer = Io::BUFFER_GARBAGE; regs.status = 0; regs.ctrl[0] = 0; regs.ctrl[1] = 0; regs.frame = 0; regs.oam = 0; scroll.latch = 0; scroll.xFine = 0; scroll.toggle = 0; scroll.address = 0; output.burstPhase = 0; cycles.reset = 0; cycles.hClock = HCLOCK_BOOT; } else if (acknowledged) { io.buffer = 0; regs.status = 0; regs.ctrl[0] = 0; regs.ctrl[1] = 0; scroll.latch = 0; scroll.xFine = 0; scroll.toggle = 0; cycles.reset = Cpu::CYCLE_MAX; cycles.hClock = HCLOCK_BOOT; std::memset( oam.ram, Oam::GARBAGE, Oam::SIZE ); } else { cycles.hClock = HCLOCK_DUMMY; cycles.reset = 0; } if (chr.Source().Empty()) { chr.Source().Set( Ram::RAM, true, false, NameTable::SIZE, nameTable.ram ); chr.SwapBanks(0,0,0,0); } if (nmt.Source().Empty()) { nmt.Source().Set( Ram::RAM, true, true, NameTable::SIZE, nameTable.ram ); nmt.SwapBanks(0,0); } chr.ResetAccessor(); nmt.ResetAccessors(); cycles.vClock = 0; cycles.count = Cpu::CYCLE_MAX; scanline = SCANLINE_VBLANK; scanline_sleep = 0; io.address = 0; io.pattern = 0; io.line.Unset(); tiles.pattern[0] = 0; tiles.pattern[1] = 0; tiles.attribute = 0; tiles.index = 8; tiles.mask = 0; oam.index = 0; oam.address = 0; oam.latch = 0; oam.spriteZeroInLine = false; oam.phase = &Ppu::EvaluateSpritesPhase0; oam.buffered = oam.buffer; oam.visible = oam.output; oam.mask = 0; output.target = NULL; hActiveHook.Unset(); hBlankHook.Unset(); UpdateStates(); screen.Clear(); } uint Ppu::SetAddressLineHook(const Core::Io::Line& line) { io.line = line; return io.address; } void Ppu::SetHActiveHook(const Hook& hook) { hActiveHook = hook; } void Ppu::SetHBlankHook(const Hook& hook) { hBlankHook = hook; } void Ppu::UpdateStates() { oam.height = (regs.ctrl[0] >> 2 & 8) + 8; tiles.show[0] = (regs.ctrl[1] & Regs::CTRL1_BG_ENABLED) ? 0xFF : 0x00; tiles.show[1] = (regs.ctrl[1] & Regs::CTRL1_BG_ENABLED_NO_CLIP) == Regs::CTRL1_BG_ENABLED_NO_CLIP ? 0xFF : 0x00; oam.show[0] = (regs.ctrl[1] & Regs::CTRL1_SP_ENABLED) ? 0xFF : 0x00; oam.show[1] = (regs.ctrl[1] & Regs::CTRL1_SP_ENABLED_NO_CLIP) == Regs::CTRL1_SP_ENABLED_NO_CLIP ? 0xFF : 0x00; UpdatePalette(); } void Ppu::UpdatePalette() { for (uint i=0, c=Coloring(), e=Emphasis(); i < Palette::SIZE; ++i) output.palette[i] = ((rgbMap ? rgbMap[palette.ram[i] & uint(Palette::COLOR)] : palette.ram[i]) & c) | e; } void Ppu::SaveState(State::Saver& state,const dword baseChunk) const { state.Begin( baseChunk ); { const byte data[11] = { regs.ctrl[0], regs.ctrl[1], regs.status, scroll.address & 0xFF, scroll.address >> 8, scroll.latch & 0xFF, scroll.latch >> 8, scroll.xFine | scroll.toggle << 3, regs.oam, io.buffer, io.latch }; state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End(); } state.Begin( AsciiId<'P','A','L'>::V ).Compress( palette.ram ).End(); state.Begin( AsciiId<'O','A','M'>::V ).Compress( oam.ram ).End(); state.Begin( AsciiId<'N','M','T'>::V ).Compress( nameTable.ram ).End(); if (model == PPU_RP2C02) state.Begin( AsciiId<'F','R','M'>::V ).Write8( (regs.frame & Regs::FRAME_ODD) == 0 ).End(); if (cycles.hClock == HCLOCK_BOOT) state.Begin( AsciiId<'P','O','W'>::V ).Write8( 0x0 ).End(); state.End(); } void Ppu::LoadState(State::Loader& state) { cycles.hClock = HCLOCK_DUMMY; regs.frame = 0; output.burstPhase = 0; while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: { State::Loader::Data<11> data( state ); regs.ctrl[0] = data[0]; regs.ctrl[1] = data[1]; regs.status = data[2] & Regs::STATUS_BITS; scroll.address = data[3] | (data[4] << 8 & 0x7F00); scroll.latch = data[5] | (data[6] << 8 & 0x7F00); scroll.xFine = data[7] & 0x7; scroll.toggle = data[7] >> 3 & 0x1; regs.oam = data[8]; io.buffer = data[9]; io.latch = data[10]; break; } case AsciiId<'P','A','L'>::V: state.Uncompress( palette.ram ); break; case AsciiId<'O','A','M'>::V: state.Uncompress( oam.ram ); break; case AsciiId<'N','M','T'>::V: state.Uncompress( nameTable.ram ); break; case AsciiId<'F','R','M'>::V: if (model == PPU_RP2C02) regs.frame = (state.Read8() & 0x1) ? 0 : Regs::FRAME_ODD; break; case AsciiId<'P','O','W'>::V: cycles.hClock = HCLOCK_BOOT; break; } state.End(); } UpdateStates(); } void Ppu::EnableCpuSynchronization() { cpu.AddHook( Hook(this,&Ppu::Hook_Sync) ); } void Ppu::ChrMem::ResetAccessor() { accessor.Set( this, &ChrMem::Access_Pattern ); } void Ppu::NmtMem::ResetAccessors() { accessors[0].Set( this, &NmtMem::Access_Name_2000 ); accessors[1].Set( this, &NmtMem::Access_Name_2400 ); accessors[2].Set( this, &NmtMem::Access_Name_2800 ); accessors[3].Set( this, &NmtMem::Access_Name_2C00 ); } void Ppu::SetModel(const PpuModel m,const bool yuvConversion) { if (model != m) { model = m; regs.frame = 0; output.burstPhase = 0; switch (model) { case PPU_RP2C07: cycles.one = PPU_RP2C07_CC; break; case PPU_DENDY: cycles.one = PPU_DENDY_CC; break; default: cycles.one = PPU_RP2C02_CC; break; } } const byte* const map = ( model == PPU_RP2C04_0001 ? yuvMaps[0] : model == PPU_RP2C04_0002 ? yuvMaps[1] : model == PPU_RP2C04_0003 ? yuvMaps[2] : model == PPU_RP2C04_0004 ? yuvMaps[3] : NULL ); const byte* const tmp[2] = { yuvConversion ? NULL : map, yuvConversion ? map : NULL }; if (yuvMap != tmp[0] || rgbMap != tmp[1]) { yuvMap = tmp[0]; rgbMap = tmp[1]; UpdatePalette(); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NST_FORCE_INLINE Cycle Ppu::GetCycles() const { return (cycles.vClock + cycles.hClock) * cycles.one; } NST_FORCE_INLINE Cycle Ppu::GetLocalCycles(Cycle clock) const { NST_COMPILE_ASSERT( PPU_DENDY_CC == PPU_RP2C02_CC || PPU_DENDY_CC == PPU_RP2C07_CC ); return cycles.one == PPU_RP2C02_CC ? clock / PPU_RP2C02_CC : (clock+PPU_RP2C07_CC-1) / PPU_RP2C07_CC; } void Ppu::BeginFrame(bool frameLock) { NST_ASSERT ( (scanline == SCANLINE_VBLANK) && (cycles.hClock == HCLOCK_BOOT || cycles.hClock == HCLOCK_DUMMY) && (cpu.GetModel() == CPU_RP2A07) == (model == PPU_RP2C07) && (cpu.GetModel() == CPU_DENDY) == (model == PPU_DENDY) ); oam.limit = oam.buffer + ((oam.spriteLimit || frameLock) ? Oam::STD_LINE_SPRITES*4 : Oam::MAX_LINE_SPRITES*4); output.target = output.pixels; Cycle frame; switch (model) { case PPU_RP2C02: regs.frame ^= Regs::FRAME_ODD; default: if (cycles.hClock == HCLOCK_DUMMY) { cycles.vClock = PPU_RP2C02_HVINT / PPU_RP2C02_CC - HCLOCK_DUMMY; cycles.count = PPU_RP2C02_HVINT; frame = PPU_RP2C02_HVSYNC_0; } else { cycles.vClock = PPU_RP2C02_HVSYNCBOOT / PPU_RP2C02_CC - HCLOCK_BOOT; cycles.count = PPU_RP2C02_HVSYNCBOOT; frame = PPU_RP2C02_HVSYNCBOOT; } break; case PPU_RP2C07: if (cycles.hClock == HCLOCK_DUMMY) { cycles.vClock = PPU_RP2C07_HVINT / PPU_RP2C07_CC - HCLOCK_DUMMY; cycles.count = PPU_RP2C07_HVINT; frame = PPU_RP2C07_HVSYNC; } else { cycles.vClock = PPU_RP2C07_HVSYNCBOOT / PPU_RP2C07_CC - HCLOCK_BOOT; cycles.count = PPU_RP2C07_HVSYNCBOOT; frame = PPU_RP2C07_HVSYNCBOOT; } break; case PPU_DENDY: if (cycles.hClock == HCLOCK_DUMMY) { cycles.vClock = PPU_DENDY_HVINT / PPU_DENDY_CC - HCLOCK_DUMMY; cycles.count = PPU_DENDY_HVINT; frame = PPU_DENDY_HVSYNC; } else { cycles.vClock = PPU_DENDY_HVSYNCBOOT / PPU_DENDY_CC - HCLOCK_BOOT; cycles.count = PPU_DENDY_HVSYNCBOOT; frame = PPU_DENDY_HVSYNCBOOT; } break; } cpu.SetFrameCycles( frame ); } NES_HOOK(Ppu,Sync) { const Cycle elapsed = cpu.GetCycles(); if (cycles.count < elapsed) { cycles.count = GetLocalCycles( elapsed ) - cycles.vClock; Run(); } } void Ppu::EndFrame() { if (cycles.count != Cpu::CYCLE_MAX) { cycles.count = Cpu::CYCLE_MAX; Run(); } } void Ppu::Update(Cycle dataSetup,const uint readAddress) { dataSetup += cpu.Update( readAddress ); if (cycles.count < dataSetup) { cycles.count = GetLocalCycles( dataSetup ) - cycles.vClock; Run(); } } void Ppu::SetMirroring(const byte (&banks)[4]) { Update( cycles.one ); NST_ASSERT( banks[0] < 4 && banks[1] < 4 && banks[2] < 4 && banks[3] < 4 ); nmt.SwapBanks( banks[0], banks[1], banks[2], banks[3] ); } void Ppu::SetMirroring(NmtMirroring mirroring) { Update( cycles.one ); nmt.SwapBanks ( uint(mirroring) >> 0 & 0x1U, uint(mirroring) >> 1 & 0x1U, uint(mirroring) >> 2 & 0x1U, uint(mirroring) >> 3 & 0x1U ); } NES_ACCESSOR(Ppu::ChrMem,Pattern) { return Peek( address ); } NES_ACCESSOR(Ppu::NmtMem,Name_2000) { return (*this)[0][address]; } NES_ACCESSOR(Ppu::NmtMem,Name_2400) { return (*this)[1][address]; } NES_ACCESSOR(Ppu::NmtMem,Name_2800) { return (*this)[2][address]; } NES_ACCESSOR(Ppu::NmtMem,Name_2C00) { return (*this)[3][address]; } NST_FORCE_INLINE uint Ppu::Chr::FetchPattern(uint address) const { return accessor.Fetch( address & 0x1FFF ); } NST_FORCE_INLINE uint Ppu::Nmt::FetchName(uint address) const { return accessors[address >> 10 & 0x3].Fetch( address & 0x3FF ); } NST_FORCE_INLINE uint Ppu::Nmt::FetchAttribute(uint address) const { return accessors[address >> 10 & 0x3].Fetch( 0x3C0 | (address & 0x03F) ); } NST_FORCE_INLINE void Ppu::UpdateAddressLine(uint address) { NST_ASSERT( address <= 0x3FFF ); io.address = address; if (io.line) io.line.Toggle( io.address, GetCycles() ); } NST_FORCE_INLINE void Ppu::UpdateScrollAddressLine() { if (io.line) io.line.Toggle( scroll.address & 0x3FFF, cpu.GetCycles() ); } NST_FORCE_INLINE void Ppu::UpdateVramAddress() { if ((scanline != SCANLINE_VBLANK ) && (regs.ctrl[1] & Regs::CTRL1_BG_SP_ENABLED)) { scroll.ClockX(); scroll.ClockY(); } else { scroll.address = (scroll.address + ((regs.ctrl[0] & Regs::CTRL0_INC32) ? 32 : 1)) & 0x7FFF; } } NST_FORCE_INLINE void Ppu::OpenName() { UpdateAddressLine( 0x2000 | (scroll.address & 0x0FFF) ); } NST_FORCE_INLINE void Ppu::FetchName() { io.pattern = nmt.FetchName( io.address ) << 4 | scroll.address >> 12 | (regs.ctrl[0] << 8 & 0x1000); } NST_FORCE_INLINE void Ppu::OpenAttribute() { UpdateAddressLine( 0x23C0 | (scroll.address & 0x0C00) | (scroll.address >> 4 & 0x0038) | (scroll.address >> 2 & 0x0007) ); } NST_FORCE_INLINE void Ppu::FetchAttribute() { tiles.attribute = nmt.FetchAttribute( io.address ) >> ((scroll.address & 0x2) | (scroll.address >> 4 & 0x4)); } NST_FORCE_INLINE void Ppu::OpenPattern(uint address) { UpdateAddressLine( address ); } NST_FORCE_INLINE uint Ppu::FetchSpPattern() const { return chr.FetchPattern( io.address ); } NST_FORCE_INLINE void Ppu::FetchBgPattern0() { const uint pattern = chr.FetchPattern( io.address ); tiles.pattern[1] = pattern >> 0 & 0x55; tiles.pattern[0] = pattern >> 1 & 0x55; } NST_FORCE_INLINE void Ppu::FetchBgPattern1() { const uint pattern = chr.FetchPattern( io.address ); tiles.pattern[0] |= pattern << 0 & 0xAA; tiles.pattern[1] |= pattern << 1 & 0xAA; } uint Ppu::GetPixelCycles() const { return (scanline+1)-1U < 240 ? scanline * 256 + NST_MIN(cycles.hClock,255) : ~0U; } NST_FORCE_INLINE bool Ppu::IsDead() const { return scanline == SCANLINE_VBLANK || !(regs.ctrl[1] & Regs::CTRL1_BG_SP_ENABLED); } NST_FORCE_INLINE uint Ppu::Coloring() const { return (regs.ctrl[1] & Regs::CTRL1_MONOCHROME) ? Palette::MONO : Palette::COLOR; } NST_FORCE_INLINE uint Ppu::Emphasis() const { return (regs.ctrl[1] & Regs::CTRL1_EMPHASIS) << 1; } NES_POKE_D(Ppu,2000) { Update( cycles.one ); NST_VERIFY( cpu.GetCycles() >= cycles.reset || !data ); if (cpu.GetCycles() >= cycles.reset) { scroll.latch = (scroll.latch & 0x73FF) | (data & 0x03) << 10; oam.height = (data >> 2 & 8) + 8; io.latch = data; data = regs.ctrl[0] ; regs.ctrl[0] = io.latch; if ((regs.ctrl[0] & regs.status & Regs::CTRL0_NMI) > data) { const Cycle clock = cpu.GetCycles() + cycles.one; if (clock < GetHVIntClock()) cpu.DoNMI( clock ); } } } NES_POKE_D(Ppu,2001) { Update( cycles.one ); NST_VERIFY( cpu.GetCycles() >= cycles.reset || !data ); if (cpu.GetCycles() >= cycles.reset) { if ((regs.ctrl[1] ^ data) & (Regs::CTRL1_BG_ENABLED_NO_CLIP|Regs::CTRL1_SP_ENABLED_NO_CLIP)) { tiles.show[0] = (data & Regs::CTRL1_BG_ENABLED) ? 0xFF : 0x00; tiles.show[1] = (data & Regs::CTRL1_BG_ENABLED_NO_CLIP) == Regs::CTRL1_BG_ENABLED_NO_CLIP ? 0xFF : 0x00; oam.show[0] = (data & Regs::CTRL1_SP_ENABLED) ? 0xFF : 0x00; oam.show[1] = (data & Regs::CTRL1_SP_ENABLED_NO_CLIP) == Regs::CTRL1_SP_ENABLED_NO_CLIP ? 0xFF : 0x00; const uint pos = (cycles.hClock - 8) >= (256-16); tiles.mask = tiles.show[pos]; oam.mask = oam.show[pos]; if ((regs.ctrl[1] & Regs::CTRL1_BG_SP_ENABLED) && !(data & Regs::CTRL1_BG_SP_ENABLED)) UpdateScrollAddressLine(); } io.latch = data; data = (regs.ctrl[1] ^ data) & (Regs::CTRL1_EMPHASIS|Regs::CTRL1_MONOCHROME); regs.ctrl[1] = io.latch; if (data) { const uint ce[] = { Coloring(), Emphasis() }; const byte* const NST_RESTRICT map = rgbMap; if (!map) { for (uint i=0; i < Palette::SIZE; ++i) output.palette[i] = (palette.ram[i] & ce[0]) | ce[1]; } else { for (uint i=0; i < Palette::SIZE; ++i) output.palette[i] = (map[palette.ram[i] & Palette::COLOR] & ce[0]) | ce[1]; } } } } NES_PEEK_A(Ppu,2002) { Update( cycles.one, address ); uint status = regs.status & 0xFF; regs.status &= (Regs::STATUS_VBLANK^0xFFU); scroll.toggle = 0; io.latch = (io.latch & Regs::STATUS_LATCH) | status; return io.latch; } NES_PEEK_A(Ppu,2002_RC2C05_01_04) { return (NES_DO_PEEK(2002,address) & 0xC0) | 0x1B; } NES_PEEK_A(Ppu,2002_RC2C05_02) { return (NES_DO_PEEK(2002,address) & 0xC0) | 0x3D; } NES_PEEK_A(Ppu,2002_RC2C05_03) { return (NES_DO_PEEK(2002,address) & 0xC0) | 0x1C; } NES_POKE_D(Ppu,2003) { Update( cycles.one ); regs.oam = data; io.latch = data; } NES_POKE_D(Ppu,2004) { Update( cycles.one ); NST_ASSERT( regs.oam < Oam::SIZE ); NST_VERIFY( IsDead() ); if (IsDead()) { if ((regs.oam & 0x03) == 0x02) data &= 0xE3; } else { data = 0xFF; } byte* const NST_RESTRICT value = oam.ram + regs.oam; regs.oam = (regs.oam + 1) & 0xFF; io.latch = data; *value = data; } NES_PEEK(Ppu,2004) { NST_ASSERT( regs.oam <= 0xFF ); if (!(regs.ctrl[1] & Regs::CTRL1_BG_SP_ENABLED) || cpu.GetCycles() - (cpu.GetFrameCycles() - (341 * 241) * cycles.one) >= (341 * 240) * cycles.one) { io.latch = oam.ram[regs.oam]; } else { Update( cycles.one ); io.latch = oam.latch; } return io.latch; } NES_POKE_D(Ppu,2005) { Update( cycles.one ); NST_VERIFY( cpu.GetCycles() >= cycles.reset || !data ); if (cpu.GetCycles() >= cycles.reset) { io.latch = data; if (scroll.toggle ^= 1) { scroll.latch = (scroll.latch & 0x7FE0) | (data >> 3); scroll.xFine = data & 0x7; } else { scroll.latch = (scroll.latch & 0x0C1F) | ((data << 2 | data << 12) & 0x73E0); } } } NES_POKE_D(Ppu,2006) { Update( cycles.one ); NST_VERIFY( cpu.GetCycles() >= cycles.reset || !data ); if (cpu.GetCycles() >= cycles.reset) { io.latch = data; if (scroll.toggle ^= 1) { scroll.latch = (scroll.latch & 0x00FF) | (data & 0x3F) << 8; } else { scroll.latch = (scroll.latch & 0x7F00) | data; scroll.address = scroll.latch; UpdateScrollAddressLine(); } } } NES_POKE_D(Ppu,2007) { Update( cycles.one * 4 ); uint address = scroll.address; UpdateVramAddress(); if (!(regs.ctrl[1] & Regs::CTRL1_BG_SP_ENABLED) || (scanline == SCANLINE_VBLANK)) UpdateAddressLine(scroll.address & 0x3fff); else return; io.latch = data; if ((address & 0x3F00) == 0x3F00) { address &= 0x1F; const uint final = ((!rgbMap ? data : rgbMap[data & Palette::COLOR]) & Coloring()) | Emphasis(); palette.ram[address] = data; output.palette[address] = final; if (!(address & 0x3)) { palette.ram[address ^ 0x10] = data; output.palette[address ^ 0x10] = final; } output.bgColor = palette.ram[0] & uint(Palette::COLOR); } else { address &= 0x3FFF; if (address >= 0x2000) nmt.Poke( address & 0xFFF, data ); else chr.Poke( address, data ); } } NES_PEEK_A(Ppu,2007) { Update( cycles.one, address ); address = scroll.address & 0x3FFF; UpdateVramAddress(); if (!(regs.ctrl[1] & Regs::CTRL1_BG_SP_ENABLED) || (scanline == SCANLINE_VBLANK)) UpdateAddressLine(scroll.address & 0x3fff); io.latch = (address & 0x3F00) != 0x3F00 ? io.buffer : palette.ram[address & 0x1F] & Coloring(); io.buffer = (address >= 0x2000 ? nmt.FetchName( address ) : chr.FetchPattern( address )); return io.latch; } NES_POKE_D(Ppu,2xxx) { io.latch = data; } NES_PEEK(Ppu,2xxx) { return io.latch; } NES_PEEK(Ppu,3000) { Update( cycles.one ); return io.latch; } NES_POKE_D(Ppu,4014) { if (cpu.IsOddCycle()) cpu.StealCycles( cpu.GetClock() ); Update( cycles.one ); cpu.StealCycles( cpu.GetClock() ); NST_ASSERT( regs.oam < 0x100 ); data <<= 8; if ((regs.oam == 0x00 && data < 0x2000) && (!(regs.ctrl[1] & Regs::CTRL1_BG_SP_ENABLED) || cpu.GetCycles() <= GetHVIntClock() - cpu.GetClock() * 512)) { cpu.StealCycles( cpu.GetClock() * 512 ); const byte* const NST_RESTRICT cpuRam = cpu.GetRam() + (data & (Cpu::RAM_SIZE-1)); byte* const NST_RESTRICT oamRam = oam.ram; for (uint i=0x00; i < 0x100; i += 0x4) { oamRam[i+0x0] = cpuRam[i+0x0]; oamRam[i+0x1] = cpuRam[i+0x1]; oamRam[i+0x2] = cpuRam[i+0x2] & 0xE3U; oamRam[i+0x3] = cpuRam[i+0x3]; } io.latch = oamRam[0xFF]; } else do { io.latch = cpu.Peek( data++ ); cpu.StealCycles( cpu.GetClock() ); Update( cycles.one ); cpu.StealCycles( cpu.GetClock() ); NST_VERIFY( IsDead() ); if (IsDead()) { if ((regs.oam & 0x03) == 0x02) io.latch &= 0xE3; } else { io.latch = 0xFF; } byte* const NST_RESTRICT out = oam.ram + regs.oam; regs.oam = (regs.oam + 1) & 0xFF; *out = io.latch; } while (data & 0xFF); } NES_PEEK(Ppu,4014) { return 0x40; } NST_FORCE_INLINE void Ppu::Scroll::ClockX() { if ((address & X_TILE) != X_TILE) address++; else address ^= (X_TILE|NAME_LOW); } NST_SINGLE_CALL void Ppu::Scroll::ResetX() { address = (address & ((X_TILE|NAME_LOW) ^ 0x7FFFU)) | (latch & (X_TILE|NAME_LOW)); } NST_SINGLE_CALL void Ppu::Scroll::ClockY() { if ((address & Y_FINE) != (7U << 12)) { address += (1U << 12); } else switch (address & Y_TILE) { default: address = (address & (Y_FINE ^ 0x7FFFU)) + (1U << 5); break; case (29U << 5): address ^= NAME_HIGH; case (31U << 5): address &= (Y_FINE|Y_TILE) ^ 0x7FFFU; break; } } NST_SINGLE_CALL void Ppu::PreLoadTiles() { const byte* const NST_RESTRICT src[] = { tileLut.block[tiles.pattern[0] | (tiles.attribute & 0x3U) << 8], tileLut.block[tiles.pattern[1] | (tiles.attribute & 0x3U) << 8] }; NST_ASSERT( tiles.index == 8 ); byte* const NST_RESTRICT dst = tiles.pixels; dst[0] = src[0][0]; dst[1] = src[1][0]; dst[2] = src[0][1]; dst[3] = src[1][1]; dst[4] = src[0][2]; dst[5] = src[1][2]; dst[6] = src[0][3]; dst[7] = src[1][3]; } NST_SINGLE_CALL void Ppu::LoadTiles() { const byte* const NST_RESTRICT src[] = { tileLut.block[tiles.pattern[0] | (tiles.attribute & 0x3U) << 8], tileLut.block[tiles.pattern[1] | (tiles.attribute & 0x3U) << 8] }; NST_ASSERT( tiles.index == 0 || tiles.index == 8 ); byte* const NST_RESTRICT dst = tiles.pixels + tiles.index; tiles.index ^= 8U; dst[0] = src[0][0]; dst[1] = src[1][0]; dst[2] = src[0][1]; dst[3] = src[1][1]; dst[4] = src[0][2]; dst[5] = src[1][2]; dst[6] = src[0][3]; dst[7] = src[1][3]; } NST_FORCE_INLINE void Ppu::EvaluateSpritesEven() { if (cycles.hClock >= 64) oam.latch = oam.ram[oam.address]; } NST_FORCE_INLINE void Ppu::EvaluateSpritesOdd() { (*this.*oam.phase)(); } void Ppu::EvaluateSpritesPhase0() { } void Ppu::EvaluateSpritesPhase1() { oam.index++; if (scanline - oam.latch >= oam.height) { if (oam.index != 64) { oam.address = (oam.index != 2 ? oam.address + 4 : 8); } else { oam.address = 0; oam.phase = &Ppu::EvaluateSpritesPhase9; } } else { oam.address++; oam.phase = &Ppu::EvaluateSpritesPhase2; oam.buffered[0] = oam.latch; } } void Ppu::EvaluateSpritesPhase2() { oam.address++; oam.phase = &Ppu::EvaluateSpritesPhase3; oam.buffered[1] = oam.latch; } void Ppu::EvaluateSpritesPhase3() { oam.address++; oam.phase = &Ppu::EvaluateSpritesPhase4; oam.buffered[2] = oam.latch; } void Ppu::EvaluateSpritesPhase4() { oam.buffered[3] = oam.latch; oam.buffered += 4; if (oam.index != 64) { oam.phase = (oam.buffered != oam.limit ? &Ppu::EvaluateSpritesPhase1 : &Ppu::EvaluateSpritesPhase5); if (oam.index != 2) { oam.address++; if (oam.index == 1) oam.spriteZeroInLine = true; } else { oam.address = 8; } } else { oam.address = 0; oam.phase = &Ppu::EvaluateSpritesPhase9; } } void Ppu::EvaluateSpritesPhase5() { if (scanline - oam.latch >= oam.height) { oam.address = ((oam.address + 4) & 0xFC) + ((oam.address + 1) & 0x03); if (oam.address <= 5) { oam.phase = &Ppu::EvaluateSpritesPhase9; oam.address &= 0xFC; } } else { oam.phase = &Ppu::EvaluateSpritesPhase6; oam.address = (oam.address + 1) & 0xFF; regs.status |= Regs::STATUS_SP_OVERFLOW; } } void Ppu::EvaluateSpritesPhase6() { oam.phase = &Ppu::EvaluateSpritesPhase7; oam.address = (oam.address + 1) & 0xFF; } void Ppu::EvaluateSpritesPhase7() { oam.phase = &Ppu::EvaluateSpritesPhase8; oam.address = (oam.address + 1) & 0xFF; } void Ppu::EvaluateSpritesPhase8() { oam.phase = &Ppu::EvaluateSpritesPhase9; oam.address = (oam.address + 1) & 0xFF; if ((oam.address & 0x3) == 0x3) oam.address++; oam.address &= 0xFC; } void Ppu::EvaluateSpritesPhase9() { oam.address = (oam.address + 4) & 0xFF; } NST_FORCE_INLINE uint Ppu::OpenSprite() const { return (regs.ctrl[0] & (Regs::CTRL0_SP_OFFSET|Regs::CTRL0_SP8X16)) ? 0x1FF0 : 0x0FF0; } NST_FORCE_INLINE uint Ppu::OpenSprite(const byte* const NST_RESTRICT buffer) const { uint address; const uint comparitor = (uint(scanline) - buffer[0]) ^ ((buffer[2] & uint(Oam::Y_FLIP)) ? 0xF : 0x0); if (regs.ctrl[0] & Regs::CTRL0_SP8X16) { address = ( ((buffer[1] & uint(Oam::TILE_LSB)) << 12) | ((buffer[1] & (Oam::TILE_LSB ^ 0xFFU)) << 4) | ((comparitor & Oam::RANGE_MSB) << 1) ); } else { address = (regs.ctrl[0] & Regs::CTRL0_SP_OFFSET) << 9 | buffer[1] << 4; } return address | (comparitor & Oam::XFINE); } NST_FORCE_INLINE void Ppu::LoadSprite(const uint pattern0,const uint pattern1,const byte* const NST_RESTRICT buffer) { if (pattern0 | pattern1) { uint a = (buffer[2] & uint(Oam::X_FLIP)) ? 7 : 0; uint p = ( (pattern0 >> 1 & 0x0055) | (pattern1 << 0 & 0x00AA) | (pattern0 << 8 & 0x5500) | (pattern1 << 9 & 0xAA00) ); Oam::Output* const NST_RESTRICT entry = oam.visible++; entry->pixels[( a^=6 )] = ( p ) & 0x3; entry->pixels[( a^=2 )] = ( p >>= 2 ) & 0x3; entry->pixels[( a^=6 )] = ( p >>= 2 ) & 0x3; entry->pixels[( a^=2 )] = ( p >>= 2 ) & 0x3; entry->pixels[( a^=7 )] = ( p >>= 2 ) & 0x3; entry->pixels[( a^=2 )] = ( p >>= 2 ) & 0x3; entry->pixels[( a^=6 )] = ( p >>= 2 ) & 0x3; entry->pixels[( a^=2 )] = ( p >>= 2 ); const uint attribute = buffer[2]; entry->x = buffer[3]; entry->palette = Palette::SPRITE_OFFSET + ((attribute & Oam::COLOR) << 2); entry->behind = (attribute & Oam::BEHIND) ? 0x3 : 0x0; entry->zero = (buffer == oam.buffer && oam.spriteZeroInLine) ? 0x3 : 0x0; } } void Ppu::LoadExtendedSprites() { const byte* NST_RESTRICT buffer = oam.buffer + (8*4); NST_ASSERT( buffer < oam.buffered ); do { const uint address = OpenSprite( buffer ); const uint patterns[2] = { chr.FetchPattern( address | 0x0 ), chr.FetchPattern( address | 0x8 ) }; LoadSprite( patterns[0], patterns[1], buffer ); buffer += 4; } while (buffer != oam.buffered); } NST_FORCE_INLINE void Ppu::RenderPixel() { uint clock; uint pixel = tiles.pixels[((clock=cycles.hClock++) + scroll.xFine) & 15] & tiles.mask; for (const Oam::Output* NST_RESTRICT sprite=oam.output, *const end=oam.visible; sprite != end; ++sprite) { uint x = clock - sprite->x; if (x > 7) continue; x = sprite->pixels[x] & oam.mask; if (x) { if (pixel & sprite->zero) regs.status |= Regs::STATUS_SP_ZERO_HIT; if (!(pixel & sprite->behind)) pixel = sprite->palette + x; break; } } Video::Screen::Pixel* const NST_RESTRICT target = output.target++; *target = output.palette[pixel]; } NST_SINGLE_CALL void Ppu::RenderPixel255() { cycles.hClock = 256; uint pixel = tiles.pixels[(255 + scroll.xFine) & 15] & tiles.mask; for (const Oam::Output* NST_RESTRICT sprite=oam.output, *const end=oam.visible; sprite != end; ++sprite) { uint x = 255U - sprite->x; if (x > 7) continue; x = sprite->pixels[x] & oam.mask; if (x) { if (!(pixel & sprite->behind)) pixel = sprite->palette + x; break; } } Video::Screen::Pixel* const NST_RESTRICT target = output.target++; *target = output.palette[pixel]; } NST_NO_INLINE void Ppu::Run() { NST_VERIFY( cycles.count != cycles.hClock ); if (scanline_sleep) // Extra lines between VBLANK and NMI in Dendy mode { switch (cycles.hClock) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58: case 59: case 60: case 61: case 62: case 63: case 64: case 65: case 66: case 67: case 68: case 69: case 70: case 71: case 72: case 73: case 74: case 75: case 76: case 77: case 78: case 79: case 80: case 81: case 82: case 83: case 84: case 85: case 86: case 87: case 88: case 89: case 90: case 91: case 92: case 93: case 94: case 95: case 96: case 97: case 98: case 99: case 100: case 101: case 102: case 103: case 104: case 105: case 106: case 107: case 108: case 109: case 110: case 111: case 112: case 113: case 114: case 115: case 116: case 117: case 118: case 119: case 120: case 121: case 122: case 123: case 124: case 125: case 126: case 127: case 128: case 129: case 130: case 131: case 132: case 133: case 134: case 135: case 136: case 137: case 138: case 139: case 140: case 141: case 142: case 143: case 144: case 145: case 146: case 147: case 148: case 149: case 150: case 151: case 152: case 153: case 154: case 155: case 156: case 157: case 158: case 159: case 160: case 161: case 162: case 163: case 164: case 165: case 166: case 167: case 168: case 169: case 170: case 171: case 172: case 173: case 174: case 175: case 176: case 177: case 178: case 179: case 180: case 181: case 182: case 183: case 184: case 185: case 186: case 187: case 188: case 189: case 190: case 191: case 192: case 193: case 194: case 195: case 196: case 197: case 198: case 199: case 200: case 201: case 202: case 203: case 204: case 205: case 206: case 207: case 208: case 209: case 210: case 211: case 212: case 213: case 214: case 215: case 216: case 217: case 218: case 219: case 220: case 221: case 222: case 223: case 224: case 225: case 226: case 227: case 228: case 229: case 230: case 231: case 232: case 233: case 234: case 235: case 236: case 237: case 238: case 239: case 240: case 241: case 242: case 243: case 244: case 245: case 246: case 247: case 248: case 249: case 250: case 251: case 252: case 253: case 254: case 255: case 256: case 257: case 258: case 260: case 261: case 262: case 263: case 264: case 266: case 267: case 268: case 269: case 270: case 271: case 272: case 273: case 274: case 275: case 276: case 277: case 278: case 279: case 280: case 281: case 282: case 283: case 284: case 285: case 286: case 287: case 288: case 289: case 290: case 291: case 292: case 293: case 294: case 295: case 296: case 297: case 298: case 299: case 300: case 301: case 302: case 303: case 304: case 305: case 306: case 307: case 308: case 309: case 310: case 311: case 312: case 313: case 314: case 315: case 316: case 317: case 318: case 319: case 320: case 321: case 322: case 323: case 324: case 325: case 326: case 327: case 328: case 329: case 330: case 331: case 332: case 333: case 334: case 335: case 336: case 337: HActiveSleep: cycles.hClock = 338; if (cycles.count <= 338) break; case 338: if (++scanline_sleep < PPU_DENDY_VSLEEP) { cycles.hClock = 0; cycles.vClock += HCLOCK_DUMMY; if (cycles.count <= HCLOCK_DUMMY) break; cycles.count -= HCLOCK_DUMMY; goto HActiveSleep; } else { cycles.hClock = HCLOCK_VBLANK_0; if (cycles.count <= HCLOCK_VBLANK_0) break; } case HCLOCK_VBLANK_0: goto VBlank0; case HCLOCK_VBLANK_1: goto VBlank1; case HCLOCK_VBLANK_2: goto VBlank2; } } else if (regs.ctrl[1] & Regs::CTRL1_BG_SP_ENABLED) { switch (cycles.hClock) { case 0: case 8: case 16: case 24: case 32: case 40: case 48: case 56: case 72: case 80: case 88: case 96: case 104: case 112: case 120: case 128: case 136: case 144: case 152: case 160: case 168: case 176: case 184: case 192: case 200: case 208: case 216: case 224: case 232: case 240: case 248: HActive: LoadTiles(); EvaluateSpritesEven(); OpenName(); RenderPixel(); if (cycles.count <= cycles.hClock) break; case 1: case 9: case 17: case 25: case 33: case 41: case 49: case 57: case 65: case 73: case 81: case 89: case 97: case 105: case 113: case 121: case 129: case 137: case 145: case 153: case 161: case 169: case 177: case 185: case 193: case 201: case 209: case 217: case 225: case 233: case 241: case 249: FetchName(); EvaluateSpritesOdd(); RenderPixel(); if (cycles.count <= cycles.hClock) break; case 2: case 10: case 18: case 26: case 34: case 42: case 50: case 58: case 66: case 74: case 82: case 90: case 98: case 106: case 114: case 122: case 130: case 138: case 146: case 154: case 162: case 170: case 178: case 186: case 194: case 202: case 210: case 218: case 226: case 234: case 242: case 250: EvaluateSpritesEven(); OpenAttribute(); RenderPixel(); if (cycles.count <= cycles.hClock) break; case 3: case 11: case 19: case 27: case 35: case 43: case 51: case 59: case 67: case 75: case 83: case 91: case 99: case 107: case 115: case 123: case 131: case 139: case 147: case 155: case 163: case 171: case 179: case 187: case 195: case 203: case 211: case 219: case 227: case 235: case 243: case 251: FetchAttribute(); EvaluateSpritesOdd(); if (cycles.hClock == 251) scroll.ClockY(); scroll.ClockX(); RenderPixel(); if (cycles.count <= cycles.hClock) break; case 4: case 12: case 20: case 28: case 36: case 44: case 52: case 60: case 68: case 76: case 84: case 92: case 100: case 108: case 116: case 124: case 132: case 140: case 148: case 156: case 164: case 172: case 180: case 188: case 196: case 204: case 212: case 220: case 228: case 236: case 244: case 252: EvaluateSpritesEven(); OpenPattern( io.pattern | 0x0 ); RenderPixel(); if (cycles.count <= cycles.hClock) break; case 5: case 13: case 21: case 29: case 37: case 45: case 53: case 61: case 69: case 77: case 85: case 93: case 101: case 109: case 117: case 125: case 133: case 141: case 149: case 157: case 165: case 173: case 181: case 189: case 197: case 205: case 213: case 221: case 229: case 237: case 245: case 253: FetchBgPattern0(); EvaluateSpritesOdd(); RenderPixel(); if (cycles.count <= cycles.hClock) break; case 6: case 14: case 22: case 30: case 38: case 46: case 54: case 62: case 70: case 78: case 86: case 94: case 102: case 110: case 118: case 126: case 134: case 142: case 150: case 158: case 166: case 174: case 182: case 190: case 198: case 206: case 214: case 222: case 230: case 238: case 246: case 254: EvaluateSpritesEven(); OpenPattern( io.pattern | 0x8 ); RenderPixel(); if (cycles.count <= cycles.hClock) break; if (cycles.hClock == 255) goto HActive255; case 7: case 15: case 23: case 31: case 39: case 47: case 55: case 63: case 71: case 79: case 87: case 95: case 103: case 111: case 119: case 127: case 135: case 143: case 151: case 159: case 167: case 175: case 183: case 191: case 199: case 207: case 215: case 223: case 231: case 239: case 247: FetchBgPattern1(); EvaluateSpritesOdd(); RenderPixel(); tiles.mask = tiles.show[0]; oam.mask = oam.show[0]; if (cycles.count <= cycles.hClock) break; if (cycles.hClock != 64) goto HActive; case 64: NST_VERIFY( regs.oam == 0 ); oam.address = regs.oam & Oam::OFFSET_TO_0_1; oam.phase = &Ppu::EvaluateSpritesPhase1; oam.latch = 0xFF; goto HActive; case 255: HActive255: FetchBgPattern1(); EvaluateSpritesOdd(); RenderPixel255(); if (cycles.count <= 256) break; case 256: OpenName(); oam.latch = 0xFF; cycles.hClock = 257; if (cycles.count <= 257) break; case 257: if (hBlankHook) hBlankHook.Execute(); scroll.ResetX(); oam.visible = oam.output; cycles.hClock = 258; if (cycles.count <= 258) break; case 258: case 266: case 274: case 282: case 290: case 298: case 306: case 314: HBlankSp: OpenName(); cycles.hClock += 2; if (cycles.count <= cycles.hClock) break; case 260: case 268: case 276: case 284: case 292: case 300: case 308: case 316: { const byte* const buffer = oam.buffer + ((cycles.hClock - 260) / 2); OpenPattern( buffer >= oam.buffered ? OpenSprite() : OpenSprite(buffer) ); if (scanline == 238 && cycles.hClock == 316) regs.oam = 0; if (cycles.count <= ++cycles.hClock) break; } case 261: case 269: case 277: case 285: case 293: case 301: case 309: case 317: if (oam.buffer + ((cycles.hClock - 261) / 2) < oam.buffered) io.pattern = FetchSpPattern(); if (cycles.count <= ++cycles.hClock) break; case 262: case 270: case 278: case 286: case 294: case 302: case 310: case 318: OpenPattern( io.address | 0x8 ); if (cycles.count <= ++cycles.hClock) break; case 263: case 271: case 279: case 287: case 295: case 303: case 311: case 319: { const byte* const buffer = oam.buffer + ((cycles.hClock - 263) / 2); if (buffer < oam.buffered) LoadSprite( io.pattern, FetchSpPattern(), buffer ); if (cycles.count <= ++cycles.hClock) break; if (cycles.hClock == 320) goto HBlankBg; } case 264: case 272: case 280: case 288: case 296: case 304: case 312: OpenName(); cycles.hClock += 2; if (cycles.count <= cycles.hClock) break; goto HBlankSp; case 320: HBlankBg: if (oam.buffer + (8*4) < oam.buffered) LoadExtendedSprites(); OpenName(); if (hActiveHook) hActiveHook.Execute(); oam.latch = oam.ram[0]; oam.buffered = oam.buffer; oam.spriteZeroInLine = false; oam.index = 0; oam.phase = &Ppu::EvaluateSpritesPhase0; cycles.hClock = 321; if (cycles.count <= 321) break; case 321: FetchName(); cycles.hClock = 322; if (cycles.count <= 322) break; case 322: OpenAttribute(); cycles.hClock = 323; if (cycles.count <= 323) break; case 323: FetchAttribute(); scroll.ClockX(); cycles.hClock = 324; if (cycles.count <= 324) break; case 324: OpenPattern( io.pattern | 0x0 ); cycles.hClock = 325; if (cycles.count <= 325) break; case 325: FetchBgPattern0(); cycles.hClock = 326; if (cycles.count <= 326) break; case 326: OpenPattern( io.pattern | 0x8 ); cycles.hClock = 327; if (cycles.count <= 327) break; case 327: FetchBgPattern1(); cycles.hClock = 328; if (cycles.count <= 328) break; case 328: PreLoadTiles(); OpenName(); cycles.hClock = 329; if (cycles.count <= 329) break; case 329: FetchName(); cycles.hClock = 330; if (cycles.count <= 330) break; case 330: OpenAttribute(); cycles.hClock = 331; if (cycles.count <= 331) break; case 331: FetchAttribute(); scroll.ClockX(); cycles.hClock = 332; if (cycles.count <= 332) break; case 332: OpenPattern( io.pattern | 0x0 ); cycles.hClock = 333; if (cycles.count <= 333) break; case 333: FetchBgPattern0(); cycles.hClock = 334; if (cycles.count <= 334) break; case 334: OpenPattern( io.pattern | 0x8 ); cycles.hClock = 335; if (cycles.count <= 335) break; case 335: FetchBgPattern1(); cycles.hClock = 336; if (cycles.count <= 336) break; case 336: OpenName(); cycles.hClock = 337; if (cycles.count <= 337) break; case 337: tiles.mask = tiles.show[1]; oam.mask = oam.show[1]; if (scanline == SCANLINE_HDUMMY && model == PPU_RP2C02) { if (regs.frame) { output.burstPhase = (output.burstPhase + 2) % 3; cpu.SetFrameCycles( PPU_RP2C02_HVSYNC_1 ); } else { output.burstPhase = (output.burstPhase + 1) % 3; } } cycles.hClock = 338; if (cycles.count <= 338) break; case 338: OpenName(); if (scanline++ != 239) { const uint line = (scanline != 0 || model != PPU_RP2C02 || !regs.frame ? HCLOCK_DUMMY : (HCLOCK_DUMMY - 1)); cycles.hClock = 0; cycles.vClock += line; if (cycles.count <= line) break; cycles.count -= line; goto HActive; } else { if (model == PPU_DENDY) { scanline_sleep = 1; cycles.hClock = 0; cycles.vClock += HCLOCK_DUMMY; if (cycles.count <= HCLOCK_DUMMY) break; cycles.count -= HCLOCK_DUMMY; goto HActiveSleep; } else { cycles.hClock = HCLOCK_VBLANK_0; if (cycles.count <= HCLOCK_VBLANK_0) break; } } case HCLOCK_VBLANK_0: VBlank0: regs.status |= Regs::STATUS_VBLANKING; cycles.hClock = HCLOCK_VBLANK_1; if (cycles.count <= HCLOCK_VBLANK_1) break; case HCLOCK_VBLANK_1: VBlank1: regs.status = (regs.status & 0xFF) | (regs.status >> 1 & Regs::STATUS_VBLANK); oam.visible = oam.output; cycles.hClock = HCLOCK_VBLANK_2; if (cycles.count <= HCLOCK_VBLANK_2) break; case HCLOCK_VBLANK_2: VBlank2: scanline_sleep = 0; cycles.hClock = HCLOCK_DUMMY; cycles.count = Cpu::CYCLE_MAX; cycles.reset = 0; if (regs.ctrl[0] & regs.status & Regs::CTRL0_NMI) cpu.DoNMI( cpu.GetFrameCycles() ); return; case HCLOCK_BOOT: goto Boot; case HCLOCK_DUMMY+0: regs.status = 0; scanline = SCANLINE_HDUMMY; case HCLOCK_DUMMY+8: case HCLOCK_DUMMY+16: case HCLOCK_DUMMY+24: case HCLOCK_DUMMY+32: case HCLOCK_DUMMY+40: case HCLOCK_DUMMY+48: case HCLOCK_DUMMY+56: case HCLOCK_DUMMY+64: case HCLOCK_DUMMY+72: case HCLOCK_DUMMY+80: case HCLOCK_DUMMY+88: case HCLOCK_DUMMY+96: case HCLOCK_DUMMY+104: case HCLOCK_DUMMY+112: case HCLOCK_DUMMY+120: case HCLOCK_DUMMY+128: case HCLOCK_DUMMY+136: case HCLOCK_DUMMY+144: case HCLOCK_DUMMY+152: case HCLOCK_DUMMY+160: case HCLOCK_DUMMY+168: case HCLOCK_DUMMY+176: case HCLOCK_DUMMY+184: case HCLOCK_DUMMY+192: case HCLOCK_DUMMY+200: case HCLOCK_DUMMY+208: case HCLOCK_DUMMY+216: case HCLOCK_DUMMY+224: case HCLOCK_DUMMY+232: case HCLOCK_DUMMY+240: case HCLOCK_DUMMY+248: HDummyBg: OpenName(); cycles.hClock += 2; if (cycles.count <= cycles.hClock) break; case HCLOCK_DUMMY+2: case HCLOCK_DUMMY+10: case HCLOCK_DUMMY+18: case HCLOCK_DUMMY+26: case HCLOCK_DUMMY+34: case HCLOCK_DUMMY+42: case HCLOCK_DUMMY+50: case HCLOCK_DUMMY+58: case HCLOCK_DUMMY+66: case HCLOCK_DUMMY+74: case HCLOCK_DUMMY+82: case HCLOCK_DUMMY+90: case HCLOCK_DUMMY+98: case HCLOCK_DUMMY+106: case HCLOCK_DUMMY+114: case HCLOCK_DUMMY+122: case HCLOCK_DUMMY+130: case HCLOCK_DUMMY+138: case HCLOCK_DUMMY+146: case HCLOCK_DUMMY+154: case HCLOCK_DUMMY+162: case HCLOCK_DUMMY+170: case HCLOCK_DUMMY+178: case HCLOCK_DUMMY+186: case HCLOCK_DUMMY+194: case HCLOCK_DUMMY+202: case HCLOCK_DUMMY+210: case HCLOCK_DUMMY+218: case HCLOCK_DUMMY+226: case HCLOCK_DUMMY+234: case HCLOCK_DUMMY+242: case HCLOCK_DUMMY+250: OpenAttribute(); cycles.hClock += 2; if (cycles.count <= cycles.hClock) break; case HCLOCK_DUMMY+4: case HCLOCK_DUMMY+12: case HCLOCK_DUMMY+20: case HCLOCK_DUMMY+28: case HCLOCK_DUMMY+36: case HCLOCK_DUMMY+44: case HCLOCK_DUMMY+52: case HCLOCK_DUMMY+60: case HCLOCK_DUMMY+68: case HCLOCK_DUMMY+76: case HCLOCK_DUMMY+84: case HCLOCK_DUMMY+92: case HCLOCK_DUMMY+100: case HCLOCK_DUMMY+108: case HCLOCK_DUMMY+116: case HCLOCK_DUMMY+124: case HCLOCK_DUMMY+132: case HCLOCK_DUMMY+140: case HCLOCK_DUMMY+148: case HCLOCK_DUMMY+156: case HCLOCK_DUMMY+164: case HCLOCK_DUMMY+172: case HCLOCK_DUMMY+180: case HCLOCK_DUMMY+188: case HCLOCK_DUMMY+196: case HCLOCK_DUMMY+204: case HCLOCK_DUMMY+212: case HCLOCK_DUMMY+220: case HCLOCK_DUMMY+228: case HCLOCK_DUMMY+236: case HCLOCK_DUMMY+244: case HCLOCK_DUMMY+252: OpenPattern( regs.ctrl[0] << 8 & 0x1000 ); cycles.hClock += 2; if (cycles.count <= cycles.hClock) break; case HCLOCK_DUMMY+6: case HCLOCK_DUMMY+14: case HCLOCK_DUMMY+22: case HCLOCK_DUMMY+30: case HCLOCK_DUMMY+38: case HCLOCK_DUMMY+46: case HCLOCK_DUMMY+54: case HCLOCK_DUMMY+62: case HCLOCK_DUMMY+70: case HCLOCK_DUMMY+78: case HCLOCK_DUMMY+86: case HCLOCK_DUMMY+94: case HCLOCK_DUMMY+102: case HCLOCK_DUMMY+110: case HCLOCK_DUMMY+118: case HCLOCK_DUMMY+126: case HCLOCK_DUMMY+134: case HCLOCK_DUMMY+142: case HCLOCK_DUMMY+150: case HCLOCK_DUMMY+158: case HCLOCK_DUMMY+166: case HCLOCK_DUMMY+174: case HCLOCK_DUMMY+182: case HCLOCK_DUMMY+190: case HCLOCK_DUMMY+198: case HCLOCK_DUMMY+206: case HCLOCK_DUMMY+214: case HCLOCK_DUMMY+222: case HCLOCK_DUMMY+230: case HCLOCK_DUMMY+238: case HCLOCK_DUMMY+246: case HCLOCK_DUMMY+254: OpenPattern( io.address | 0x8 ); cycles.hClock += 2; if (cycles.count <= cycles.hClock) break; if (cycles.hClock != HCLOCK_DUMMY+256) goto HDummyBg; case HCLOCK_DUMMY+256: case HCLOCK_DUMMY+264: case HCLOCK_DUMMY+272: case HCLOCK_DUMMY+280: case HCLOCK_DUMMY+288: case HCLOCK_DUMMY+296: case HCLOCK_DUMMY+312: HDummySp: OpenName(); cycles.hClock += 2; if (cycles.count <= cycles.hClock) break; case HCLOCK_DUMMY+258: case HCLOCK_DUMMY+266: case HCLOCK_DUMMY+274: case HCLOCK_DUMMY+282: case HCLOCK_DUMMY+290: case HCLOCK_DUMMY+298: case HCLOCK_DUMMY+306: case HCLOCK_DUMMY+314: OpenName(); cycles.hClock += 2; if (cycles.count <= cycles.hClock) break; case HCLOCK_DUMMY+260: case HCLOCK_DUMMY+268: case HCLOCK_DUMMY+276: case HCLOCK_DUMMY+284: case HCLOCK_DUMMY+292: case HCLOCK_DUMMY+300: case HCLOCK_DUMMY+308: case HCLOCK_DUMMY+316: OpenPattern( OpenSprite() ); cycles.hClock += 2; if (cycles.count <= cycles.hClock) break; case HCLOCK_DUMMY+262: case HCLOCK_DUMMY+270: case HCLOCK_DUMMY+278: case HCLOCK_DUMMY+286: case HCLOCK_DUMMY+294: case HCLOCK_DUMMY+302: case HCLOCK_DUMMY+310: case HCLOCK_DUMMY+318: OpenPattern( io.address | 0x8 ); if (cycles.hClock != HCLOCK_DUMMY+318) { cycles.hClock += 2; if (cycles.count <= cycles.hClock) break; if (cycles.hClock != HCLOCK_DUMMY+304) goto HDummySp; } else { cycles.hClock = 320; cycles.vClock += HCLOCK_DUMMY; cycles.count -= HCLOCK_DUMMY; if (cycles.count <= cycles.hClock) break; goto HBlankBg; } case HCLOCK_DUMMY+304: scroll.address = scroll.latch; goto HDummySp; default: NST_UNREACHABLE(); } } else { switch (cycles.hClock) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58: case 59: case 60: case 61: case 62: case 63: case 64: case 65: case 66: case 67: case 68: case 69: case 70: case 71: case 72: case 73: case 74: case 75: case 76: case 77: case 78: case 79: case 80: case 81: case 82: case 83: case 84: case 85: case 86: case 87: case 88: case 89: case 90: case 91: case 92: case 93: case 94: case 95: case 96: case 97: case 98: case 99: case 100: case 101: case 102: case 103: case 104: case 105: case 106: case 107: case 108: case 109: case 110: case 111: case 112: case 113: case 114: case 115: case 116: case 117: case 118: case 119: case 120: case 121: case 122: case 123: case 124: case 125: case 126: case 127: case 128: case 129: case 130: case 131: case 132: case 133: case 134: case 135: case 136: case 137: case 138: case 139: case 140: case 141: case 142: case 143: case 144: case 145: case 146: case 147: case 148: case 149: case 150: case 151: case 152: case 153: case 154: case 155: case 156: case 157: case 158: case 159: case 160: case 161: case 162: case 163: case 164: case 165: case 166: case 167: case 168: case 169: case 170: case 171: case 172: case 173: case 174: case 175: case 176: case 177: case 178: case 179: case 180: case 181: case 182: case 183: case 184: case 185: case 186: case 187: case 188: case 189: case 190: case 191: case 192: case 193: case 194: case 195: case 196: case 197: case 198: case 199: case 200: case 201: case 202: case 203: case 204: case 205: case 206: case 207: case 208: case 209: case 210: case 211: case 212: case 213: case 214: case 215: case 216: case 217: case 218: case 219: case 220: case 221: case 222: case 223: case 224: case 225: case 226: case 227: case 228: case 229: case 230: case 231: case 232: case 233: case 234: case 235: case 236: case 237: case 238: case 239: case 240: case 241: case 242: case 243: case 244: case 245: case 246: case 247: case 248: case 249: case 250: case 251: case 252: case 253: case 254: case 255: HActiveOff: { const uint pixel = output.palette[(scroll.address & 0x3F00) == 0x3F00 ? (scroll.address & 0x001F) : 0]; uint i = cycles.hClock; const uint hClock = NST_MIN(cycles.count,256); NST_ASSERT( i < hClock ); cycles.hClock = hClock; tiles.index = (hClock - 1) & 8; byte* const NST_RESTRICT tile = tiles.pixels; Video::Screen::Pixel* NST_RESTRICT target = output.target; do { tile[i++ & 15] = 0; *target++ = pixel; } while (i != hClock); output.target = target; if (cycles.count <= 256) break; } case 256: cycles.hClock = 257; if (cycles.count <= 257) break; case 257: if (hBlankHook) hBlankHook.Execute(); oam.visible = oam.output; cycles.hClock = 258; if (cycles.count <= 258) break; case 258: case 260: case 261: case 262: case 263: case 264: case 266: case 268: case 269: case 270: case 271: case 272: case 274: case 276: case 277: case 278: case 279: case 280: case 282: case 284: case 285: case 286: case 287: case 288: case 290: case 292: case 293: case 294: case 295: case 296: case 298: case 300: case 301: case 302: case 303: case 304: case 306: case 308: case 309: case 310: case 311: case 312: case 314: case 316: case 317: case 318: case 319: if (cycles.count <= 320) { cycles.hClock = cycles.count + ((cycles.count & 0x7) == 3 || (cycles.count & 0x7) == 1); break; } case 320: HBlankOff: cycles.hClock = 321; if (hActiveHook) hActiveHook.Execute(); oam.buffered = oam.buffer; oam.spriteZeroInLine = false; oam.index = 0; oam.phase = &Ppu::EvaluateSpritesPhase0; if (cycles.count <= 321) break; case 321: case 322: case 323: case 324: case 325: case 326: case 327: case 328: case 329: case 330: case 331: case 332: case 333: case 334: case 335: case 336: case 337: cycles.hClock = cycles.count; if (cycles.count <= 338) break; case 338: if (scanline++ != 239) { tiles.mask = tiles.show[1]; oam.mask = oam.show[1]; if (scanline == 0 && model == PPU_RP2C02) output.burstPhase = (output.burstPhase + 1) % 3; cycles.vClock += HCLOCK_DUMMY; cycles.hClock = 0; if (cycles.count <= HCLOCK_DUMMY) break; cycles.count -= HCLOCK_DUMMY; goto HActiveOff; } else { if (model == PPU_DENDY) { scanline_sleep = 1; cycles.vClock += HCLOCK_DUMMY; cycles.hClock = 0; if (cycles.count <= HCLOCK_DUMMY) break; cycles.count -= HCLOCK_DUMMY; goto HActiveSleep; } else { cycles.hClock = HCLOCK_VBLANK_0; if (cycles.count <= HCLOCK_VBLANK_0) break; } } case HCLOCK_VBLANK_0: goto VBlank0; case HCLOCK_VBLANK_1: goto VBlank1; case HCLOCK_VBLANK_2: goto VBlank2; case HCLOCK_BOOT: Boot: regs.status |= Regs::STATUS_VBLANK; cycles.hClock = HCLOCK_DUMMY; cycles.count = Cpu::CYCLE_MAX; if (cycles.reset) { switch (model) { case PPU_RP2C07: cycles.reset = PPU_RP2C07_HVREGBOOT - PPU_RP2C07_HVSYNCBOOT; break; case PPU_DENDY: cycles.reset = PPU_DENDY_HVREGBOOT - PPU_DENDY_HVSYNCBOOT; break; default: cycles.reset = PPU_RP2C02_HVREGBOOT - PPU_RP2C02_HVSYNCBOOT; break; } } return; case HCLOCK_DUMMY+0: regs.status = 0; scanline = SCANLINE_HDUMMY; case HCLOCK_DUMMY+2: case HCLOCK_DUMMY+4: case HCLOCK_DUMMY+6: case HCLOCK_DUMMY+8: case HCLOCK_DUMMY+10: case HCLOCK_DUMMY+12: case HCLOCK_DUMMY+14: case HCLOCK_DUMMY+16: case HCLOCK_DUMMY+18: case HCLOCK_DUMMY+20: case HCLOCK_DUMMY+22: case HCLOCK_DUMMY+24: case HCLOCK_DUMMY+26: case HCLOCK_DUMMY+28: case HCLOCK_DUMMY+30: case HCLOCK_DUMMY+32: case HCLOCK_DUMMY+34: case HCLOCK_DUMMY+36: case HCLOCK_DUMMY+38: case HCLOCK_DUMMY+40: case HCLOCK_DUMMY+42: case HCLOCK_DUMMY+44: case HCLOCK_DUMMY+46: case HCLOCK_DUMMY+48: case HCLOCK_DUMMY+50: case HCLOCK_DUMMY+52: case HCLOCK_DUMMY+54: case HCLOCK_DUMMY+56: case HCLOCK_DUMMY+58: case HCLOCK_DUMMY+60: case HCLOCK_DUMMY+62: case HCLOCK_DUMMY+64: case HCLOCK_DUMMY+66: case HCLOCK_DUMMY+68: case HCLOCK_DUMMY+70: case HCLOCK_DUMMY+72: case HCLOCK_DUMMY+74: case HCLOCK_DUMMY+76: case HCLOCK_DUMMY+78: case HCLOCK_DUMMY+80: case HCLOCK_DUMMY+82: case HCLOCK_DUMMY+84: case HCLOCK_DUMMY+86: case HCLOCK_DUMMY+88: case HCLOCK_DUMMY+90: case HCLOCK_DUMMY+92: case HCLOCK_DUMMY+94: case HCLOCK_DUMMY+96: case HCLOCK_DUMMY+98: case HCLOCK_DUMMY+100: case HCLOCK_DUMMY+102: case HCLOCK_DUMMY+104: case HCLOCK_DUMMY+106: case HCLOCK_DUMMY+108: case HCLOCK_DUMMY+110: case HCLOCK_DUMMY+112: case HCLOCK_DUMMY+114: case HCLOCK_DUMMY+116: case HCLOCK_DUMMY+118: case HCLOCK_DUMMY+120: case HCLOCK_DUMMY+122: case HCLOCK_DUMMY+124: case HCLOCK_DUMMY+126: case HCLOCK_DUMMY+128: case HCLOCK_DUMMY+130: case HCLOCK_DUMMY+132: case HCLOCK_DUMMY+134: case HCLOCK_DUMMY+136: case HCLOCK_DUMMY+138: case HCLOCK_DUMMY+140: case HCLOCK_DUMMY+142: case HCLOCK_DUMMY+144: case HCLOCK_DUMMY+146: case HCLOCK_DUMMY+148: case HCLOCK_DUMMY+150: case HCLOCK_DUMMY+152: case HCLOCK_DUMMY+154: case HCLOCK_DUMMY+156: case HCLOCK_DUMMY+158: case HCLOCK_DUMMY+160: case HCLOCK_DUMMY+162: case HCLOCK_DUMMY+164: case HCLOCK_DUMMY+166: case HCLOCK_DUMMY+168: case HCLOCK_DUMMY+170: case HCLOCK_DUMMY+172: case HCLOCK_DUMMY+174: case HCLOCK_DUMMY+176: case HCLOCK_DUMMY+178: case HCLOCK_DUMMY+180: case HCLOCK_DUMMY+182: case HCLOCK_DUMMY+184: case HCLOCK_DUMMY+186: case HCLOCK_DUMMY+188: case HCLOCK_DUMMY+190: case HCLOCK_DUMMY+192: case HCLOCK_DUMMY+194: case HCLOCK_DUMMY+196: case HCLOCK_DUMMY+198: case HCLOCK_DUMMY+200: case HCLOCK_DUMMY+202: case HCLOCK_DUMMY+204: case HCLOCK_DUMMY+206: case HCLOCK_DUMMY+208: case HCLOCK_DUMMY+210: case HCLOCK_DUMMY+212: case HCLOCK_DUMMY+214: case HCLOCK_DUMMY+216: case HCLOCK_DUMMY+218: case HCLOCK_DUMMY+220: case HCLOCK_DUMMY+222: case HCLOCK_DUMMY+224: case HCLOCK_DUMMY+226: case HCLOCK_DUMMY+228: case HCLOCK_DUMMY+230: case HCLOCK_DUMMY+232: case HCLOCK_DUMMY+234: case HCLOCK_DUMMY+236: case HCLOCK_DUMMY+238: case HCLOCK_DUMMY+240: case HCLOCK_DUMMY+242: case HCLOCK_DUMMY+244: case HCLOCK_DUMMY+246: case HCLOCK_DUMMY+248: case HCLOCK_DUMMY+250: case HCLOCK_DUMMY+252: case HCLOCK_DUMMY+254: case HCLOCK_DUMMY+256: case HCLOCK_DUMMY+258: case HCLOCK_DUMMY+260: case HCLOCK_DUMMY+262: case HCLOCK_DUMMY+264: case HCLOCK_DUMMY+266: case HCLOCK_DUMMY+268: case HCLOCK_DUMMY+270: case HCLOCK_DUMMY+272: case HCLOCK_DUMMY+274: case HCLOCK_DUMMY+276: case HCLOCK_DUMMY+278: case HCLOCK_DUMMY+280: case HCLOCK_DUMMY+282: case HCLOCK_DUMMY+284: case HCLOCK_DUMMY+286: case HCLOCK_DUMMY+288: case HCLOCK_DUMMY+290: case HCLOCK_DUMMY+292: case HCLOCK_DUMMY+294: case HCLOCK_DUMMY+296: case HCLOCK_DUMMY+298: case HCLOCK_DUMMY+300: case HCLOCK_DUMMY+302: case HCLOCK_DUMMY+304: case HCLOCK_DUMMY+306: case HCLOCK_DUMMY+308: case HCLOCK_DUMMY+310: case HCLOCK_DUMMY+312: case HCLOCK_DUMMY+314: case HCLOCK_DUMMY+316: { NST_COMPILE_ASSERT( HCLOCK_DUMMY & 1 ); cycles.hClock = cycles.count | 1; if (cycles.count <= HCLOCK_DUMMY+318) break; } case HCLOCK_DUMMY+318: cycles.hClock = 320; cycles.vClock += HCLOCK_DUMMY; cycles.count -= HCLOCK_DUMMY; if (cycles.count <= 320) break; goto HBlankOff; default: NST_UNREACHABLE(); } } cycles.count = GetCycles(); } } } nestopia-1.51.1/source/core/NstPpu.hpp000066400000000000000000000270441411157722000176220ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_PPU_H #define NST_PPU_H #ifndef NST_IO_PORT_H #include "NstIoPort.hpp" #endif #include "NstIoAccessor.hpp" #include "NstIoLine.hpp" #include "NstHook.hpp" #include "NstMemory.hpp" #include "NstVideoScreen.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class Ppu { public: explicit Ppu(Cpu&); void Reset(bool,bool); void PowerOff(); void BeginFrame(bool); void EndFrame(); enum { SCANLINE_HDUMMY = -1, SCANLINE_VBLANK = 240 }; enum NmtMirroring { NMT_H = 0xC, NMT_V = 0xA, NMT_0 = 0x0, NMT_1 = 0xF }; void SetModel(PpuModel,bool); void SetMirroring(NmtMirroring); void SetMirroring(const byte (&)[4]); uint SetAddressLineHook(const Core::Io::Line&); void SetHActiveHook(const Hook&); void SetHBlankHook(const Hook&); uint GetPixelCycles() const; void EnableCpuSynchronization(); void LoadState(State::Loader&); void SaveState(State::Saver&,dword) const; class ChrMem : public Memory { NES_DECL_ACCESSOR( Pattern ); protected: Io::Accessor accessor; public: void ResetAccessor(); template void SetAccessor(T t,U u) { accessor.Set( t, u ); } }; class NmtMem : public Memory { NES_DECL_ACCESSOR( Name_2000 ); NES_DECL_ACCESSOR( Name_2400 ); NES_DECL_ACCESSOR( Name_2800 ); NES_DECL_ACCESSOR( Name_2C00 ); protected: Io::Accessor accessors[4]; public: void ResetAccessors(); template void SetAccessors(T t,U u,V v,W w,X x) { accessors[0].Set( t, u ); accessors[1].Set( t, v ); accessors[2].Set( t, w ); accessors[3].Set( t, x ); } }; private: struct Chr : ChrMem { NST_FORCE_INLINE uint FetchPattern(uint) const; }; struct Nmt : NmtMem { NST_FORCE_INLINE uint FetchName(uint) const; NST_FORCE_INLINE uint FetchAttribute(uint) const; }; enum { HCLOCK_DUMMY = 341, HCLOCK_VBLANK_0 = 681, HCLOCK_VBLANK_1 = 682, HCLOCK_VBLANK_2 = 684, HCLOCK_BOOT = 685 }; NES_DECL_POKE( 2000 ); NES_DECL_PEEK( 2002 ); NES_DECL_PEEK( 2002_RC2C05_01_04 ); NES_DECL_PEEK( 2002_RC2C05_02 ); NES_DECL_PEEK( 2002_RC2C05_03 ); NES_DECL_POKE( 2001 ); NES_DECL_POKE( 2003 ); NES_DECL_PEEK( 2004 ); NES_DECL_POKE( 2004 ); NES_DECL_POKE( 2005 ); NES_DECL_POKE( 2006 ); NES_DECL_PEEK( 2007 ); NES_DECL_POKE( 2007 ); NES_DECL_PEEK( 2xxx ); NES_DECL_POKE( 2xxx ); NES_DECL_PEEK( 3000 ); NES_DECL_PEEK( 4014 ); NES_DECL_POKE( 4014 ); NES_DECL_HOOK( Sync ); NST_FORCE_INLINE Cycle GetCycles() const; NST_FORCE_INLINE Cycle GetLocalCycles(Cycle) const; NST_FORCE_INLINE bool IsDead() const; NST_FORCE_INLINE uint Coloring() const; NST_FORCE_INLINE uint Emphasis() const; NST_FORCE_INLINE void UpdateAddressLine(uint); NST_FORCE_INLINE void UpdateScrollAddressLine(); NST_FORCE_INLINE void UpdateVramAddress(); NST_FORCE_INLINE void OpenName(); NST_FORCE_INLINE void FetchName(); NST_FORCE_INLINE void OpenAttribute(); NST_FORCE_INLINE void FetchAttribute(); NST_FORCE_INLINE void OpenPattern(uint); NST_FORCE_INLINE uint FetchSpPattern() const; NST_FORCE_INLINE void FetchBgPattern0(); NST_FORCE_INLINE void FetchBgPattern1(); NST_FORCE_INLINE void EvaluateSpritesEven(); NST_FORCE_INLINE void EvaluateSpritesOdd(); void EvaluateSpritesPhase0(); void EvaluateSpritesPhase1(); void EvaluateSpritesPhase2(); void EvaluateSpritesPhase3(); void EvaluateSpritesPhase4(); void EvaluateSpritesPhase5(); void EvaluateSpritesPhase6(); void EvaluateSpritesPhase7(); void EvaluateSpritesPhase8(); void EvaluateSpritesPhase9(); void Reset(bool,bool,bool); void Update(Cycle,uint=0); void UpdateStates(); void UpdatePalette(); void LoadExtendedSprites(); NST_FORCE_INLINE uint OpenSprite() const; NST_FORCE_INLINE uint OpenSprite(const byte* NST_RESTRICT) const; NST_FORCE_INLINE void LoadSprite(uint,uint,const byte* NST_RESTRICT); NST_SINGLE_CALL void PreLoadTiles(); NST_SINGLE_CALL void LoadTiles(); NST_FORCE_INLINE void RenderPixel(); NST_SINGLE_CALL void RenderPixel255(); NST_NO_INLINE void Run(); struct Regs { enum { CTRL0_NAME_OFFSET = 0x03, CTRL0_INC32 = 0x04, CTRL0_SP_OFFSET = 0x08, CTRL0_BG_OFFSET = 0x10, CTRL0_SP8X16 = 0x20, CTRL0_NMI = 0x80, CTRL0_NMI_OCCUR = 0x100, CTRL1_MONOCHROME = 0x01, CTRL1_BG_NO_CLIP = 0x02, CTRL1_SP_NO_CLIP = 0x04, CTRL1_BG_ENABLED = 0x08, CTRL1_SP_ENABLED = 0x10, CTRL1_BG_ENABLED_NO_CLIP = CTRL1_BG_ENABLED|CTRL1_BG_NO_CLIP, CTRL1_SP_ENABLED_NO_CLIP = CTRL1_SP_ENABLED|CTRL1_SP_NO_CLIP, CTRL1_BG_SP_ENABLED = CTRL1_BG_ENABLED|CTRL1_SP_ENABLED, CTRL1_EMPHASIS = 0xE0, STATUS_LATCH = 0x1F, STATUS_SP_OVERFLOW = 0x20, STATUS_SP_ZERO_HIT = 0x40, STATUS_VBLANK = 0x80, STATUS_BITS = STATUS_SP_OVERFLOW|STATUS_SP_ZERO_HIT|STATUS_VBLANK, STATUS_VBLANKING = 0x100, FRAME_ODD = CTRL1_BG_ENABLED|CTRL1_SP_ENABLED }; uint ctrl[2]; uint status; uint frame; uint oam; }; struct Scroll { enum { X_TILE = 0x001F, Y_TILE = 0x03E0, Y_FINE = 0x7000, LOW = 0x00FF, HIGH = 0xFF00, NAME = 0x0C00, NAME_LOW = 0x0400, NAME_HIGH = 0x0800 }; NST_FORCE_INLINE void ClockX(); NST_SINGLE_CALL void ResetX(); NST_SINGLE_CALL void ClockY(); uint address; uint toggle; uint latch; uint xFine; }; struct Tiles { Tiles(); byte pattern[2]; byte attribute; byte index; byte pixels[16]; uint mask; byte show[2]; const byte padding0; const byte padding1; }; struct Palette { enum { SIZE = 0x20, COLORS = 0x40, SPRITE_OFFSET = 0x10, COLOR = 0x3F, MONO = 0x30 }; byte ram[SIZE]; }; struct Output { explicit Output(Video::Screen::Pixel*); Video::Screen::Pixel* target; Video::Screen::Pixel* pixels; uint burstPhase; word palette[Palette::SIZE]; uint bgColor; }; struct Oam { Oam(); enum { SIZE = 0x100, OFFSET_TO_0_1 = 0xF8, STD_LINE_SPRITES = 8, MAX_LINE_SPRITES = 32, GARBAGE = 0xFF, COLOR = 0x03, BEHIND = 0x20, X_FLIP = 0x40, Y_FLIP = 0x80, XFINE = 0x07, RANGE_MSB = 0x08, TILE_LSB = 0x01 }; struct Output { byte x; byte behind; byte zero; byte palette; byte pixels[8]; }; typedef void (Ppu::*Phase)(); const byte* limit; Output* visible; Phase phase; uint latch; uint index; byte* buffered; uint address; uint height; uint mask; byte show[2]; bool spriteZeroInLine; bool spriteLimit; byte ram[0x100]; byte buffer[MAX_LINE_SPRITES*4]; Output output[MAX_LINE_SPRITES]; }; struct NameTable { enum { SIZE = SIZE_2K, GARBAGE = 0xFF }; byte ram[SIZE]; }; struct TileLut { TileLut(); byte block[0x400][4]; }; struct Io { enum { BUFFER_GARBAGE = 0xE8 }; uint address; uint pattern; uint latch; uint buffer; Core::Io::Line line; }; Cpu& cpu; struct { Cycle count; Cycle hClock; Cycle vClock; uint one; Cycle reset; } cycles; Io io; Regs regs; Scroll scroll; Tiles tiles; Chr chr; Nmt nmt; int scanline; int scanline_sleep; public: Output output; private: PpuModel model; Hook hActiveHook; Hook hBlankHook; const byte* rgbMap; const byte* yuvMap; Oam oam; Palette palette; NameTable nameTable; const TileLut tileLut; Video::Screen screen; static const byte yuvMaps[4][0x40]; public: void Update() { Update(0); } PpuModel GetModel() const { return model; } ibool IsEnabled() const { return regs.ctrl[1] & Regs::CTRL1_BG_SP_ENABLED; } int GetScanline() const { return scanline; } uint GetCtrl(uint i) const { NST_ASSERT( i < 2 ); return regs.ctrl[i]; } Video::Screen& GetScreen() { return screen; } Video::Screen::Pixel* GetOutputPixels() { return output.pixels; } void SetOutputPixels(Video::Screen::Pixel* pixels) { NST_ASSERT( pixels ); output.pixels = pixels; } const Palette& GetPalette() const { return palette; } uint GetPixel(uint i) const { NST_ASSERT( i < Video::Screen::PIXELS ); return output.pixels[i]; } uint GetYuvColor(uint i) const { NST_ASSERT( i < Palette::COLORS ); return yuvMap ? yuvMap[i] : i; } ChrMem& GetChrMem() { return chr; } NmtMem& GetNmtMem() { return nmt; } Cycle GetClock(dword count=1) const { NST_ASSERT( count ); return cycles.one * count; } Cycle GetHSyncClock() const { return model == PPU_RP2C07 ? PPU_RP2C07_HSYNC : model == PPU_DENDY ? PPU_DENDY_HSYNC : PPU_RP2C02_HSYNC; } Cycle GetHVIntClock() const { return model == PPU_RP2C07 ? PPU_RP2C07_HVINT : model == PPU_DENDY ? PPU_DENDY_HVINT : PPU_RP2C02_HVINT; } const Core::Io::Line& GetAddressLineHook() const { return io.line; } bool IsShortFrame() const { return regs.ctrl[1] & regs.frame; } uint GetBurstPhase() const { return output.burstPhase; } void EnableSpriteLimit(bool enable) { oam.spriteLimit = enable; } bool HasSpriteLimit() const { return oam.spriteLimit; } }; } } #endif nestopia-1.51.1/source/core/NstProperties.cpp000066400000000000000000000062431411157722000212030ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include "NstAssert.hpp" #include "NstProperties.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif struct Properties::Container { typedef std::map Map; Map map; }; Properties::Properties(const Properties& properties) : container(properties.container ? new Container(*properties.container) : NULL) {} Properties::~Properties() { Clear(); } Properties& Properties::operator = (const Properties& properties) { if (this != &properties) { Clear(); if (properties.container) container = new Container(*properties.container); } return *this; } bool Properties::operator ! () const { return container == NULL || container->map.empty(); } void Properties::Clear() { if (Container* tmp = container) { container = NULL; delete tmp; } } void Properties::Proxy::operator = (wcstring function) { NST_ASSERT( function ); if (container == NULL) container = new Container; container->map[id] = function; } wcstring Properties::Find(const Container* container,uint id) { if (container) { Container::Map::const_iterator it(container->map.find(id)); if (it != container->map.end()) return it->second.c_str(); } return L""; } bool Properties::Proxy::operator == (wcstring string) const { return Core::StringCompare( Find(container,id), string ) == 0; } wcstring Properties::Proxy::operator * () const { return Find(container,id); } Properties::ConstProxy::ConstProxy(const Container* container,uint id) : function(Find(container,id)) {} Properties::ConstProxy::ConstProxy(Proxy proxy) : function(Find(proxy.container,proxy.id)) {} bool Properties::ConstProxy::operator == (wcstring string) const { return Core::StringCompare( function, string ) == 0; } wcstring Properties::ConstProxy::operator * () const { return function; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } nestopia-1.51.1/source/core/NstProperties.hpp000066400000000000000000000050541411157722000212070ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_PROPERTIES_H #define NST_PROPERTIES_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class Properties : public ImplicitBool { public: Properties(const Properties&); ~Properties(); Properties& operator = (const Properties&); bool operator ! () const; void Clear(); protected: struct Container; static wcstring Find(const Container*,uint); Container* container; public: class ConstProxy; class Proxy { protected: friend class Properties; friend class ConstProxy; Container*& container; const uint id; Proxy(Container*& c,uint i) : container(c), id(i) {} public: bool operator == (wcstring) const; void operator = (wcstring); wcstring operator * () const; bool operator != (wcstring s) const { return !(*this == s); } }; class ConstProxy { protected: friend class Properties; wcstring const function; ConstProxy(const Container*,uint); public: ConstProxy(Proxy); bool operator == (wcstring) const; wcstring operator * () const; bool operator != (wcstring s) const { return !(*this == s); } }; Properties() : container(NULL) {} Proxy operator [] (uint i) { return Proxy( container, i ); } ConstProxy operator [] (uint i) const { return ConstProxy( container, i ); } }; } } #endif nestopia-1.51.1/source/core/NstRam.cpp000066400000000000000000000110561411157722000175640ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include "NstAssert.hpp" #include "NstRam.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Ram::Ram() : mem ( NULL ), mask ( 0 ), size ( 0 ), type ( RAM ), readable ( false ), writable ( false ), internal ( false ) {} Ram::Ram(Type t,bool r,bool w,dword s,byte* m) : mem ( NULL ), mask ( 0 ), size ( 0 ), type ( t ), readable ( r ), writable ( w ), internal ( false ) { Set( s, m ); } Ram::Ram(const Ram& ram) : mem ( ram.mem ), mask ( ram.mask ), size ( ram.size ), type ( ram.type ), readable ( ram.readable ), writable ( ram.writable ), internal ( false ), pins ( ram.pins ) {} Ram::~Ram() { if (internal) std::free( mem ); } Ram& Ram::operator = (const Ram& ram) { if (this != &ram) { Destroy(); mem = ram.mem; mask = ram.mask; size = ram.size; type = ram.type; readable = ram.readable; writable = ram.writable; internal = false; pins = ram.pins; } return *this; } void Ram::Destroy() { pins.Clear(); mask = 0; size = 0; if (byte* const tmp = mem) { mem = NULL; if (internal) { internal = false; std::free( tmp ); } } } void Ram::Set(dword s,byte* m) { if (s) { dword prev = mask+1; mask = s - 1; mask |= mask >> 1; mask |= mask >> 2; mask |= mask >> 4; mask |= mask >> 8; mask |= mask >> 16; size = s; NST_VERIFY( s == mask+1 ); if (m) { if (internal) { internal = false; std::free( mem ); } } else { m = static_cast(std::realloc( internal ? mem : NULL, mask+1 )); if (m) { if (!internal) { internal = true; prev = 0; } if (prev < mask+1) std::memset( m+prev, 0, mask+1-prev ); } else { Destroy(); throw RESULT_ERR_OUT_OF_MEMORY; } } mem = m; } else { Destroy(); } } void Ram::Set(Type t,bool r,bool w,dword s,byte* m) { Set( s, m ); type = t; readable = r; writable = w; } void Ram::Fill(uint value) const { NST_ASSERT( bool(mem) == bool(size) ); NST_VERIFY( value <= 0xFF ); std::memset( mem, value & 0xFF, size ); } void Ram::Mirror(dword block) { NST_VERIFY( block ); if (block) { const dword nearest = mask+1; if (internal || !size) { block--; block |= block >> 1; block |= block >> 2; block |= block >> 4; block |= block >> 8; block |= block >> 16; block++; if (mask+1 < block) { const dword tmp = size; Set( block ); size = tmp; } } NST_ASSERT( nearest <= mask+1 && !((mask+1) & mask) && !(nearest & (nearest-1)) ); if (size) { for (block=nearest; size % block; ) block /= 2; for (dword i=size, n=size-block; i != nearest; i += block) std::memcpy( mem + i, mem + n, block ); for (dword i=nearest, n=mask+1; i != n; i += nearest) std::memcpy( mem + i, mem, nearest ); } } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } nestopia-1.51.1/source/core/NstRam.hpp000066400000000000000000000054001411157722000175650ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_RAM_H #define NST_RAM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstPins.hpp" namespace Nes { namespace Core { class Ram { public: enum Type { RAM, NVRAM, ROM }; Ram(); Ram(const Ram&); Ram(Type,bool,bool,dword,byte* = NULL); ~Ram(); void Set(dword,byte* = NULL); void Set(Type,bool,bool,dword,byte* = NULL); void Destroy(); void Fill(uint) const; void Mirror(dword); Ram& operator = (const Ram&); private: byte* mem; dword mask; dword size; byte type; bool readable; bool writable; bool internal; Pins pins; public: dword Size() const { return size; } dword Masking() const { return mask; } bool Empty() const { return size == 0; } bool Readable() const { return readable; } bool Writable() const { return writable; } bool Internal() const { return internal; } Type GetType() const { return static_cast(type); } void ReadEnable(bool r) { readable = r; } void WriteEnable(bool w) { writable = w; } void SetSecurity(bool r,bool w) { readable = r; writable = w; } void SetType(Type t) { type = t; } byte* Mem(dword offset=0) const { return mem + (offset & mask); } byte& operator [] (dword i) const { return mem[i]; } Pins::PinsProxy Pin(uint i) { return pins[i]; } Pins::ConstPinsProxy Pin(uint i) const { return pins[i]; } bool PinsDefined() const { return pins; } }; } } #endif nestopia-1.51.1/source/core/NstSha1.cpp000066400000000000000000000163631411157722000176470ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// // // Based on public domain code written by Steve Reid // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstAssert.hpp" #include "NstSha1.hpp" namespace Nes { namespace Core { namespace Sha1 { #define NST_ROL(v,b) (((v) << (b) & 0xFFFFFFFF) | ((v) >> (32 - (b)))) #define NST_BLK(p,i) (p[i&15U] = NST_ROL(p[(i+13)&15U] ^ p[(i+8)&15U] ^ p[(i+2)&15U] ^ p[i&15U],1)) #define NST_R0(p,v,w,x,y,z,i) z = (z + ((w & (x ^ y)) ^ y) + p[i] + 0x5A827999 + NST_ROL(v,5)) & 0xFFFFFFFF; w = NST_ROL(w,30) #define NST_R1(p,v,w,x,y,z,i) z = (z + ((w & (x ^ y)) ^ y) + NST_BLK(p,i) + 0x5A827999 + NST_ROL(v,5)) & 0xFFFFFFFF; w = NST_ROL(w,30) #define NST_R2(p,v,w,x,y,z,i) z = (z + (w ^ x ^ y) + NST_BLK(p,i) + 0x6ED9EBA1 + NST_ROL(v,5)) & 0xFFFFFFFF; w = NST_ROL(w,30) #define NST_R3(p,v,w,x,y,z,i) z = (z + (((w | x) & y) | (w & x)) + NST_BLK(p,i) + 0x8F1BBCDC + NST_ROL(v,5)) & 0xFFFFFFFF; w = NST_ROL(w,30) #define NST_R4(p,v,w,x,y,z,i) z = (z + (w ^ x ^ y) + NST_BLK(p,i) + 0xCA62C1D6 + NST_ROL(v,5)) & 0xFFFFFFFF; w = NST_ROL(w,30) static void Transform(dword* const NST_RESTRICT state,const byte* const NST_RESTRICT buffer) { dword p[16]; for (uint i=0; i < 16; ++i) p[i] = dword(buffer[i*4+0]) << 24 | dword(buffer[i*4+1]) << 16 | uint(buffer[i*4+2]) << 8 | buffer[i*4+3]; dword a = state[0]; dword b = state[1]; dword c = state[2]; dword d = state[3]; dword e = state[4]; NST_R0(p,a,b,c,d,e, 0); NST_R0(p,e,a,b,c,d, 1); NST_R0(p,d,e,a,b,c, 2); NST_R0(p,c,d,e,a,b, 3); NST_R0(p,b,c,d,e,a, 4); NST_R0(p,a,b,c,d,e, 5); NST_R0(p,e,a,b,c,d, 6); NST_R0(p,d,e,a,b,c, 7); NST_R0(p,c,d,e,a,b, 8); NST_R0(p,b,c,d,e,a, 9); NST_R0(p,a,b,c,d,e,10); NST_R0(p,e,a,b,c,d,11); NST_R0(p,d,e,a,b,c,12); NST_R0(p,c,d,e,a,b,13); NST_R0(p,b,c,d,e,a,14); NST_R0(p,a,b,c,d,e,15); NST_R1(p,e,a,b,c,d,16); NST_R1(p,d,e,a,b,c,17); NST_R1(p,c,d,e,a,b,18); NST_R1(p,b,c,d,e,a,19); NST_R2(p,a,b,c,d,e,20); NST_R2(p,e,a,b,c,d,21); NST_R2(p,d,e,a,b,c,22); NST_R2(p,c,d,e,a,b,23); NST_R2(p,b,c,d,e,a,24); NST_R2(p,a,b,c,d,e,25); NST_R2(p,e,a,b,c,d,26); NST_R2(p,d,e,a,b,c,27); NST_R2(p,c,d,e,a,b,28); NST_R2(p,b,c,d,e,a,29); NST_R2(p,a,b,c,d,e,30); NST_R2(p,e,a,b,c,d,31); NST_R2(p,d,e,a,b,c,32); NST_R2(p,c,d,e,a,b,33); NST_R2(p,b,c,d,e,a,34); NST_R2(p,a,b,c,d,e,35); NST_R2(p,e,a,b,c,d,36); NST_R2(p,d,e,a,b,c,37); NST_R2(p,c,d,e,a,b,38); NST_R2(p,b,c,d,e,a,39); NST_R3(p,a,b,c,d,e,40); NST_R3(p,e,a,b,c,d,41); NST_R3(p,d,e,a,b,c,42); NST_R3(p,c,d,e,a,b,43); NST_R3(p,b,c,d,e,a,44); NST_R3(p,a,b,c,d,e,45); NST_R3(p,e,a,b,c,d,46); NST_R3(p,d,e,a,b,c,47); NST_R3(p,c,d,e,a,b,48); NST_R3(p,b,c,d,e,a,49); NST_R3(p,a,b,c,d,e,50); NST_R3(p,e,a,b,c,d,51); NST_R3(p,d,e,a,b,c,52); NST_R3(p,c,d,e,a,b,53); NST_R3(p,b,c,d,e,a,54); NST_R3(p,a,b,c,d,e,55); NST_R3(p,e,a,b,c,d,56); NST_R3(p,d,e,a,b,c,57); NST_R3(p,c,d,e,a,b,58); NST_R3(p,b,c,d,e,a,59); NST_R4(p,a,b,c,d,e,60); NST_R4(p,e,a,b,c,d,61); NST_R4(p,d,e,a,b,c,62); NST_R4(p,c,d,e,a,b,63); NST_R4(p,b,c,d,e,a,64); NST_R4(p,a,b,c,d,e,65); NST_R4(p,e,a,b,c,d,66); NST_R4(p,d,e,a,b,c,67); NST_R4(p,c,d,e,a,b,68); NST_R4(p,b,c,d,e,a,69); NST_R4(p,a,b,c,d,e,70); NST_R4(p,e,a,b,c,d,71); NST_R4(p,d,e,a,b,c,72); NST_R4(p,c,d,e,a,b,73); NST_R4(p,b,c,d,e,a,74); NST_R4(p,a,b,c,d,e,75); NST_R4(p,e,a,b,c,d,76); NST_R4(p,d,e,a,b,c,77); NST_R4(p,c,d,e,a,b,78); NST_R4(p,b,c,d,e,a,79); state[0] = (state[0] + a) & 0xFFFFFFFF; state[1] = (state[1] + b) & 0xFFFFFFFF; state[2] = (state[2] + c) & 0xFFFFFFFF; state[3] = (state[3] + d) & 0xFFFFFFFF; state[4] = (state[4] + e) & 0xFFFFFFFF; } #undef NST_ROL #undef NST_BLK #undef NST_R0 #undef NST_R1 #undef NST_R2 #undef NST_R3 #undef NST_R4 void NST_CALL Compute(Key& key,const byte* data,dword length) { if (length) key.Compute( data, length ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Key::Key() { Clear(); } void Key::Clear() { count = 0; state[0] = 0x67452301; state[1] = 0xEFCDAB89; state[2] = 0x98BADCFE; state[3] = 0x10325476; state[4] = 0xC3D2E1F0; finalized = false; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif inline void Key::Update() const { if (!finalized) Finalize(); } bool Key::operator == (const Key& key) const { Update(); key.Update(); for (uint i=0; i < 5; ++i) { if (final[i] != key.final[i]) return false; } return true; } void Key::Compute(const byte* const data,const dword length) { NST_ASSERT( data && length ); finalized = false; dword i = 0, j = count & 63; count += length; if (length + j > 63) { i = 64 - j; std::memcpy( buffer+j, data, i ); Transform( state, buffer ); for (; i + 63 < length; i += 64) Transform( state, data+i ); j = 0; } std::memcpy( buffer+j, data+i, length-i ); } void Key::Finalize() const { NST_ASSERT( !finalized && sizeof(final) == sizeof(state) ); finalized = true; std::memcpy( final, state, sizeof(final) ); byte end[64+64]; const uint length = count & 63; std::memcpy( end, buffer, length ); end[length] = 0x80; const uint page = (length >= 56 ? 64 : 0); std::memset( end+length+1, 0x00, page + (64-1) - length ); end[page+56] = count >> (56 - 3) & 0xFF; end[page+57] = count >> (48 - 3) & 0xFF; end[page+58] = count >> (40 - 3) & 0xFF; end[page+59] = count >> (32 - 3) & 0xFF; end[page+60] = count >> (24 - 3) & 0xFF; end[page+61] = count >> (16 - 3) & 0xFF; end[page+62] = count >> (8 - 3) & 0xFF; end[page+63] = count << ( 3) & 0xFF; Transform( final, end ); if (page) Transform( final, end+64 ); } Key::Digest Key::GetDigest() const { Update(); return final; } } } } nestopia-1.51.1/source/core/NstSha1.hpp000066400000000000000000000037561411157722000176560ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_SHA1_H #define NST_SHA1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Sha1 { class Key; void NST_CALL Compute(Key&,const byte*,dword); class Key : public ImplicitBool { public: Key(); enum { DIGEST_SIZE = 20 }; typedef const dword (&Digest)[5]; void Clear(); Digest GetDigest() const; bool operator == (const Key& key) const; private: friend void NST_CALL Compute(Key&,const byte*,dword); inline void Update() const; void Compute(const byte*,dword); void Finalize() const; qaword count; dword state[5]; mutable ibool finalized; mutable dword final[5]; byte buffer[64]; public: bool operator != (const Key& key) const { return !(*this == key); } bool operator ! () const { return !count; } }; } } } #endif nestopia-1.51.1/source/core/NstSoundPcm.cpp000066400000000000000000000043521411157722000205760ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstCpu.hpp" #include "NstSoundPcm.hpp" namespace Nes { namespace Core { namespace Sound { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Pcm::Pcm(Apu& a) : Channel(a) { Connect( UpdateSettings() ); } bool Pcm::CanDo(uint bits,dword rate) { return (bits == 8 || bits == 16) && (rate >= 8000 && rate <= 96000); } void Pcm::Reset() { Stop(); } bool Pcm::UpdateSettings() { Stop(); rate = GetSampleRate(); muted = IsMuted(); return true; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Pcm::Play(const iword* w,dword l,dword r) { NST_ASSERT( w && l && CanDo(16,r) ); pos = 0; wave.data = w; wave.length = l; wave.rate = r; } void Pcm::Stop() { pos = 0; wave.data = NULL; wave.length = 0; wave.rate = 0; } Pcm::Sample Pcm::GetSample() { if (wave.data) { const dword i = pos / rate; if (i < wave.length) { pos += wave.rate; return !muted ? wave.data[i] : 0; } wave.data = NULL; } return 0; } } } } nestopia-1.51.1/source/core/NstSoundPcm.hpp000066400000000000000000000032101411157722000205730ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_SOUND_PCM_H #define NST_SOUND_PCM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Sound { class Pcm : Apu::Channel { public: void Stop(); static bool CanDo(uint,dword); protected: explicit Pcm(Apu&); void Play(const iword*,dword,dword); private: void Reset(); bool UpdateSettings(); Sample GetSample(); qaword pos; struct { const iword* data; dword length; dword rate; } wave; dword rate; ibool muted; }; } } } #endif nestopia-1.51.1/source/core/NstSoundPlayer.cpp000066400000000000000000000133451411157722000213150ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstCpu.hpp" #include "NstChips.hpp" #include "NstSoundPlayer.hpp" #include "api/NstApiUser.hpp" namespace Nes { namespace Core { namespace Sound { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Player::Slot::Slot() : data(NULL) {} Player::Slot::~Slot() { delete [] data; } Player::Player(Apu& a,uint n) : Pcm(a), slots(new Slot [n]), numSlots(n) { NST_ASSERT( n ); } Player::~Player() { delete [] slots; } Player* Player::Create(Apu& apu,const Chips& chips,wcstring const chip,Game game,uint maxSamples) { if (!maxSamples) return NULL; if (chip && chips.Has(chip) && chips[chip].HasSamples()) { game = GAME_UNKNOWN; } else if (game != GAME_UNKNOWN) { maxSamples = uint(game) >> GAME_NUM_SAMPLES_SHIFT; NST_ASSERT( maxSamples ); } else { return NULL; } if (Player* const player = new (std::nothrow) Player(apu,maxSamples)) { for (uint i=0; i < maxSamples; ++i) { class Loader : public Api::User::File { const Action action; Slot& slot; const uint id; wcstring const filename; Action GetAction() const throw() { return action; } wcstring GetName() const throw() { return filename; } uint GetId() const throw() { return id; } Result SetSampleContent(const void* data,ulong length,bool stereo,uint bits,ulong rate) throw() { if (!data || !length) return RESULT_ERR_INVALID_PARAM; if (!Pcm::CanDo( bits, rate )) return RESULT_ERR_UNSUPPORTED; iword* NST_RESTRICT dst = new (std::nothrow) iword [length]; if (!dst) return RESULT_ERR_OUT_OF_MEMORY; slot.data = dst; slot.length = length; slot.rate = rate; if (bits == 8) { const byte* NST_RESTRICT src = static_cast(data); const byte* const end = src + length; if (stereo) { for (; src != end; src += 2) { const idword sample = (idword(uint(src[0]) << 8) - 32768) + (idword(uint(src[1]) << 8) - 32768); *dst++ = Clamp(sample); } } else { for (; src != end; src += 1) { const idword sample = idword(uint(*src) << 8) - 32768; *dst++ = Clamp(sample); } } } else { const iword* NST_RESTRICT src = static_cast(data); const iword* const end = src + length; if (stereo) { for (; src != end; src += 2) { const idword sample = src[0] + src[1]; *dst++ = Clamp(sample); } } else { for (; src != end; src += 1) { const idword sample = *src; *dst++ = Clamp(sample); } } } return RESULT_OK; } public: Loader(Game g,Slot& s,uint i,wcstring f) : action ( g == GAME_MOERO_PRO_YAKYUU ? LOAD_SAMPLE_MOERO_PRO_YAKYUU : g == GAME_MOERO_PRO_YAKYUU_88 ? LOAD_SAMPLE_MOERO_PRO_YAKYUU_88 : g == GAME_MOERO_PRO_TENNIS ? LOAD_SAMPLE_MOERO_PRO_TENNIS : g == GAME_TERAO_NO_DOSUKOI_OOZUMOU ? LOAD_SAMPLE_TERAO_NO_DOSUKOI_OOZUMOU : g == GAME_AEROBICS_STUDIO ? LOAD_SAMPLE_AEROBICS_STUDIO : LOAD_SAMPLE ), slot (s), id (i), filename (f) { } }; wcstring filename = L""; if (game != GAME_UNKNOWN || *(filename = *chips[chip].Sample(i))) { Loader loader( game, player->slots[i], i, filename ); try { Api::User::fileIoCallback( loader ); } catch (...) { delete player; throw; } } } for (uint i=0; i < maxSamples; ++i) { if (player->slots[i].data) return player; } delete player; } return NULL; } void Player::Destroy(Player* player) { delete player; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } } nestopia-1.51.1/source/core/NstSoundPlayer.hpp000066400000000000000000000044321411157722000213170ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_SOUND_PLAYER_H #define NST_SOUND_PLAYER_H #include "NstSoundPcm.hpp" #include "api/NstApiSound.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Sound { class Player : public Pcm { enum { GAME_NUM_SAMPLES_SHIFT = 4 }; public: enum Game { GAME_UNKNOWN, GAME_MOERO_PRO_YAKYUU = 16U << GAME_NUM_SAMPLES_SHIFT | 1, GAME_MOERO_PRO_YAKYUU_88 = 20U << GAME_NUM_SAMPLES_SHIFT | 2, GAME_MOERO_PRO_TENNIS = 19U << GAME_NUM_SAMPLES_SHIFT | 3, GAME_TERAO_NO_DOSUKOI_OOZUMOU = 6U << GAME_NUM_SAMPLES_SHIFT | 4, GAME_AEROBICS_STUDIO = 8U << GAME_NUM_SAMPLES_SHIFT | 5 }; static Player* Create(Apu&,const Chips&,wcstring,Game,uint); static void Destroy(Player*); private: Player(Apu&,uint); ~Player(); struct Slot { Slot(); ~Slot(); const iword* data; dword length; dword rate; }; Slot* const slots; const uint numSlots; public: void Play(uint i) { if (i < numSlots && slots[i].data) Pcm::Play( slots[i].data, slots[i].length, slots[i].rate ); } }; } } } #endif nestopia-1.51.1/source/core/NstSoundRenderer.cpp000066400000000000000000000033461411157722000216270ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstCpu.hpp" #include "NstSoundRenderer.hpp" namespace Nes { namespace Core { namespace Sound { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Buffer::Buffer(uint bits) : output(new iword [SIZE]) { Reset( bits, true ); } Buffer::~Buffer() { delete [] output; } void Buffer::Reset(uint bits,bool clear) { pos = start = 0; history.pos = 0; std::fill( history.buffer, history.buffer+History::SIZE, iword(bits == 16 ? 0 : 0x80) ); if (clear) std::fill( output, output+SIZE, iword(0) ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } } nestopia-1.51.1/source/core/NstSoundRenderer.hpp000066400000000000000000000065771411157722000216450ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_SOUND_RENDERER_H #define NST_SOUND_RENDERER_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Sound { typedef idword Sample; class Buffer { public: explicit Buffer(uint); ~Buffer(); enum { SIZE = 0x4000, MASK = SIZE-1 }; struct Block { inline explicit Block(uint); const iword* data; uint start; uint length; }; void Reset(uint,bool=true); void operator >> (Block&); template class Renderer; private: template class BaseRenderer : public ImplicitBool< BaseRenderer > { protected: T* NST_RESTRICT dst; const T* const end; inline BaseRenderer(void*,uint); public: inline bool operator !() const; }; struct History { template inline void operator >> (T&) const; inline void operator << (Sample); enum { SIZE = 0x40, MASK = SIZE-1 }; uint pos; iword buffer[SIZE]; }; uint pos; uint start; iword* const NST_RESTRICT output; public: inline void operator << (const Sample); History history; }; template<> class Buffer::Renderer : public Buffer::BaseRenderer { public: inline Renderer(void*,uint,const History&); inline void operator << (Sample); NST_FORCE_INLINE bool operator << (const Block&); }; template<> class Buffer::Renderer : public Buffer::BaseRenderer { History& history; public: inline Renderer(void*,uint,History&); inline void operator << (Sample); NST_FORCE_INLINE bool operator << (Block&); }; template<> class Buffer::Renderer : public Buffer::BaseRenderer { public: inline Renderer(void*,uint,const History&); inline void operator << (Sample); NST_FORCE_INLINE bool operator << (Block&); }; template<> class Buffer::Renderer : public Buffer::BaseRenderer { History& history; public: inline Renderer(void*,uint,History&); inline void operator << (Sample); NST_FORCE_INLINE bool operator << (Block&); }; } } } #endif nestopia-1.51.1/source/core/NstSoundRenderer.inl000066400000000000000000000116471411157722000216320ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// namespace Nes { namespace Core { namespace Sound { void Buffer::operator >> (Block& block) { NST_ASSERT( block.length ); const uint delta = (dword(pos) + SIZE - start) & MASK; block.data = output; block.start = start; if (block.length > delta) block.length = delta; start = (start + block.length) & MASK; if (start == pos) { start = 0; pos = 0; } } inline Buffer::Block::Block(uint l) : length(l) {} template inline Buffer::BaseRenderer::BaseRenderer(void* samples,uint length) : dst (static_cast(samples)), end (static_cast(samples) + length) {} template inline bool Buffer::BaseRenderer::operator !() const { return dst == end; } template inline void Buffer::History::operator >> (T& sample) const { sample = buffer[pos & MASK]; } inline void Buffer::History::operator << (Sample sample) { buffer[pos++ & MASK] = sample; } inline void Buffer::operator << (const Sample sample) { const uint p = pos; pos = (pos + 1) & MASK; output[p] = sample; } inline Buffer::Renderer::Renderer(void* samples,uint length,const History&) : BaseRenderer(samples,length) {} inline void Buffer::Renderer::operator << (Sample sample) { *dst++ = sample; } NST_FORCE_INLINE bool Buffer::Renderer::operator << (const Block& block) { NST_ASSERT( end - dst >= block.length ); if (block.length) { if (block.start + block.length <= SIZE) { std::memcpy( dst, block.data + block.start, sizeof(iword) * block.length ); } else { const uint chunk = SIZE - block.start; std::memcpy( dst, block.data + block.start, sizeof(iword) * chunk ); std::memcpy( dst + chunk, block.data, sizeof(iword) * ((block.start + block.length) - SIZE) ); } dst += block.length; } return dst != end; } inline Buffer::Renderer::Renderer(void* samples,uint length,History& h) : BaseRenderer(samples,length << 1), history(h) {} inline void Buffer::Renderer::operator << (Sample sample) { history >> dst[0]; history << sample; dst[1] = sample; dst += 2; } NST_FORCE_INLINE bool Buffer::Renderer::operator << (Block& block) { NST_ASSERT( end - dst >= block.length ); block.length += block.start; for (uint i=block.start; i < block.length; ++i) (*this) << Sample( block.data[i & MASK] ); return dst != end; } inline Buffer::Renderer::Renderer(void* samples,uint length,const History&) : BaseRenderer(samples,length) {} inline void Buffer::Renderer::operator << (Sample sample) { *dst++ = dword(sample + 32768L) >> 8; } NST_FORCE_INLINE bool Buffer::Renderer::operator << (Block& block) { NST_ASSERT( end - dst >= block.length ); block.length += block.start; for (uint i=block.start; i < block.length; ++i) (*this) << Sample( block.data[i & MASK] ); return dst != end; } inline Buffer::Renderer::Renderer(void* samples,uint length,History& h) : BaseRenderer(samples,length << 1), history(h) {} inline void Buffer::Renderer::operator << (Sample sample) { history >> dst[0]; sample = dword(sample + 32768L) >> 8; history << sample; dst[1] = sample; dst += 2; } NST_FORCE_INLINE bool Buffer::Renderer::operator << (Block& block) { NST_ASSERT( end - dst >= block.length ); block.length += block.start; for (uint i=block.start; i < block.length; ++i) (*this) << Sample( block.data[i & MASK] ); return dst != end; } } } } nestopia-1.51.1/source/core/NstState.cpp000066400000000000000000000137631411157722000201340ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstState.hpp" #include "NstZlib.hpp" namespace Nes { namespace Core { namespace State { enum Compression { NO_COMPRESSION, ZLIB_COMPRESSION }; #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Saver::Saver(StdStream p,bool c,bool i,dword append) : stream(p), chunks(CHUNK_RESERVE), useCompression(c), internal(i) { NST_COMPILE_ASSERT( CHUNK_RESERVE >= 2 ); chunks.SetTo(1); chunks.Front() = 0; if (append) { chunks.SetTo(2); chunks[1] = append; stream.Seek( 4 + 4 + append ); } } Saver::~Saver() { NST_VERIFY( chunks.Size() == 1 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif Saver& Saver::Begin(dword chunk) { stream.Write32( chunk ); stream.Write32( 0 ); chunks.Append( 0 ); return *this; } Saver& Saver::End() { NST_ASSERT( chunks.Size() > 1 ); const dword written = chunks.Pop(); chunks.Back() += 4 + 4 + written; stream.Seek( -idword(written + 4) ); stream.Write32( written ); stream.Seek( written ); return *this; } Saver& Saver::Write8(uint data) { chunks.Back() += 1; stream.Write8( data ); return *this; } Saver& Saver::Write16(uint data) { chunks.Back() += 2; stream.Write16( data ); return *this; } Saver& Saver::Write32(dword data) { chunks.Back() += 4; stream.Write32( data ); return *this; } Saver& Saver::Write64(qaword data) { chunks.Back() += 8; stream.Write64( data ); return *this; } Saver& Saver::Write(const byte* data,dword length) { chunks.Back() += length; stream.Write( data, length ); return *this; } Saver& Saver::Compress(const byte* const data,const dword length) { NST_VERIFY( length ); if (Zlib::AVAILABLE && useCompression && length > 1) { Vector buffer( length - 1 ); if (const dword compressed = Zlib::Compress( data, length, buffer.Begin(), buffer.Size(), Zlib::BEST_COMPRESSION )) { chunks.Back() += 1 + compressed; stream.Write8( ZLIB_COMPRESSION ); stream.Write( buffer.Begin(), compressed ); return *this; } } chunks.Back() += 1 + length; stream.Write8( NO_COMPRESSION ); stream.Write( data, length ); return *this; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Loader::Loader(StdStream p,bool c) : stream(p), chunks(CHUNK_RESERVE), checkCrc(c) { chunks.SetTo(0); } Loader::~Loader() { NST_VERIFY( chunks.Size() <= 1 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif dword Loader::Begin() { if (chunks.Size() && !chunks.Back()) return 0; const dword chunk = stream.Read32(); const dword length = stream.Read32(); if (chunks.Size()) { if (chunks.Back() >= 4+4+length) chunks.Back() -= 4+4+length; else throw RESULT_ERR_CORRUPT_FILE; } chunks.Append( length ); return chunk; } dword Loader::Length() const { return chunks.Size() ? chunks.Back() : 0; } dword Loader::Check() { return chunks.Size() && !chunks.Back() ? 0 : stream.Peek32(); } void Loader::End() { if (const dword remaining = chunks.Pop()) { NST_DEBUG_MSG("unreferenced state chunk data!"); stream.Seek( remaining ); } } void Loader::End(dword rollBack) { if (const idword back = -idword(rollBack+4+4) + idword(chunks.Pop())) stream.Seek( back ); } void Loader::CheckRead(dword length) { if (chunks.Back() >= length) chunks.Back() -= length; else throw RESULT_ERR_CORRUPT_FILE; } uint Loader::Read8() { CheckRead( 1 ); return stream.Read8(); } uint Loader::Read16() { CheckRead( 2 ); return stream.Read16(); } dword Loader::Read32() { CheckRead( 4 ); return stream.Read32(); } qaword Loader::Read64() { CheckRead( 8 ); return stream.Read64(); } void Loader::Read(byte* const data,const dword length) { CheckRead( length ); stream.Read( data, length ); } void Loader::Uncompress(byte* const data,const dword length) { NST_VERIFY( length ); switch (Read8()) { case NO_COMPRESSION: Read( data, length ); break; case ZLIB_COMPRESSION: if (!Zlib::AVAILABLE) { throw RESULT_ERR_UNSUPPORTED; } else if (chunks.Back()) { Vector buffer( chunks.Back() ); Read( buffer.Begin(), buffer.Size() ); if (Zlib::Uncompress( buffer.Begin(), buffer.Size(), data, length )) break; } default: throw RESULT_ERR_CORRUPT_FILE; } } } } } nestopia-1.51.1/source/core/NstState.hpp000066400000000000000000000067131411157722000201360ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_STATE_H #define NST_STATE_H #ifndef NST_VECTOR_H #include "NstVector.hpp" #endif #include "NstStream.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace State { class Saver { public: Saver(StdStream,bool,bool,dword=0); ~Saver(); Saver& Begin(dword); Saver& Write8(uint); Saver& Write16(uint); Saver& Write32(dword); Saver& Write64(qaword); Saver& Write(const byte*,dword); Saver& Compress(const byte*,dword); Saver& End(); protected: Stream::Out stream; private: enum { CHUNK_RESERVE = 8 }; Vector chunks; const bool useCompression; const bool internal; public: template Saver& Write(const byte (&data)[N]) { NST_COMPILE_ASSERT( N > 0 ); return Write( data, N ); } template Saver& Compress(const byte (&data)[N]) { NST_COMPILE_ASSERT( N > 0 ); return Compress( data, N ); } bool Internal() const { return internal; } }; class Loader { public: Loader(StdStream,bool); ~Loader(); dword Begin(); dword Check(); dword Length() const; uint Read8(); uint Read16(); dword Read32(); qaword Read64(); void Read(byte*,dword); void Uncompress(byte*,dword); void End(); void End(dword); template class Data { struct Block { byte data[N]; explicit Block(Loader& loader) { loader.Read( data, N ); } }; const Block block; public: explicit Data(Loader& loader) : block(loader) {} uint operator [] (uint i) const { NST_ASSERT( i < N ); return block.data[i]; } }; protected: Stream::In stream; private: void CheckRead(dword); enum { CHUNK_RESERVE = 8 }; Vector chunks; const bool checkCrc; public: template void Read(byte (&data)[N]) { NST_COMPILE_ASSERT( N > 0 ); Read( data, N ); } template void Uncompress(byte (&data)[N]) { NST_COMPILE_ASSERT( N > 0 ); Uncompress( data, N ); } bool CheckCrc() const { return checkCrc; } }; } } } #endif nestopia-1.51.1/source/core/NstStream.cpp000066400000000000000000000216321411157722000203010ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstVector.hpp" #include "NstStream.hpp" namespace Nes { namespace Core { namespace Stream { void In::Clear() { std::istream& ref = *static_cast(stream); if (!ref.bad()) ref.clear(); } void In::SafeRead(byte* data,dword size) { static_cast(stream)->read( reinterpret_cast(data), size ); } void In::Read(byte* data,dword size) { NST_ASSERT( data && size ); SafeRead( data, size ); if (!*static_cast(stream)) throw RESULT_ERR_CORRUPT_FILE; } uint In::Read8() { byte data; Read( &data, 1 ); return data; } uint In::Read16() { byte data[2]; Read( data, 2 ); return data[0] | uint(data[1]) << 8; } dword In::Read32() { byte data[4]; Read( data, 4 ); return data[0] | uint(data[1]) << 8 | dword(data[2]) << 16 | dword(data[3]) << 24; } qaword In::Read64() { byte data[8]; Read( data, 8 ); return ( qaword(data[4] | uint(data[5]) << 8 | dword(data[6]) << 16 | dword(data[7]) << 24) << 32 | dword(data[0] | uint(data[1]) << 8 | dword(data[2]) << 16 | dword(data[3]) << 24) ); } uint In::SafeRead8() { byte data; SafeRead( &data, 1 ); return *static_cast(stream) ? data : ~0U; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void In::Seek(idword distance) { Clear(); if (!static_cast(stream)->seekg( distance, std::ios::cur )) throw RESULT_ERR_CORRUPT_FILE; } ulong In::Length() { Clear(); std::istream& ref = *static_cast(stream); const ulong pos = ref.tellg(); if (!ref.seekg( 0, std::istream::end )) throw RESULT_ERR_CORRUPT_FILE; Clear(); const ulong length = ulong(ref.tellg()) - pos; if (!ref.seekg( pos )) throw RESULT_ERR_CORRUPT_FILE; Clear(); return length; } dword In::AsciiToC(char* NST_RESTRICT dst,const byte* NST_RESTRICT src,dword length) { const char* const dstEnd = dst + length; const byte* srcEnd = src; for (const byte* end=src+length; srcEnd != end && *srcEnd; ) ++srcEnd; while (srcEnd != src && srcEnd[-1] == Ascii<' '>::V) --srcEnd; while (src != srcEnd && *src && *src == Ascii<' '>::V) ++src; while (src != srcEnd) { const byte b = *src++; char c; if (b >= Ascii<'a'>::V && b <= Ascii<'z'>::V) { c = b - Ascii<'a'>::V + 'a'; } else if (b >= Ascii<'A'>::V && b <= Ascii<'Z'>::V) { c = b - Ascii<'A'>::V + 'A'; } else if (b >= Ascii<'0'>::V && b <= Ascii<'9'>::V) { c = b - Ascii<'0'>::V + '0'; } else switch (b) { case Ascii< '\0' >::V: c = '\0'; break; case Ascii< ' ' >::V: c = ' ' ; break; case Ascii< '!' >::V: c = '!' ; break; case Ascii< '#' >::V: c = '#' ; break; case Ascii< '%' >::V: c = '%' ; break; case Ascii< '^' >::V: c = '^' ; break; case Ascii< '&' >::V: c = '&' ; break; case Ascii< '*' >::V: c = '*' ; break; case Ascii< '(' >::V: c = '(' ; break; case Ascii< ')' >::V: c = ')' ; break; case Ascii< '-' >::V: c = '-' ; break; case Ascii< '_' >::V: c = '_' ; break; case Ascii< '+' >::V: c = '+' ; break; case Ascii< '=' >::V: c = '=' ; break; case Ascii< '~' >::V: c = '~' ; break; case Ascii< '[' >::V: c = '[' ; break; case Ascii< ']' >::V: c = ']' ; break; case Ascii< '\\' >::V: c = '\\'; break; case Ascii< '|' >::V: c = '|' ; break; case Ascii< ';' >::V: c = ';' ; break; case Ascii< ':' >::V: c = ':' ; break; case Ascii< '\'' >::V: c = '\''; break; case Ascii< '\"' >::V: c = '\"'; break; case Ascii< '{' >::V: c = '{' ; break; case Ascii< '}' >::V: c = '}' ; break; case Ascii< ',' >::V: c = ',' ; break; case Ascii< '.' >::V: c = '.' ; break; case Ascii< '<' >::V: c = '<' ; break; case Ascii< '>' >::V: c = '>' ; break; case Ascii< '/' >::V: c = '/' ; break; case Ascii< '?' >::V: c = '?' ; break; case Ascii< '\a' >::V: case Ascii< '\b' >::V: case Ascii< '\t' >::V: case Ascii< '\v' >::V: case Ascii< '\n' >::V: case Ascii< '\r' >::V: case Ascii< '\f' >::V: NST_DEBUG_MSG("invalid stream character!"); continue; default: NST_DEBUG_MSG("unknown stream character!"); c = b - (CHAR_MIN < 0 ? 0x100 : 0); break; } *dst++ = c; } length -= dstEnd - dst; while (dst != dstEnd) *dst++ = '\0'; return length; } void In::Read(char* dst,dword size) { NST_ASSERT( dst && size ); Vector buffer( size ); Read( buffer.Begin(), size ); AsciiToC( dst, buffer.Begin(), size ); } dword In::Read(Vector& string) { Vector buffer; buffer.Reserve( 32 ); for (uint c; (c=Read8()) != '\0'; buffer.Append(c)); string.Resize( buffer.Size() + 1 ); string.SetTo( AsciiToC( string.Begin(), buffer.Begin(), buffer.Size() ) + 1 ); string.Back() = '\0'; return buffer.Size() + 1; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif uint In::Peek8() { const uint data = Read8(); Seek( -1 ); return data; } uint In::Peek16() { const uint data = Read16(); Seek( -2 ); return data; } dword In::Peek32() { const dword data = Read32(); Seek( -4 ); return data; } void In::Peek(byte* data,dword length) { Read( data, length ); Seek( -idword(length) ); } bool In::Eof() { std::istream& ref = *static_cast(stream); return ref.eof() || (ref.peek(), ref.eof()); } void Out::Write(const byte* data,dword size) { NST_VERIFY( data && size ); if (!static_cast(stream)->write( reinterpret_cast(data), size )) throw RESULT_ERR_CORRUPT_FILE; } void Out::Write8(const uint data) { NST_VERIFY( data <= 0xFF ); const byte d = data & 0xFF; Write( &d, 1 ); } void Out::Write16(const uint data) { NST_VERIFY( data <= 0xFFFF ); const byte d[2] = { data >> 0 & 0xFF, data >> 8 & 0xFF }; Write( d, 2 ); } void Out::Write32(const dword data) { NST_VERIFY( data <= 0xFFFFFFFF ); const byte d[4] = { data >> 0 & 0xFF, data >> 8 & 0xFF, data >> 16 & 0xFF, data >> 24 & 0xFF }; Write( d, 4 ); } void Out::Write64(const qaword data) { const byte d[8] = { data >> 0 & 0xFF, data >> 8 & 0xFF, data >> 16 & 0xFF, data >> 24 & 0xFF, data >> 32 & 0xFF, data >> 40 & 0xFF, data >> 48 & 0xFF, data >> 56 & 0xFF }; Write( d, 8 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Out::Clear() { std::ostream& ref = *static_cast(stream); if (!ref.bad()) ref.clear(); } void Out::Seek(idword distance) { Clear(); if (!static_cast(stream)->seekp( distance, std::ios::cur )) throw RESULT_ERR_CORRUPT_FILE; } bool Out::SeekEnd() { Clear(); std::ostream& ref = *static_cast(stream); const std::streampos pos( ref.tellp() ); ref.seekp( 0, std::ios::end ); const bool advanced = !(pos == ref.tellp()); Clear(); return advanced; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } } nestopia-1.51.1/source/core/NstStream.hpp000066400000000000000000000056431411157722000203120ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_STREAM_H #define NST_STREAM_H #ifndef NST_ASSERT_H #include "NstAssert.hpp" #endif #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { template class Vector; typedef void* StdStream; namespace Stream { class In { StdStream const stream; void SafeRead(byte*,dword); void Clear(); public: explicit In(StdStream s) : stream(s) { NST_ASSERT( stream ); } static dword AsciiToC(char* NST_RESTRICT,const byte* NST_RESTRICT,dword); void Read(byte*,dword); void Read(char*,dword); dword Read(Vector&); uint Read8(); uint Read16(); dword Read32(); qaword Read64(); uint SafeRead8(); void Peek(byte*,dword); uint Peek8(); uint Peek16(); dword Peek32(); void Seek(idword); ulong Length(); bool Eof(); template void Read(byte (&data)[N]) { NST_COMPILE_ASSERT( N > 0 ); Read( data, N ); } bool operator == (StdStream s) const { return stream == s; } bool operator != (StdStream s) const { return stream != s; } }; class Out { StdStream const stream; void Clear(); public: explicit Out(StdStream s) : stream(s) { NST_ASSERT( stream ); } void Write(const byte*,dword); void Write8(uint); void Write16(uint); void Write32(dword); void Write64(qaword); void Seek(idword); bool SeekEnd(); template void Write(const byte (&data)[N]) { NST_COMPILE_ASSERT( N > 0 ); Write( data, N ); } bool operator == (StdStream s) const { return stream == s; } bool operator != (StdStream s) const { return stream != s; } }; } } } #endif nestopia-1.51.1/source/core/NstTimer.hpp000066400000000000000000000132771411157722000201410ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_TIMER_H #define NST_TIMER_H #ifndef NST_CPU_H #include "NstCpu.hpp" #endif #ifndef NST_PPU_H #include "NstPpu.hpp" #endif #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Timer { template class M2 { public: explicit M2(Cpu&); template M2(Cpu&,Param&); template M2(Cpu&,const Param&); void Reset(bool,bool); void VSync(); private: enum { IRQ_SETUP = 2 }; NES_DECL_HOOK( Signaled ); Cycle count; ibool connected; Cpu& cpu; public: Unit unit; bool Connect(bool connect) { connected = connect; return connect; } bool Connected() const { return connected; } void Update() { M2::NES_DO_HOOK( Signaled ); } void ClearIRQ() const { cpu.ClearIRQ(); } }; template M2::M2(Cpu& c) : count(0), connected(false), cpu(c) { } template template M2::M2(Cpu& c,Param& p) : count(0), connected(false), cpu(c), unit(p) { } template template M2::M2(Cpu& c,const Param& p) : count(0), connected(false), cpu(c), unit(p) { } template void M2::Reset(const bool hard,const bool connect) { count = 0; connected = connect; unit.Reset( hard ); cpu.AddHook( Hook(this,&M2::Hook_Signaled) ); } NES_HOOK_T(template,M2,Signaled) { NST_COMPILE_ASSERT( Divider <= 8 ); while (count <= cpu.GetCycles()) { if (connected && unit.Clock()) cpu.DoIRQ( Cpu::IRQ_EXT, count + cpu.GetClock(IRQ_SETUP) ); count += cpu.GetClock(Divider); } } template void M2::VSync() { NST_VERIFY( count == 0 || count >= cpu.GetFrameCycles()); count = (count > cpu.GetFrameCycles() ? count - cpu.GetFrameCycles() : 0); } template class A12; template<> class A12 { protected: template class Filter { Cycle clock; Cycle hold; public: Filter() : clock(0), hold(0) {} void Reset(const Ppu& ppu) { clock = 0; hold = ppu.GetClock(Hold); } bool Clock(Cycle cycle) { Cycle next = clock; clock = cycle + hold; return cycle >= next; } void VSync(const Cpu& cpu) { clock = (clock > cpu.GetFrameCycles() ? clock - cpu.GetFrameCycles() : 0); } }; }; template<> class A12::Filter<0> { public: void Reset(const Ppu&) const { } bool Clock(Cycle) const { return true; } void VSync(const Cpu&) const { } }; template class A12 : A12 { public: void Reset(bool,bool=true); private: NES_DECL_LINE( Signaled ); uint line; Cpu& cpu; Ppu& ppu; Filter filter; public: Unit unit; A12(Cpu& c,Ppu& p) : line(0), cpu(c), ppu(p) {} template A12(Cpu& c,Ppu& p,Param& a) : cpu(c), ppu(p), unit(a) {} void Connect(bool connect) { line = ppu.SetAddressLineHook( Io::Line(connect ? this : NULL,connect ? &A12::Line_Signaled : NULL) ) & 0x1000; } bool Connected() const { return ppu.GetAddressLineHook(); } void Update() const { ppu.Update(); } void ClearIRQ() const { cpu.ClearIRQ(); } void VSync() { filter.VSync( cpu ); } }; template void A12::Reset(bool hard,bool connect) { filter.Reset( ppu ); unit.Reset( hard ); Connect( connect ); ppu.EnableCpuSynchronization(); } NES_LINE_T(template,A12,Signaled) { NST_COMPILE_ASSERT( Delay <= 8 ); uint prev = line; line = address & 0x1000; if (line > prev && filter.Clock(cycle) && unit.Clock()) cpu.DoIRQ( Cpu::IRQ_EXT, cycle + (Delay ? cpu.GetClock(Delay) : 0) ); } } } } #endif nestopia-1.51.1/source/core/NstTracker.cpp000066400000000000000000000154011411157722000204360ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstMachine.hpp" #include "NstTrackerMovie.hpp" #include "NstTrackerRewinder.hpp" #include "NstImage.hpp" #include "api/NstApiMachine.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Tracker::Tracker() : frame (0), rewinderSound (false), rewinderEnabled (NULL), rewinder (NULL), movie (NULL) {} Tracker::~Tracker() { delete rewinder; delete movie; } void Tracker::Unload() { frame = 0; if (rewinder) rewinder->Unload(); else StopMovie(); } void Tracker::Reset() { frame = 0; if (rewinder) { rewinder->Reset(); } else if (movie) { movie->Reset(); } } void Tracker::PowerOff() { StopMovie(); } void Tracker::Resync(bool excludeFrame) const { if (rewinder) { rewinder->Reset(); } else if (movie && !excludeFrame) { movie->Resync(); } } Result Tracker::TryResync(Result lastResult,bool excludeFrame) const { NST_VERIFY( NES_SUCCEEDED(lastResult) ); if (NES_SUCCEEDED(lastResult) && lastResult != RESULT_NOP) Resync( excludeFrame ); return lastResult; } Result Tracker::EnableRewinder(Machine* const emulator) { if (rewinderEnabled == emulator) return RESULT_NOP; rewinderEnabled = emulator; UpdateRewinderState( true ); return RESULT_OK; } void Tracker::EnableRewinderSound(bool enable) { rewinderSound = enable; if (rewinder) rewinder->EnableSound( enable ); } void Tracker::ResetRewinder() const { if (rewinder) rewinder->Reset(); } void Tracker::UpdateRewinderState(bool enable) { if (enable && rewinderEnabled && !movie) { if (!rewinder) { rewinder = new Rewinder ( *rewinderEnabled, &Machine::Execute, &Machine::LoadState, &Machine::SaveState, rewinderEnabled->cpu, rewinderEnabled->cpu.GetApu(), rewinderEnabled->ppu, rewinderSound ); } } else { delete rewinder; rewinder = NULL; } } Result Tracker::PlayMovie(Machine& emulator,std::istream& stream) { if (!emulator.Is(Api::Machine::GAME)) return RESULT_ERR_NOT_READY; UpdateRewinderState( false ); Result result; try { if (movie == NULL) { movie = new Movie ( emulator, &Machine::LoadState, &Machine::SaveState, emulator.cpu, emulator.Is(Api::Machine::CARTRIDGE) ? emulator.image->GetPrgCrc() : 0 ); } if (movie->Play( stream )) { if (emulator.Is(Api::Machine::ON)) emulator.Reset( true ); return RESULT_OK; } else { return RESULT_NOP; } } catch (Result r) { result = r; } catch (const std::bad_alloc&) { result = RESULT_ERR_OUT_OF_MEMORY; } catch (...) { result = RESULT_ERR_GENERIC; } StopMovie(); return result; } Result Tracker::RecordMovie(Machine& emulator,std::iostream& stream,const bool append) { if (!emulator.Is(Api::Machine::GAME)) return RESULT_ERR_NOT_READY; UpdateRewinderState( false ); Result result; try { if (movie == NULL) { movie = new Movie ( emulator, &Machine::LoadState, &Machine::SaveState, emulator.cpu, emulator.image->GetPrgCrc() ); } return movie->Record( stream, append ) ? RESULT_OK : RESULT_NOP; } catch (Result r) { result = r; } catch (const std::bad_alloc&) { result = RESULT_ERR_OUT_OF_MEMORY; } catch (...) { result = RESULT_ERR_GENERIC; } StopMovie(); return result; } void Tracker::StopMovie() { delete movie; movie = NULL; UpdateRewinderState( true ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif Result Tracker::StartRewinding() const { return rewinder ? rewinder->Start() : RESULT_ERR_NOT_READY; } Result Tracker::StopRewinding() const { return rewinder ? rewinder->Stop() : RESULT_NOP; } bool Tracker::IsRewinding() const { return rewinder && rewinder->IsRewinding(); } bool Tracker::IsMoviePlaying() const { return movie && movie->IsPlaying(); } bool Tracker::IsMovieRecording() const { return movie && movie->IsRecording(); } bool Tracker::IsLocked(bool excludeFrame) const { return IsRewinding() || (!excludeFrame && IsMoviePlaying()); } bool Tracker::IsActive() const { return IsRewinding() || movie; } Result Tracker::Execute ( Machine& machine, Video::Output* const video, Sound::Output* const sound, Input::Controllers* input ) { if (machine.Is(Api::Machine::ON)) { ++frame; try { if (machine.Is(Api::Machine::GAME)) { if (rewinder) { rewinder->Execute( video, sound, input ); return RESULT_OK; } else if (movie) { if (!movie->Execute()) { StopMovie(); } else if (movie->IsPlaying()) { input = NULL; } } } machine.Execute( video, sound, input ); return RESULT_OK; } catch (Result result) { return machine.PowerOff( result ); } catch (const std::bad_alloc&) { return machine.PowerOff( RESULT_ERR_OUT_OF_MEMORY ); } catch (...) { return machine.PowerOff( RESULT_ERR_GENERIC ); } } else { return RESULT_ERR_NOT_READY; } } } } nestopia-1.51.1/source/core/NstTracker.hpp000066400000000000000000000051271411157722000204470ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_TRACKER_H #define NST_TRACKER_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class Machine; namespace Video { class Output; } namespace Sound { class Output; } namespace Input { class Controllers; } class Tracker { public: Tracker(); ~Tracker(); void Reset(); void PowerOff(); Result Execute(Machine&,Video::Output*,Sound::Output*,Input::Controllers*); void Resync(bool=false) const; Result TryResync(Result,bool=false) const; void Unload(); bool IsActive() const; bool IsLocked(bool=false) const; Result EnableRewinder(Machine*); void EnableRewinderSound(bool); void ResetRewinder() const; Result StartRewinding() const; Result StopRewinding() const; bool IsRewinding() const; Result PlayMovie(Machine&,std::istream&); Result RecordMovie(Machine&,std::iostream&,bool); void StopMovie(); bool IsMoviePlaying() const; bool IsMovieRecording() const; private: void UpdateRewinderState(bool); class Movie; class Rewinder; dword frame; ibool rewinderSound; Machine* rewinderEnabled; Rewinder* rewinder; Movie* movie; public: bool IsRewinderEnabled() const { return rewinderEnabled; } bool IsRewinderSoundEnabled() const { return rewinderSound; } bool IsFrameLocked() const { return movie; } dword Frame() const { return frame; } }; } } #endif nestopia-1.51.1/source/core/NstTrackerMovie.cpp000066400000000000000000000301551411157722000214410ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include "NstMachine.hpp" #include "NstState.hpp" #include "NstTrackerMovie.hpp" #include "NstZlib.hpp" #include "api/NstApiMovie.hpp" #include "api/NstApiUser.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif class Tracker::Movie::Player { public: ~Player(); void Relink(); private: static dword Validate(State::Loader&,const Cpu&,dword,bool); enum { MAX_BUFFER_MASK = 0xFFFFFF, OPEN_BUS = 0x40 }; struct Buffer : Vector { dword pos; Buffer() : pos(0) {} }; struct Loader : State::Loader { explicit Loader(std::istream& s) : State::Loader(&s,false) {} bool operator == (std::istream& s) const { return stream == &s; } }; NES_DECL_PEEK( Port ); NES_DECL_POKE( Port ); const Io::Port* ports[2]; dword frame; Buffer buffers[2]; Loader state; Cpu& cpu; public: static dword Validate(std::istream& stream,const Cpu& cpu,dword prgCrc) { Loader state( stream ); return Validate( state, cpu, prgCrc, true ); } Player(std::istream& stream,Cpu& c,const dword prgCrc) : frame(0), state(stream), cpu(c) { Validate( state, cpu, prgCrc, false ); Relink(); } bool operator == (std::istream& stream) const { return state == stream; } void Stop() { state.End(); } bool Execute(Machine& emulator,EmuLoadState loadState) { NST_ASSERT( loadState ); if (buffers[0].pos > buffers[0].Size() || buffers[1].pos > buffers[1].Size()) throw RESULT_ERR_CORRUPT_FILE; if (frame) { --frame; } else for (;;) { NST_VERIFY( buffers[0].pos == buffers[0].Size() && buffers[1].pos == buffers[1].Size() ); const dword chunk = state.Begin(); if (chunk == AsciiId<'K','E','Y'>::V) { for (uint i=0; i < 2; ++i) { buffers[i].pos = 0; buffers[i].Clear(); } while (const dword subChunk = state.Begin()) { switch (subChunk) { case AsciiId<'S','A','V'>::V: (emulator.*loadState)( state, false ); break; case AsciiId<'P','T','0'>::V: case AsciiId<'P','T','1'>::V: { const uint i = (subChunk == AsciiId<'P','T','1'>::V); buffers[i].Resize( state.Read32() & MAX_BUFFER_MASK ); state.Uncompress( buffers[i].Begin(), buffers[i].Size() ); break; } case AsciiId<'L','E','N'>::V: frame = state.Read32(); NST_VERIFY( frame <= 0xFFFFF ); break; } state.End(); } state.End(); break; } else if (chunk) { state.End(); } else { return false; } } return true; } }; Tracker::Movie::Player::~Player() { for (uint i=0; i < 2; ++i) cpu.Unlink( 0x4016 + i, this, &Player::Peek_Port, &Player::Poke_Port ); } dword Tracker::Movie::Player::Validate(State::Loader& state,const Cpu& cpu,const dword prgCrc,const bool end) { if (state.Begin() != (AsciiId<'N','S','V'>::V | 0x1AUL << 24)) throw RESULT_ERR_INVALID_FILE; const dword length = state.Length(); Region region = REGION_NTSC; dword crc = 0; while (const dword chunk = state.Check()) { if (chunk == AsciiId<'P','A','L'>::V) { state.Begin(); region = REGION_PAL; state.End(); } else if (chunk == AsciiId<'C','R','C'>::V) { state.Begin(); crc = state.Read32(); state.End(); } else if (chunk & 0xFFFFFF00) { break; } else { throw RESULT_ERR_UNSUPPORTED_FILE_VERSION; } } if (end) state.End( length ); if (region != cpu.GetRegion()) throw RESULT_ERR_WRONG_MODE; if (crc && prgCrc && crc != prgCrc && Api::User::questionCallback( Api::User::QUESTION_NSV_PRG_CRC_FAIL_CONTINUE ) == Api::User::ANSWER_NO) throw RESULT_ERR_INVALID_CRC; return length; } void Tracker::Movie::Player::Relink() { for (uint i=0; i < 2; ++i) ports[i] = cpu.Link( 0x4016 + i, Cpu::LEVEL_HIGHEST, this, &Player::Peek_Port, &Player::Poke_Port ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(Tracker::Movie::Player,Port) { address &= 0x1; const uint pos = buffers[address].pos++; if (pos < buffers[address].Size()) { return buffers[address][pos]; } else { NST_DEBUG_MSG("buffer >> data failed!"); return OPEN_BUS; } } NES_POKE_AD(Tracker::Movie::Player,Port) { ports[address & 0x1]->Poke( address, data ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif class Tracker::Movie::Recorder { public: ~Recorder(); void Relink(); private: void BeginKey(Machine&,EmuSaveState); void EndKey(); enum { BAD_FRAME = dword(~0UL), MAX_BUFFER_BLOCK = SIZE_1K * 8192UL }; typedef Vector Buffer; struct Saver : State::Saver { Saver(std::ostream& s,dword a) : State::Saver(&s,true,true,a) {} bool operator == (std::ostream& s) const { return stream == &s; } }; NES_DECL_PEEK( Port ); NES_DECL_POKE( Port ); const Io::Port* ports[2]; ibool resync; dword frame; Buffer buffers[2]; Saver state; Cpu& cpu; public: Recorder(std::iostream& stream,Cpu& c,const dword prgCrc,const bool append) : resync(true), frame(0), state(stream,append ? Player::Validate(stream,c,prgCrc) : 0), cpu(c) { if (!append) { state.Begin( AsciiId<'N','S','V'>::V | 0x1AUL << 24 ); if (cpu.GetRegion() == REGION_PAL) state.Begin( AsciiId<'P','A','L'>::V ).End(); if (prgCrc) state.Begin( AsciiId<'C','R','C'>::V ).Write32( prgCrc ).End(); } Relink(); } bool operator == (std::ostream& stream) const { return state == stream; } void Resync() { resync = true; } void Stop() { EndKey(); state.End(); } void Execute(Machine& machine,EmuSaveState saveState) { NST_ASSERT( saveState ); if (frame == BAD_FRAME) throw RESULT_ERR_OUT_OF_MEMORY; if (resync || buffers[0].Size() >= MAX_BUFFER_BLOCK || buffers[1].Size() >= MAX_BUFFER_BLOCK) { EndKey(); BeginKey( machine, saveState ); } ++frame; } }; Tracker::Movie::Recorder::~Recorder() { for (uint i=0; i < 2; ++i) cpu.Unlink( 0x4016 + i, this, &Recorder::Peek_Port, &Recorder::Poke_Port ); } void Tracker::Movie::Recorder::Relink() { for (uint i=0; i < 2; ++i) ports[i] = cpu.Link( 0x4016 + i, Cpu::LEVEL_HIGHEST, this, &Recorder::Peek_Port, &Recorder::Poke_Port ); } void Tracker::Movie::Recorder::BeginKey(Machine& machine,EmuSaveState saveState) { state.Begin( AsciiId<'K','E','Y'>::V ); if (resync) { resync = false; state.Begin( AsciiId<'S','A','V'>::V ); (machine.*saveState)( state ); state.End(); } } void Tracker::Movie::Recorder::EndKey() { if (frame == BAD_FRAME) throw RESULT_ERR_OUT_OF_MEMORY; if (frame) { state.Begin( AsciiId<'L','E','N'>::V ).Write32( frame-1 ).End(); frame = 0; for (uint i=0; i < 2; ++i) { if (buffers[i].Size()) { state.Begin( AsciiId<'P','T','0'>::R(0,0,i) ).Write32( buffers[i].Size() ).Compress( buffers[i].Begin(), buffers[i].Size() ).End(); buffers[i].Clear(); } } state.End(); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(Tracker::Movie::Recorder,Port) { const uint data = ports[address & 0x1]->Peek( address ); if (frame != BAD_FRAME) { try { buffers[address & 0x1].Append( data ); } catch (...) { frame = BAD_FRAME; } } return data; } NES_POKE_AD(Tracker::Movie::Recorder,Port) { ports[address & 0x1]->Poke( address, data ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Tracker::Movie::Movie(Machine& e,EmuLoadState l,EmuSaveState s,Cpu& c,dword crc) : player (NULL), recorder (NULL), emulator (e), saveState (s), loadState (l), cpu (c), prgCrc (crc) { } Tracker::Movie::~Movie() { Stop(); } bool Tracker::Movie::Record(std::iostream& stream,const bool append) { if (!Zlib::AVAILABLE) throw RESULT_ERR_UNSUPPORTED; if (player) throw RESULT_ERR_NOT_READY; if (recorder && *recorder == stream) return false; Stop(); recorder = new Recorder( stream, cpu, prgCrc, append ); Api::Movie::eventCallback( Api::Movie::EVENT_RECORDING ); return true; } bool Tracker::Movie::Play(std::istream& stream) { if (!Zlib::AVAILABLE) throw RESULT_ERR_UNSUPPORTED; if (recorder) throw RESULT_ERR_NOT_READY; if (player && *player == stream) return false; Stop(); player = new Player( stream, cpu, prgCrc ); Api::Movie::eventCallback( Api::Movie::EVENT_PLAYING ); return true; } void Tracker::Movie::Stop() { Stop( RESULT_OK ); } bool Tracker::Movie::Stop(Result result) { if (recorder || player) { if (NES_SUCCEEDED(result)) { try { if (recorder) recorder->Stop(); else player->Stop(); } catch (Result r) { result = r; } catch (const std::bad_alloc&) { result = RESULT_ERR_OUT_OF_MEMORY; } catch (...) { result = RESULT_ERR_GENERIC; } } if (recorder) { delete recorder; recorder = NULL; Api::Movie::eventCallback( Api::Movie::EVENT_RECORDING_STOPPED, result ); } else { delete player; player = NULL; Api::Movie::eventCallback( Api::Movie::EVENT_PLAYING_STOPPED, result ); if (NES_FAILED(result)) return false; } } return true; } void Tracker::Movie::Reset() { if (recorder) { recorder->Relink(); } else if (player) { player->Relink(); } Resync(); } void Tracker::Movie::Resync() { if (recorder) recorder->Resync(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif bool Tracker::Movie::Execute() { Result result = RESULT_OK; try { if (recorder) { recorder->Execute( emulator, saveState ); return true; } else if (player && player->Execute( emulator, loadState )) { return true; } } catch (Result r) { result = r; } catch (const std::bad_alloc&) { result = RESULT_ERR_OUT_OF_MEMORY; } catch (...) { result = RESULT_ERR_GENERIC; } if (!Stop( result )) throw result; return false; } } } nestopia-1.51.1/source/core/NstTrackerMovie.hpp000066400000000000000000000037121411157722000214450ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_TRACKER_MOVIE_H #define NST_TRACKER_MOVIE_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class Tracker::Movie { typedef bool (Machine::*EmuLoadState)(State::Loader&,bool); typedef void (Machine::*EmuSaveState)(State::Saver&) const; public: Movie(Machine&,EmuLoadState,EmuSaveState,Cpu&,dword); ~Movie(); bool Play(std::istream&); bool Record(std::iostream&,bool); void Stop(); void Resync(); void Reset(); bool Execute(); private: bool Stop(Result); class Player; class Recorder; Player* player; Recorder* recorder; Machine& emulator; const EmuSaveState saveState; const EmuLoadState loadState; Cpu& cpu; const dword prgCrc; public: bool IsPlaying() const { return player; } bool IsRecording() const { return recorder; } }; } } #endif nestopia-1.51.1/source/core/NstTrackerRewinder.cpp000066400000000000000000000432141411157722000221410ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include "NstMachine.hpp" #include "NstState.hpp" #include "NstTrackerRewinder.hpp" #include "api/NstApiRewinder.hpp" #include "NstZlib.hpp" namespace Nes { namespace Core { class Tracker::Rewinder::ReverseVideo::Mutex { Ppu& ppu; Video::Screen::Pixel* const pixels; public: explicit Mutex(const ReverseVideo& r) : ppu(r.ppu), pixels(r.ppu.GetOutputPixels()) {} void Flush(Video::Screen::Pixel* src) const { std::memcpy( pixels, src, Video::Screen::PIXELS * sizeof(Video::Screen::Pixel) ); } ~Mutex() { ppu.SetOutputPixels( pixels ); } }; class Tracker::Rewinder::ReverseVideo::Buffer { typedef Video::Screen::Pixel Pixel; enum { PIXELS = Video::Screen::PIXELS, SIZE = PIXELS * dword(NUM_FRAMES), FULL_SIZE = dword(SIZE) + Video::Screen::PIXELS_PADDING }; Pixel pixels[FULL_SIZE]; public: Buffer() { std::fill( pixels + SIZE, pixels + FULL_SIZE, Pixel(0) ); } Pixel* operator [] (dword i) { NST_ASSERT( i < NUM_FRAMES ); return pixels + (PIXELS * i); } }; class Tracker::Rewinder::ReverseSound::Mutex { Output::LockCallback funcLock; void* userLock; Output::UnlockCallback funcUnlock; void* userUnlock; public: Mutex() { Output::lockCallback.Get( funcLock, userLock ); Output::unlockCallback.Get( funcUnlock, userUnlock ); Output::lockCallback.Set( NULL, NULL ); Output::unlockCallback.Set( NULL, NULL ); } bool Lock(Output& output) const { return funcLock ? funcLock( userLock, output ) : true; } void Unlock(Output& output) const { if (funcUnlock) funcUnlock( userUnlock, output ); } ~Mutex() { Output::lockCallback.Set( funcLock, userLock ); Output::unlockCallback.Set( funcUnlock, userUnlock ); } }; #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Tracker::Rewinder::ReverseVideo::ReverseVideo(Ppu& p) : pingpong (1), frame (0), ppu (p), buffer (NULL) {} Tracker::Rewinder::ReverseSound::ReverseSound(const Apu& a,bool e) : enabled (e), good (false), stereo (false), bits (0), rate (0), index (0), buffer (NULL), size (0), input (NULL), apu (a) {} Tracker::Rewinder::Rewinder(Machine& e,EmuExecute x,EmuLoadState l,EmuSaveState s,Cpu& c,const Apu& a,Ppu& p,bool b) : rewinding (false), sound (a,b), video (p), emulator (e), emuExecute (x), emuLoadState (l), emuSaveState (s), cpu (c), ppu (p) { Reset( true ); } Tracker::Rewinder::ReverseVideo::~ReverseVideo() { End(); } Tracker::Rewinder::ReverseSound::~ReverseSound() { End(); } Tracker::Rewinder::~Rewinder() { LinkPorts( false ); } void Tracker::Rewinder::LinkPorts(bool on) { for (uint i=0; i < 2; ++i) { cpu.Unlink( 0x4016+i, this, &Rewinder::Peek_Port_Get, &Rewinder::Poke_Port ); cpu.Unlink( 0x4016+i, this, &Rewinder::Peek_Port_Put, &Rewinder::Poke_Port ); } if (on) { for (uint i=0; i < 2; ++i) ports[i] = cpu.Link( 0x4016+i, Cpu::LEVEL_HIGHEST, this, rewinding ? &Rewinder::Peek_Port_Get : &Rewinder::Peek_Port_Put, &Rewinder::Poke_Port ); } } Tracker::Rewinder::Key::Key() { } Tracker::Rewinder::Key::~Key() { } void Tracker::Rewinder::Key::Input::Reset() { pos = BAD_POS; buffer.Destroy(); } void Tracker::Rewinder::Key::Reset() { stream.str( std::string() ); input.Reset(); } void Tracker::Rewinder::Reset(bool on) { video.End(); sound.End(); if (rewinding) { rewinding = false; Api::Rewinder::stateCallback( Api::Rewinder::STOPPED ); } uturn = false; frame = LAST_FRAME; key = keys + LAST_KEY; for (uint i=0; i < NUM_FRAMES; ++i) keys[i].Reset(); LinkPorts( on ); } void Tracker::Rewinder::ReverseVideo::Begin() { pingpong = 1; frame = 0; if (buffer == NULL) buffer = new Buffer; } void Tracker::Rewinder::ReverseVideo::End() { delete buffer; buffer = NULL; } void Tracker::Rewinder::ReverseSound::Begin() { good = true; index = 0; } void Tracker::Rewinder::ReverseSound::End() { std::free( buffer ); buffer = NULL; } void Tracker::Rewinder::ReverseSound::Enable(bool state) { enabled = state; if (!state) End(); } bool Tracker::Rewinder::ReverseSound::Update() { const dword old = (bits == 16 ? size * sizeof(iword) : size * sizeof(byte)); bits = apu.GetSampleBits(); rate = apu.GetSampleRate(); stereo = apu.InStereo(); size = rate << (stereo+1); const dword total = (bits == 16 ? size * sizeof(iword) : size * sizeof(byte)); NST_ASSERT( total ); if (!buffer || total != old) { if (void* const next = std::realloc( buffer, total )) { buffer = next; } else { End(); good = false; return false; } } good = true; index = 0; if (bits == 16) std::fill( static_cast(buffer), static_cast(buffer) + size, iword(0) ); else std::memset( buffer, 0x80, size ); return true; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif inline void Tracker::Rewinder::Key::Input::Invalidate() { pos = BAD_POS; } inline void Tracker::Rewinder::Key::Input::BeginForward() { const dword hint = pos; pos = 0; buffer.Clear(); if (hint != BAD_POS) buffer.Reserve( hint ); } bool Tracker::Rewinder::Key::Input::EndForward() { if (pos == 0) { pos = buffer.Size(); if (Zlib::AVAILABLE && pos >= MIN_COMPRESSION_SIZE) { Buffer tmp( pos - 1 ); if (const dword size = Zlib::Compress( buffer.Begin(), buffer.Size(), tmp.Begin(), tmp.Size(), Zlib::NORMAL_COMPRESSION )) { NST_ASSERT( size < pos ); tmp.SetTo( size ); Buffer::Swap( tmp, buffer ); } else { NST_DEBUG_MSG("compress() in Tracker::Rewinder::Key::Input failed!"); } buffer.Defrag(); } return true; } return false; } void Tracker::Rewinder::Key::Input::BeginBackward() { dword size = pos; pos = 0; if (Zlib::AVAILABLE && size > buffer.Size()) { Buffer tmp( size ); size = Zlib::Uncompress( buffer.Begin(), buffer.Size(), tmp.Begin(), tmp.Size() ); if (!size) throw RESULT_ERR_CORRUPT_FILE; NST_VERIFY( size == tmp.Size() ); Buffer::Swap( tmp, buffer ); } } inline void Tracker::Rewinder::Key::Input::EndBackward() { pos = 0; } inline void Tracker::Rewinder::Key::Input::ResumeForward() { NST_VERIFY( pos != BAD_POS ); dword size = pos; pos = 0; buffer.Resize( size != BAD_POS ? size : 0 ); } inline bool Tracker::Rewinder::Key::Input::CanRewind() const { return pos != BAD_POS; } inline uint Tracker::Rewinder::Key::Input::Put(const uint data) { if (pos != BAD_POS) { try { buffer.Append( data ); } catch (...) { NST_DEBUG_MSG("buffer << data failed!"); pos = BAD_POS; } } return data; } inline uint Tracker::Rewinder::Key::Input::Get() { if (pos < buffer.Size()) { return buffer[pos++]; } else { NST_DEBUG_MSG("buffer >> data failed!"); pos = BAD_POS; return OPEN_BUS; } } inline void Tracker::Rewinder::Key::Invalidate() { input.Invalidate(); } inline bool Tracker::Rewinder::Key::CanRewind() const { return input.CanRewind(); } inline void Tracker::Rewinder::Key::ResumeForward() { input.ResumeForward(); } void Tracker::Rewinder::Key::BeginForward(Machine& emulator,EmuSaveState saveState,EmuLoadState loadState) { NST_ASSERT( !saveState || !loadState ); input.BeginForward(); if (saveState) { stream.clear(); stream.seekp( 0, std::stringstream::beg ); stream.clear(); State::Saver saver( &static_cast(stream), false, true ); (emulator.*saveState)( saver ); } else if (loadState) { TurnForward( emulator, loadState ); } } void Tracker::Rewinder::Key::EndForward() { if (!input.EndForward()) Reset(); } void Tracker::Rewinder::Key::TurnForward(Machine& emulator,EmuLoadState loadState) { stream.clear(); stream.seekg( 0, std::stringstream::beg ); stream.clear(); State::Loader loader( &static_cast(stream), false ); (emulator.*loadState)( loader, true ); } void Tracker::Rewinder::Key::BeginBackward(Machine& emulator,EmuLoadState loadState) { NST_VERIFY( CanRewind() ); TurnForward( emulator, loadState ); input.BeginBackward(); } inline void Tracker::Rewinder::Key::EndBackward() { input.EndBackward(); } inline uint Tracker::Rewinder::Key::Put(uint data) { return input.Put( data ); } inline uint Tracker::Rewinder::Key::Get() { return input.Get(); } inline Tracker::Rewinder::Key* Tracker::Rewinder::PrevKey(Key* k) { return (k != keys ? k-1 : keys+LAST_KEY); } inline Tracker::Rewinder::Key* Tracker::Rewinder::PrevKey() { return PrevKey( key ); } inline Tracker::Rewinder::Key* Tracker::Rewinder::NextKey(Key* k) { return (k != keys+LAST_KEY ? k+1 : keys); } inline Tracker::Rewinder::Key* Tracker::Rewinder::NextKey() { return NextKey( key ); } inline void Tracker::Rewinder::ReverseVideo::Flush(const Mutex& mutex) { mutex.Flush( (*buffer)[frame] ); } void Tracker::Rewinder::ReverseVideo::Store() { NST_ASSERT( frame < NUM_FRAMES && (pingpong == 1U-0U || pingpong == 0U-1U) ); ppu.SetOutputPixels( (*buffer)[frame] ); frame += pingpong; if (frame == NUM_FRAMES) { frame = LAST_FRAME; pingpong = 0U-1U; } else if (frame == 0U-1U) { frame = 0; pingpong = 1U-0U; } } template NST_FORCE_INLINE Sound::Output* Tracker::Rewinder::ReverseSound::StoreType() { NST_ASSERT( index <= NUM_FRAMES+LAST_FRAME ); switch (index++) { case 0: *output.length = rate / NUM_FRAMES; *output.samples = buffer; input = static_cast(buffer) + (size / 1); break; case LAST_FRAME: *output.samples = static_cast(*output.samples) + (*output.length << stereo); *output.length = dword(static_cast(buffer) + (size / 2) - static_cast(*output.samples)) >> stereo; break; case NUM_FRAMES: *output.length = rate / NUM_FRAMES; *output.samples = static_cast(buffer) + (size / 2); input = *output.samples; break; case NUM_FRAMES+LAST_FRAME: index = 0; *output.samples = static_cast(*output.samples) + (*output.length << stereo); *output.length = dword(static_cast(buffer) + (size / 1) - static_cast(*output.samples)) >> stereo; break; default: *output.samples = static_cast(*output.samples) + (*output.length << stereo); break; } return &output; } Sound::Output* Tracker::Rewinder::ReverseSound::Store() { NST_COMPILE_ASSERT( NUM_FRAMES % 2 == 0 ); if (!buffer || (bits ^ apu.GetSampleBits()) | (rate ^ apu.GetSampleRate()) | (stereo ^ uint(bool(apu.InStereo())))) { if (!good || !Update() || !enabled) return NULL; } return bits == 16 ? StoreType() : StoreType(); } template void Tracker::Rewinder::ReverseSound::ReverseSilence(const Output& target) const { for (uint i=0; i < 2; ++i) std::fill( static_cast(target.samples[i]), static_cast(target.samples[i]) + (target.length[i] << stereo), SILENCE ); } template const void* Tracker::Rewinder::ReverseSound::ReverseCopy(const Output& target) const { const T* NST_RESTRICT src = static_cast(input); for (uint i=0; i < 2; ++i) { if (const dword length = (target.length[i] << stereo)) { T* NST_RESTRICT dst = static_cast(target.samples[i]); T* const dstEnd = dst + length; for (const T* const srcEnd = dword(src - static_cast(buffer)) >= length ? src - length : static_cast(buffer); src != srcEnd; ) *dst++ = *--src; const T last( *src ); std::fill( dst, dstEnd, last ); } } return src; } void Tracker::Rewinder::ReverseSound::Flush(Output* const target,const Mutex& mutex) { if (target && mutex.Lock( *target )) { if (enabled & good) { input = (bits == 16) ? ReverseCopy( *target ) : ReverseCopy( *target ); } else { if (bits == 16) ReverseSilence( *target ); else ReverseSilence( *target ); } mutex.Unlock( *target ); } } void Tracker::Rewinder::Execute(Video::Output* videoOut,Sound::Output* soundOut,Input::Controllers* inputOut) { try { if (uturn) ChangeDirection(); NST_ASSERT( frame < NUM_FRAMES ); if (!rewinding) { if (++frame == NUM_FRAMES) { frame = 0; key->EndForward(); key = NextKey(); key->BeginForward( emulator, emuSaveState, NULL ); } } else { if (++frame == NUM_FRAMES) { frame = 0; key->EndBackward(); Key* const prev = PrevKey(); if (prev->CanRewind()) { prev->BeginBackward( emulator, emuLoadState ); key = prev; } else { rewinding = false; key->Invalidate(); key = NextKey(); key->BeginForward( emulator, NULL, emuLoadState ); Api::Rewinder::stateCallback( Api::Rewinder::STOPPED ); LinkPorts(); } } if (rewinding) { const ReverseVideo::Mutex videoMutex( video ); video.Flush( videoMutex ); video.Store(); const ReverseSound::Mutex soundMutex; sound.Flush( soundOut, soundMutex ); soundOut = sound.Store(); (emulator.*emuExecute)( videoOut, soundOut, inputOut ); return; } } } catch (...) { Reset(); throw; } (emulator.*emuExecute)( videoOut, soundOut, inputOut ); } void Tracker::Rewinder::ChangeDirection() { Api::Rewinder::stateCallback( Api::Rewinder::PREPARING ); uturn = false; if (rewinding) { for (uint i=frame; i < LAST_FRAME; ++i) (emulator.*emuExecute)( NULL, NULL, NULL ); NextKey()->Invalidate(); video.Begin(); sound.Begin(); key->BeginBackward( emulator, emuLoadState ); LinkPorts(); { const ReverseVideo::Mutex videoMutex( video ); const ReverseSound::Mutex soundMutex; for (uint i=0; i < NUM_FRAMES; ++i) { video.Store(); (emulator.*emuExecute)( NULL, sound.Store(), NULL ); } } uint align = LAST_FRAME - frame; frame = LAST_FRAME; while (align--) { Execute( NULL, NULL, NULL ); if (!rewinding) throw RESULT_ERR_CORRUPT_FILE; } Api::Rewinder::stateCallback( Api::Rewinder::REWINDING ); } else { for (uint i=NUM_FRAMES+LAST_FRAME-frame*2; i; --i) { if (++frame == NUM_FRAMES) { frame = 0; key = NextKey(); key->TurnForward( emulator, emuLoadState ); } (emulator.*emuExecute)( NULL, NULL, NULL ); } key->ResumeForward(); LinkPorts(); video.End(); sound.End(); Api::Rewinder::stateCallback( Api::Rewinder::STOPPED ); } } Result Tracker::Rewinder::Start() { if (rewinding) return RESULT_NOP; if (uturn || !PrevKey()->CanRewind()) return RESULT_ERR_NOT_READY; uturn = true; rewinding = true; return RESULT_OK; } Result Tracker::Rewinder::Stop() { if (!rewinding) return RESULT_NOP; if (uturn) return RESULT_ERR_NOT_READY; uturn = true; rewinding = false; return RESULT_OK; } NES_PEEK_A(Tracker::Rewinder,Port_Put) { return key->Put( ports[address-0x4016]->Peek( address ) ); } NES_PEEK(Tracker::Rewinder,Port_Get) { return key->Get(); } NES_POKE_AD(Tracker::Rewinder,Port) { ports[address-0x4016]->Poke( address, data ); } } } nestopia-1.51.1/source/core/NstTrackerRewinder.hpp000066400000000000000000000121401411157722000221400ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_TRACKER_REWINDER_H #define NST_TRACKER_REWINDER_H #include #include "api/NstApiSound.hpp" #ifndef NST_VECTOR_H #include "NstVector.hpp" #endif #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class Tracker::Rewinder { typedef void (Machine::*EmuExecute)(Video::Output*,Sound::Output*,Input::Controllers*); typedef void (Machine::*EmuSaveState)(State::Saver&) const; typedef bool (Machine::*EmuLoadState)(State::Loader&,bool); public: Rewinder(Machine&,EmuExecute,EmuLoadState,EmuSaveState,Cpu&,const Apu&,Ppu&,bool); ~Rewinder(); Result Start(); Result Stop(); void Execute(Video::Output*,Sound::Output*,Input::Controllers*); private: void Reset(bool); void LinkPorts(bool=true); void ChangeDirection(); enum { NUM_KEYS = 60, LAST_KEY = NUM_KEYS-1, NUM_FRAMES = 60, LAST_FRAME = NUM_FRAMES-1 }; class Key { class Input { typedef Vector Buffer; enum { BAD_POS = INT_MAX, MIN_COMPRESSION_SIZE = 1024, OPEN_BUS = 0x40 }; dword pos; Buffer buffer; public: void Reset(); inline void BeginForward(); bool EndForward(); void BeginBackward(); inline void EndBackward(); inline uint Put(uint); inline uint Get(); inline void ResumeForward(); inline bool CanRewind() const; inline void Invalidate(); }; Input input; std::stringstream stream; public: Key(); ~Key(); void Reset(); void BeginForward(Machine&,EmuSaveState,EmuLoadState); void EndForward(); void BeginBackward(Machine&,EmuLoadState); inline void EndBackward(); inline uint Put(uint); inline uint Get(); inline bool CanRewind() const; inline void ResumeForward(); inline void TurnForward(Machine&,EmuLoadState); inline void Invalidate(); }; class ReverseVideo { public: explicit ReverseVideo(Ppu&); ~ReverseVideo(); class Mutex; void Begin(); void End(); void Store(); inline void Flush(const Mutex&); private: class Buffer; uint pingpong; uint frame; Ppu& ppu; Buffer* buffer; }; class ReverseSound { public: typedef Sound::Output Output; ReverseSound(const Apu&,bool); ~ReverseSound(); class Mutex; void Begin(); void End(); void Enable(bool); Output* Store(); void Flush(Output*,const Mutex&); private: template const void* ReverseCopy(const Output&) const; template void ReverseSilence(const Output&) const; template NST_FORCE_INLINE Output* StoreType(); bool Update(); bool enabled; bool good; byte stereo; byte bits; dword rate; uint index; void* buffer; dword size; Output output; const void* input; const Apu& apu; public: bool IsRewinding() const { return enabled && good && buffer; } }; inline Key* PrevKey(Key*); inline Key* PrevKey(); inline Key* NextKey(Key*); inline Key* NextKey(); NES_DECL_PEEK( Port_Get ); NES_DECL_PEEK( Port_Put ); NES_DECL_POKE( Port ); ibool rewinding; ibool uturn; uint frame; const Io::Port* ports[2]; Key* key; Key keys[NUM_KEYS]; ReverseSound sound; ReverseVideo video; Machine& emulator; const EmuExecute emuExecute; const EmuLoadState emuLoadState; const EmuSaveState emuSaveState; Cpu& cpu; Ppu& ppu; public: void Reset() { Reset( true ); } void Unload() { Reset( false ); } void EnableSound(bool enable) { sound.Enable( enable ); } bool IsRewinding() const { return rewinding; } bool IsSoundRewinding() const { return rewinding && sound.IsRewinding(); } }; } } #endif nestopia-1.51.1/source/core/NstVector.cpp000066400000000000000000000034611411157722000203100ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include #include "NstVector.hpp" namespace Nes { namespace Core { void* Vector::Malloc(dword size) { NST_ASSERT( size ); if (void* mem = std::malloc( size )) return mem; else throw std::bad_alloc(); } void* Vector::Realloc(void* mem,dword size) { NST_ASSERT( size ); if (NULL != (mem = std::realloc( mem, size ))) return mem; else throw std::bad_alloc(); } void Vector::Free(void* mem) { std::free( mem ); } void Vector::Copy(void* dst,const void* src,dword size) { std::memcpy( dst, src, size ); } void Vector::Move(void* dst,const void* src,dword size) { std::memmove( dst, src, size ); } } } nestopia-1.51.1/source/core/NstVector.hpp000066400000000000000000000171101411157722000203110ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_VECTOR_H #define NST_VECTOR_H #ifndef NST_ASSERT_H #include "NstAssert.hpp" #endif #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { template class Vector; template<> class Vector { public: static void* Malloc(dword); static void* Realloc(void*,dword); static void Free(void*); static void Copy(void*,const void*,dword); static void Move(void*,const void*,dword); template static void Copy(T& dst,const T& src) { Copy( &dst, &src, sizeof(T) ); } }; template<> inline void Vector::Copy(char& dst,const char& src) { dst = src; } template<> inline void Vector::Copy(schar& dst,const schar& src) { dst = src; } template<> inline void Vector::Copy(uchar& dst,const uchar& src) { dst = src; } template<> inline void Vector::Copy(short& dst,const short& src) { dst = src; } template<> inline void Vector::Copy(ushort& dst,const ushort& src) { dst = src; } template<> inline void Vector::Copy(int& dst,const int& src) { dst = src; } template<> inline void Vector::Copy(uint& dst,const uint& src) { dst = src; } template<> inline void Vector::Copy(long& dst,const long& src) { dst = src; } template<> inline void Vector::Copy(ulong& dst,const ulong& src) { dst = src; } template class Vector { T* data; dword size; dword capacity; void MakeRoom(dword); typedef Vector Allocator; public: typedef T Type; Vector(); explicit Vector(dword); Vector(const Vector&); Vector(const T*,dword); bool operator == (const Vector&) const; void Reserve(dword); void Resize(dword); void Expand(dword); void Assign(const T*,dword); void Append(const T&); void Append(const T*,dword); T* Insert(T*,const T&); void Erase(T*,dword=1); void Destroy(); void Defrag(); static void Swap(Vector&,Vector&); ~Vector() { Allocator::Free( data ); } void operator = (const Vector& vector) { Assign( vector.data, vector.size ); } void operator += (const Vector& vector) { Append( vector.data, vector.size ); } T& operator [] (dword i) const { NST_ASSERT( i < size ); return data[i]; } T* Begin() const { return data; } T* End() const { return data + size; } dword Size() const { return size; } dword Capacity() const { return capacity; } T& Front() const { NST_ASSERT( size ); return data[0]; } T& Back() const { NST_ASSERT( size ); return data[size - 1]; } const T& Pop() { NST_ASSERT( size ); return data[--size]; } void SetTo(dword count) { NST_ASSERT( count <= capacity ); size = count; } void Clear() { size = 0; } }; template Vector::Vector() : data(NULL), size(0), capacity(0) {} template Vector::Vector(const dword count) : data(count ? static_cast(Allocator::Malloc(count * sizeof(T))) : NULL), size(count), capacity(count) { } template Vector::Vector(const T* in,const dword count) : data(count ? static_cast(Allocator::Malloc(count * sizeof(T))) : NULL), size(count), capacity(count) { Allocator::Copy( data, in, count * sizeof(T) ); } template Vector::Vector(const Vector& v) : data(v.size ? static_cast(Allocator::Malloc(v.size * sizeof(T))) : NULL), size(v.size), capacity(v.size) { Allocator::Copy( data, v.data, v.size * sizeof(T) ); } template void Vector::MakeRoom(const dword count) { NST_ASSERT( count ); data = static_cast(Allocator::Realloc( data, count * sizeof(T) )); capacity = count; } template void Vector::Append(const T& value) { if (size == capacity) MakeRoom( (size + 1) * 2 ); Allocator::Copy( data[size++], value ); } template void Vector::Assign(const T* const NST_RESTRICT inData,const dword inSize) { if (capacity < inSize) MakeRoom( inSize ); Allocator::Copy( data, inData, (size=inSize) * sizeof(T) ); } template void Vector::Append(const T* const NST_RESTRICT inData,const dword inSize) { if (capacity < size + inSize) MakeRoom( (size * 2) + inSize ); void* const tmp = data + size; size += inSize; Allocator::Copy( tmp, inData, inSize * sizeof(T) ); } template T* Vector::Insert(T* it,const T& value) { const dword pos = it - data; if (size++ == capacity) MakeRoom( size * 2 ); Allocator::Move( data+pos+1, data+pos, (size - (pos+1)) * sizeof(T) ); Allocator::Copy( data[pos], value ); return data+pos; } template void Vector::Erase(T* it,dword count) { NST_ASSERT( size >= count ); const dword s = size; size -= count; Allocator::Move( it, it + count, (s - ((it-data) + count)) * sizeof(T) ); } template void Vector::Reserve(dword count) { if (capacity < count) MakeRoom( count ); } template void Vector::Resize(dword count) { Reserve( count ); size = count; } template void Vector::Expand(dword count) { Reserve( size + count ); size += count; } template void Vector::Defrag() { if (size) { MakeRoom( size ); } else if (void* const tmp = data) { data = NULL; capacity = 0; Allocator::Free( tmp ); } } template bool Vector::operator == (const Vector& vector) const { if (size != vector.size) return false; for (const T *a=data, *b=vector.data, *const end=data+size; a != end; ++a, ++b) { if (!(*a == *b)) return false; } return true; } template void Vector::Destroy() { if (void* const tmp = data) { data = NULL; size = 0; capacity = 0; Allocator::Free( tmp ); } } template void Vector::Swap(Vector& a,Vector& b) { T* t = a.data; a.data = b.data; b.data = t; dword u = a.size; a.size = b.size; b.size = u; u = a.capacity; a.capacity = b.capacity; b.capacity = u; } } } #endif nestopia-1.51.1/source/core/NstVideoFilter2xSaI.cpp000066400000000000000000000154331411157722000221330ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2001 Derek Liauw Kie Fa // Copyright (C) 2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstAssert.hpp" #ifndef NST_NO_2XSAI #include "NstVideoRenderer.hpp" #include "NstVideoFilter2xSaI.hpp" namespace Nes { namespace Core { namespace Video { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Renderer::Filter2xSaI::Filter2xSaI(const RenderState& state) : Filter (state), lsb0 (~((1UL << format.shifts[0]) | (1UL << format.shifts[1]) | (1UL << format.shifts[2]))), lsb1 (~((3UL << format.shifts[0]) | (3UL << format.shifts[1]) | (3UL << format.shifts[2]))) { } bool Renderer::Filter2xSaI::Check(const RenderState& state) { return ( (state.bits.count == 16 || state.bits.count == 32) && (state.filter == RenderState::FILTER_2XSAI && state.width == WIDTH*2 && state.height == HEIGHT*2) ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif inline dword Renderer::Filter2xSaI::Blend(dword a,dword b) const { return (a != b) ? ((a & lsb0) >> 1) + ((b & lsb0) >> 1) + (a & b & ~lsb0) : a; } inline dword Renderer::Filter2xSaI::Blend(dword a,dword b,dword c,dword d) const { return ( (((a & lsb1) >> 2) + ((b & lsb1) >> 2) + ((c & lsb1) >> 2) + ((d & lsb1) >> 2)) + ((((a & ~lsb1) + (b & ~lsb1) + (c & ~lsb1) + (d & ~lsb1)) >> 2) & ~lsb1) ); } template void Renderer::Filter2xSaI::BlitType(const Input& input,const Output& output) const { const word* NST_RESTRICT src = input.pixels; const long pitch = output.pitch; T* NST_RESTRICT dst[2] = { static_cast(output.pixels), reinterpret_cast(static_cast(output.pixels) + pitch) }; dword a,b,c,d,e=0,f=0,g,h,i=0,j=0,k,l,m,n,o; for (uint y=0; y < HEIGHT; ++y) { for (uint x=0; x < WIDTH; ++x, ++src, dst[0] += 2, dst[1] += 2) { if (y) { i = x > 0 ? input.palette[src[ -WIDTH-1 ]] : 0; e = input.palette[src[ -WIDTH ]]; f = x < WIDTH-1 ? input.palette[src[ -WIDTH+1 ]] : 0; j = x < WIDTH-2 ? input.palette[src[ -WIDTH+2 ]] : 0; } g = x > 0 ? input.palette[src[ -1 ]] : 0; a = input.palette[src[ 0 ]]; b = x < WIDTH-1 ? input.palette[src[ 1 ]] : 0; k = x < WIDTH-2 ? input.palette[src[ 2 ]] : 0; if (y < HEIGHT-1) { h = x > 0 ? input.palette[src[ WIDTH-1 ]] : 0; c = input.palette[src[ WIDTH ]]; d = x < WIDTH-1 ? input.palette[src[ WIDTH+1 ]] : 0; l = x < WIDTH-2 ? input.palette[src[ WIDTH+2 ]] : 0; if (y < HEIGHT-2) { m = x > 0 ? input.palette[src[ WIDTH*2-1 ]] : 0; n = input.palette[src[ WIDTH*2 ]]; o = x < WIDTH-1 ? input.palette[src[ WIDTH*2+1 ]] : 0; } else { m = n = o = 0; } } else { h = c = d = l = m = n = o = 0; } dword q[3]; if (a == d && b != c) { if ((a == e && b == l) || (a == c && a == f && b != e && b == j)) { q[0] = a; } else { q[0] = Blend( a, b ); } if ((a == g && c == o) || (a == b && a == h && g != c && c == m)) { q[1] = a; } else { q[1] = Blend( a, c ); } q[2] = a; } else if (b == c && a != d) { if ((b == f && a == h) || (b == e && b == d && a != f && a == i)) { q[0] = b; } else { q[0] = Blend( a, b ); } if ((c == h && a == f) || (c == g && c == d && a != h && a == i)) { q[1] = c; } else { q[1] = Blend( a, c ); } q[2] = b; } else if (a == d && b == c) { if (a == b) { q[0] = a; q[1] = a; q[2] = a; } else { q[1] = Blend( a, c ); q[0] = Blend( a, b ); const int result = ( (a == g && a == e ? -1 : b == g && b == e ? +1 : 0) + (b == k && b == f ? -1 : a == k && a == f ? +1 : 0) + (b == h && b == n ? -1 : a == h && a == n ? +1 : 0) + (a == l && a == o ? -1 : b == l && b == o ? +1 : 0) ); if (result > 0) { q[2] = a; } else if (result < 0) { q[2] = b; } else { q[2] = Blend( a, b, c, d ); } } } else { q[2] = Blend( a, b, c, d ); if (a == c && a == f && b != e && b == j) { q[0] = a; } else if (b == e && b == d && a != f && a == i) { q[0] = b; } else { q[0] = Blend( a, b ); } if (a == b && a == h && g != c && c == m) { q[1] = a; } else if (c == g && c == d && a != h && a == i) { q[1] = c; } else { q[1] = Blend( a, c ); } } dst[0][0] = a; dst[0][1] = q[0]; dst[1][0] = q[1]; dst[1][1] = q[2]; } dst[0] = reinterpret_cast(reinterpret_cast(dst[1]) + (pitch - long(sizeof(T) * WIDTH*2))); dst[1] = reinterpret_cast(reinterpret_cast(dst[0]) + pitch); } } void Renderer::Filter2xSaI::Blit(const Input& input,const Output& output,uint) { switch (format.bpp) { case 32: BlitType< dword >( input, output ); break; case 16: BlitType< word >( input, output ); break; default: NST_UNREACHABLE(); } } } } } #endif nestopia-1.51.1/source/core/NstVideoFilter2xSaI.hpp000066400000000000000000000032721411157722000221360ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2006 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_VIDEO_FILTER_2XSAI_H #define NST_VIDEO_FILTER_2XSAI_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Video { class Renderer::Filter2xSaI : public Renderer::Filter { public: explicit Filter2xSaI(const RenderState&); static bool Check(const RenderState&); private: void Blit(const Input&,const Output&,uint); template void BlitType(const Input&,const Output&) const; inline dword Blend(dword,dword) const; inline dword Blend(dword,dword,dword,dword) const; const dword lsb0; const dword lsb1; }; } } } #endif nestopia-1.51.1/source/core/NstVideoFilterHq2x.inl000066400000000000000000000755671411157722000220450ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003 MaxSt ( maxst@hiend3d.com ) // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// switch ( (b.w[4] != b.w[0] && ((yuv5 - lut.yuv[b.w[0]]) & Lut::YUV_MASK) ? 0x01U : 0x0U) | (b.w[4] != b.w[1] && ((yuv5 - lut.yuv[b.w[1]]) & Lut::YUV_MASK) ? 0x02U : 0x0U) | (b.w[4] != b.w[2] && ((yuv5 - lut.yuv[b.w[2]]) & Lut::YUV_MASK) ? 0x04U : 0x0U) | (b.w[4] != b.w[3] && ((yuv5 - lut.yuv[b.w[3]]) & Lut::YUV_MASK) ? 0x08U : 0x0U) | (b.w[4] != b.w[5] && ((yuv5 - lut.yuv[b.w[5]]) & Lut::YUV_MASK) ? 0x10U : 0x0U) | (b.w[4] != b.w[6] && ((yuv5 - lut.yuv[b.w[6]]) & Lut::YUV_MASK) ? 0x20U : 0x0U) | (b.w[4] != b.w[7] && ((yuv5 - lut.yuv[b.w[7]]) & Lut::YUV_MASK) ? 0x40U : 0x0U) | (b.w[4] != b.w[8] && ((yuv5 - lut.yuv[b.w[8]]) & Lut::YUV_MASK) ? 0x80U : 0x0U) ) #define PIXEL00_0 dst[0][0] = b.c[4]; #define PIXEL00_10 dst[0][0] = Interpolate1( b.c[4], b.c[0] ); #define PIXEL00_11 dst[0][0] = Interpolate1( b.c[4], b.c[3] ); #define PIXEL00_12 dst[0][0] = Interpolate1( b.c[4], b.c[1] ); #define PIXEL00_20 dst[0][0] = Interpolate2( b.c[4], b.c[3], b.c[1] ); #define PIXEL00_21 dst[0][0] = Interpolate2( b.c[4], b.c[0], b.c[1] ); #define PIXEL00_22 dst[0][0] = Interpolate2( b.c[4], b.c[0], b.c[3] ); #define PIXEL00_60 dst[0][0] = Interpolate6( b.c[4], b.c[1], b.c[3] ); #define PIXEL00_61 dst[0][0] = Interpolate6( b.c[4], b.c[3], b.c[1] ); #define PIXEL00_70 dst[0][0] = Interpolate7( b.c[4], b.c[3], b.c[1] ); #define PIXEL00_90 dst[0][0] = Interpolate9( b.c[4], b.c[3], b.c[1] ); #define PIXEL00_100 dst[0][0] = Interpolate10( b.c[4], b.c[3], b.c[1] ); #define PIXEL01_0 dst[0][1] = b.c[4]; #define PIXEL01_10 dst[0][1] = Interpolate1( b.c[4], b.c[2] ); #define PIXEL01_11 dst[0][1] = Interpolate1( b.c[4], b.c[1] ); #define PIXEL01_12 dst[0][1] = Interpolate1( b.c[4], b.c[5] ); #define PIXEL01_20 dst[0][1] = Interpolate2( b.c[4], b.c[1], b.c[5] ); #define PIXEL01_21 dst[0][1] = Interpolate2( b.c[4], b.c[2], b.c[5] ); #define PIXEL01_22 dst[0][1] = Interpolate2( b.c[4], b.c[2], b.c[1] ); #define PIXEL01_60 dst[0][1] = Interpolate6( b.c[4], b.c[5], b.c[1] ); #define PIXEL01_61 dst[0][1] = Interpolate6( b.c[4], b.c[1], b.c[5] ); #define PIXEL01_70 dst[0][1] = Interpolate7( b.c[4], b.c[1], b.c[5] ); #define PIXEL01_90 dst[0][1] = Interpolate9( b.c[4], b.c[1], b.c[5] ); #define PIXEL01_100 dst[0][1] = Interpolate10( b.c[4], b.c[1], b.c[5] ); #define PIXEL10_0 dst[1][0] = b.c[4]; #define PIXEL10_10 dst[1][0] = Interpolate1( b.c[4], b.c[6] ); #define PIXEL10_11 dst[1][0] = Interpolate1( b.c[4], b.c[7] ); #define PIXEL10_12 dst[1][0] = Interpolate1( b.c[4], b.c[3] ); #define PIXEL10_20 dst[1][0] = Interpolate2( b.c[4], b.c[7], b.c[3] ); #define PIXEL10_21 dst[1][0] = Interpolate2( b.c[4], b.c[6], b.c[3] ); #define PIXEL10_22 dst[1][0] = Interpolate2( b.c[4], b.c[6], b.c[7] ); #define PIXEL10_60 dst[1][0] = Interpolate6( b.c[4], b.c[3], b.c[7] ); #define PIXEL10_61 dst[1][0] = Interpolate6( b.c[4], b.c[7], b.c[3] ); #define PIXEL10_70 dst[1][0] = Interpolate7( b.c[4], b.c[7], b.c[3] ); #define PIXEL10_90 dst[1][0] = Interpolate9( b.c[4], b.c[7], b.c[3] ); #define PIXEL10_100 dst[1][0] = Interpolate10( b.c[4], b.c[7], b.c[3] ); #define PIXEL11_0 dst[1][1] = b.c[4]; #define PIXEL11_10 dst[1][1] = Interpolate1( b.c[4], b.c[8] ); #define PIXEL11_11 dst[1][1] = Interpolate1( b.c[4], b.c[5] ); #define PIXEL11_12 dst[1][1] = Interpolate1( b.c[4], b.c[7] ); #define PIXEL11_20 dst[1][1] = Interpolate2( b.c[4], b.c[5], b.c[7] ); #define PIXEL11_21 dst[1][1] = Interpolate2( b.c[4], b.c[8], b.c[7] ); #define PIXEL11_22 dst[1][1] = Interpolate2( b.c[4], b.c[8], b.c[5] ); #define PIXEL11_60 dst[1][1] = Interpolate6( b.c[4], b.c[7], b.c[5] ); #define PIXEL11_61 dst[1][1] = Interpolate6( b.c[4], b.c[5], b.c[7] ); #define PIXEL11_70 dst[1][1] = Interpolate7( b.c[4], b.c[5], b.c[7] ); #define PIXEL11_90 dst[1][1] = Interpolate9( b.c[4], b.c[5], b.c[7] ); #define PIXEL11_100 dst[1][1] = Interpolate10( b.c[4], b.c[5], b.c[7] ); { case 0: case 1: case 4: case 32: case 128: case 5: case 132: case 160: case 33: case 129: case 36: case 133: case 164: case 161: case 37: case 165: PIXEL00_20 PIXEL01_20 PIXEL10_20 PIXEL11_20 break; case 2: case 34: case 130: case 162: PIXEL00_22 PIXEL01_21 PIXEL10_20 PIXEL11_20 break; case 16: case 17: case 48: case 49: PIXEL00_20 PIXEL01_22 PIXEL10_20 PIXEL11_21 break; case 64: case 65: case 68: case 69: PIXEL00_20 PIXEL01_20 PIXEL10_21 PIXEL11_22 break; case 8: case 12: case 136: case 140: PIXEL00_21 PIXEL01_20 PIXEL10_22 PIXEL11_20 break; case 3: case 35: case 131: case 163: PIXEL00_11 PIXEL01_21 PIXEL10_20 PIXEL11_20 break; case 6: case 38: case 134: case 166: PIXEL00_22 PIXEL01_12 PIXEL10_20 PIXEL11_20 break; case 20: case 21: case 52: case 53: PIXEL00_20 PIXEL01_11 PIXEL10_20 PIXEL11_21 break; case 144: case 145: case 176: case 177: PIXEL00_20 PIXEL01_22 PIXEL10_20 PIXEL11_12 break; case 192: case 193: case 196: case 197: PIXEL00_20 PIXEL01_20 PIXEL10_21 PIXEL11_11 break; case 96: case 97: case 100: case 101: PIXEL00_20 PIXEL01_20 PIXEL10_12 PIXEL11_22 break; case 40: case 44: case 168: case 172: PIXEL00_21 PIXEL01_20 PIXEL10_11 PIXEL11_20 break; case 9: case 13: case 137: case 141: PIXEL00_12 PIXEL01_20 PIXEL10_22 PIXEL11_20 break; case 18: case 50: PIXEL00_22 if (Diff( b.w[1], b.w[5] )) PIXEL01_10 else PIXEL01_20 PIXEL10_20 PIXEL11_21 break; case 80: case 81: PIXEL00_20 PIXEL01_22 PIXEL10_21 if (Diff( b.w[5], b.w[7] )) PIXEL11_10 else PIXEL11_20 break; case 72: case 76: PIXEL00_21 PIXEL01_20 if (Diff( b.w[7], b.w[3] )) PIXEL10_10 else PIXEL10_20 PIXEL11_22 break; case 10: case 138: if (Diff( b.w[3], b.w[1] )) PIXEL00_10 else PIXEL00_20 PIXEL01_21 PIXEL10_22 PIXEL11_20 break; case 66: PIXEL00_22 PIXEL01_21 PIXEL10_21 PIXEL11_22 break; case 24: PIXEL00_21 PIXEL01_22 PIXEL10_22 PIXEL11_21 break; case 7: case 39: case 135: PIXEL00_11 PIXEL01_12 PIXEL10_20 PIXEL11_20 break; case 148: case 149: case 180: PIXEL00_20 PIXEL01_11 PIXEL10_20 PIXEL11_12 break; case 224: case 228: case 225: PIXEL00_20 PIXEL01_20 PIXEL10_12 PIXEL11_11 break; case 41: case 169: case 45: PIXEL00_12 PIXEL01_20 PIXEL10_11 PIXEL11_20 break; case 22: case 54: PIXEL00_22 if (Diff( b.w[1], b.w[5] )) PIXEL01_0 else PIXEL01_20 PIXEL10_20 PIXEL11_21 break; case 208: case 209: PIXEL00_20 PIXEL01_22 PIXEL10_21 if (Diff( b.w[5], b.w[7] )) PIXEL11_0 else PIXEL11_20 break; case 104: case 108: PIXEL00_21 PIXEL01_20 if (Diff( b.w[7], b.w[3] )) PIXEL10_0 else PIXEL10_20 PIXEL11_22 break; case 11: case 139: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_20 PIXEL01_21 PIXEL10_22 PIXEL11_20 break; case 19: case 51: if (Diff( b.w[1], b.w[5] )) { PIXEL00_11 PIXEL01_10 } else { PIXEL00_60 PIXEL01_90 } PIXEL10_20 PIXEL11_21 break; case 146: case 178: PIXEL00_22 if (Diff( b.w[1], b.w[5] )) { PIXEL01_10 PIXEL11_12 } else { PIXEL01_90 PIXEL11_61 } PIXEL10_20 break; case 84: case 85: PIXEL00_20 if (Diff( b.w[5], b.w[7] )) { PIXEL01_11 PIXEL11_10 } else { PIXEL01_60 PIXEL11_90 } PIXEL10_21 break; case 112: case 113: PIXEL00_20 PIXEL01_22 if (Diff( b.w[5], b.w[7] )) { PIXEL10_12 PIXEL11_10 } else { PIXEL10_61 PIXEL11_90 } break; case 200: case 204: PIXEL00_21 PIXEL01_20 if (Diff( b.w[7], b.w[3] )) { PIXEL10_10 PIXEL11_11 } else { PIXEL10_90 PIXEL11_60 } break; case 73: case 77: if (Diff( b.w[7], b.w[3] )) { PIXEL00_12 PIXEL10_10 } else { PIXEL00_61 PIXEL10_90 } PIXEL01_20 PIXEL11_22 break; case 42: case 170: if (Diff( b.w[3], b.w[1] )) { PIXEL00_10 PIXEL10_11 } else { PIXEL00_90 PIXEL10_60 } PIXEL01_21 PIXEL11_20 break; case 14: case 142: if (Diff( b.w[3], b.w[1] )) { PIXEL00_10 PIXEL01_12 } else { PIXEL00_90 PIXEL01_61 } PIXEL10_22 PIXEL11_20 break; case 67: PIXEL00_11 PIXEL01_21 PIXEL10_21 PIXEL11_22 break; case 70: PIXEL00_22 PIXEL01_12 PIXEL10_21 PIXEL11_22 break; case 28: PIXEL00_21 PIXEL01_11 PIXEL10_22 PIXEL11_21 break; case 152: PIXEL00_21 PIXEL01_22 PIXEL10_22 PIXEL11_12 break; case 194: PIXEL00_22 PIXEL01_21 PIXEL10_21 PIXEL11_11 break; case 98: PIXEL00_22 PIXEL01_21 PIXEL10_12 PIXEL11_22 break; case 56: PIXEL00_21 PIXEL01_22 PIXEL10_11 PIXEL11_21 break; case 25: PIXEL00_12 PIXEL01_22 PIXEL10_22 PIXEL11_21 break; case 26: case 31: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_20 if (Diff( b.w[1], b.w[5] )) PIXEL01_0 else PIXEL01_20 PIXEL10_22 PIXEL11_21 break; case 82: case 214: PIXEL00_22 if (Diff( b.w[1], b.w[5] )) PIXEL01_0 else PIXEL01_20 PIXEL10_21 if (Diff( b.w[5], b.w[7] )) PIXEL11_0 else PIXEL11_20 break; case 88: case 248: PIXEL00_21 PIXEL01_22 if (Diff( b.w[7], b.w[3] )) PIXEL10_0 else PIXEL10_20 if (Diff( b.w[5], b.w[7] )) PIXEL11_0 else PIXEL11_20 break; case 74: case 107: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_20 PIXEL01_21 if (Diff( b.w[7], b.w[3] )) PIXEL10_0 else PIXEL10_20 PIXEL11_22 break; case 27: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_20 PIXEL01_10 PIXEL10_22 PIXEL11_21 break; case 86: PIXEL00_22 if (Diff( b.w[1], b.w[5] )) PIXEL01_0 else PIXEL01_20 PIXEL10_21 PIXEL11_10 break; case 216: PIXEL00_21 PIXEL01_22 PIXEL10_10 if (Diff( b.w[5], b.w[7] )) PIXEL11_0 else PIXEL11_20 break; case 106: PIXEL00_10 PIXEL01_21 if (Diff( b.w[7], b.w[3] )) PIXEL10_0 else PIXEL10_20 PIXEL11_22 break; case 30: PIXEL00_10 if (Diff( b.w[1], b.w[5] )) PIXEL01_0 else PIXEL01_20 PIXEL10_22 PIXEL11_21 break; case 210: PIXEL00_22 PIXEL01_10 PIXEL10_21 if (Diff( b.w[5], b.w[7] )) PIXEL11_0 else PIXEL11_20 break; case 120: PIXEL00_21 PIXEL01_22 if (Diff( b.w[7], b.w[3] )) PIXEL10_0 else PIXEL10_20 PIXEL11_10 break; case 75: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_20 PIXEL01_21 PIXEL10_10 PIXEL11_22 break; case 29: PIXEL00_12 PIXEL01_11 PIXEL10_22 PIXEL11_21 break; case 198: PIXEL00_22 PIXEL01_12 PIXEL10_21 PIXEL11_11 break; case 184: PIXEL00_21 PIXEL01_22 PIXEL10_11 PIXEL11_12 break; case 99: PIXEL00_11 PIXEL01_21 PIXEL10_12 PIXEL11_22 break; case 57: PIXEL00_12 PIXEL01_22 PIXEL10_11 PIXEL11_21 break; case 71: PIXEL00_11 PIXEL01_12 PIXEL10_21 PIXEL11_22 break; case 156: PIXEL00_21 PIXEL01_11 PIXEL10_22 PIXEL11_12 break; case 226: PIXEL00_22 PIXEL01_21 PIXEL10_12 PIXEL11_11 break; case 60: PIXEL00_21 PIXEL01_11 PIXEL10_11 PIXEL11_21 break; case 195: PIXEL00_11 PIXEL01_21 PIXEL10_21 PIXEL11_11 break; case 102: PIXEL00_22 PIXEL01_12 PIXEL10_12 PIXEL11_22 break; case 153: PIXEL00_12 PIXEL01_22 PIXEL10_22 PIXEL11_12 break; case 58: if (Diff( b.w[3], b.w[1] )) PIXEL00_10 else PIXEL00_70 if (Diff( b.w[1], b.w[5] )) PIXEL01_10 else PIXEL01_70 PIXEL10_11 PIXEL11_21 break; case 83: PIXEL00_11 if (Diff( b.w[1], b.w[5] )) PIXEL01_10 else PIXEL01_70 PIXEL10_21 if (Diff( b.w[5], b.w[7] )) PIXEL11_10 else PIXEL11_70 break; case 92: PIXEL00_21 PIXEL01_11 if (Diff( b.w[7], b.w[3] )) PIXEL10_10 else PIXEL10_70 if (Diff( b.w[5], b.w[7] )) PIXEL11_10 else PIXEL11_70 break; case 202: if (Diff( b.w[3], b.w[1] )) PIXEL00_10 else PIXEL00_70 PIXEL01_21 if (Diff( b.w[7], b.w[3] )) PIXEL10_10 else PIXEL10_70 PIXEL11_11 break; case 78: if (Diff( b.w[3], b.w[1] )) PIXEL00_10 else PIXEL00_70 PIXEL01_12 if (Diff( b.w[7], b.w[3] )) PIXEL10_10 else PIXEL10_70 PIXEL11_22 break; case 154: if (Diff( b.w[3], b.w[1] )) PIXEL00_10 else PIXEL00_70 if (Diff( b.w[1], b.w[5] )) PIXEL01_10 else PIXEL01_70 PIXEL10_22 PIXEL11_12 break; case 114: PIXEL00_22 if (Diff( b.w[1], b.w[5] )) PIXEL01_10 else PIXEL01_70 PIXEL10_12 if (Diff( b.w[5], b.w[7] )) PIXEL11_10 else PIXEL11_70 break; case 89: PIXEL00_12 PIXEL01_22 if (Diff( b.w[7], b.w[3] )) PIXEL10_10 else PIXEL10_70 if (Diff( b.w[5], b.w[7] )) PIXEL11_10 else PIXEL11_70 break; case 90: if (Diff( b.w[3], b.w[1] )) PIXEL00_10 else PIXEL00_70 if (Diff( b.w[1], b.w[5] )) PIXEL01_10 else PIXEL01_70 if (Diff( b.w[7], b.w[3] )) PIXEL10_10 else PIXEL10_70 if (Diff( b.w[5], b.w[7] )) PIXEL11_10 else PIXEL11_70 break; case 55: case 23: if (Diff( b.w[1], b.w[5] )) { PIXEL00_11 PIXEL01_0 } else { PIXEL00_60 PIXEL01_90 } PIXEL10_20 PIXEL11_21 break; case 182: case 150: PIXEL00_22 if (Diff( b.w[1], b.w[5] )) { PIXEL01_0 PIXEL11_12 } else { PIXEL01_90 PIXEL11_61 } PIXEL10_20 break; case 213: case 212: PIXEL00_20 if (Diff( b.w[5], b.w[7] )) { PIXEL01_11 PIXEL11_0 } else { PIXEL01_60 PIXEL11_90 } PIXEL10_21 break; case 241: case 240: PIXEL00_20 PIXEL01_22 if (Diff( b.w[5], b.w[7] )) { PIXEL10_12 PIXEL11_0 } else { PIXEL10_61 PIXEL11_90 } break; case 236: case 232: PIXEL00_21 PIXEL01_20 if (Diff( b.w[7], b.w[3] )) { PIXEL10_0 PIXEL11_11 } else { PIXEL10_90 PIXEL11_60 } break; case 109: case 105: if (Diff( b.w[7], b.w[3] )) { PIXEL00_12 PIXEL10_0 } else { PIXEL00_61 PIXEL10_90 } PIXEL01_20 PIXEL11_22 break; case 171: case 43: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL10_11 } else { PIXEL00_90 PIXEL10_60 } PIXEL01_21 PIXEL11_20 break; case 143: case 15: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL01_12 } else { PIXEL00_90 PIXEL01_61 } PIXEL10_22 PIXEL11_20 break; case 124: PIXEL00_21 PIXEL01_11 if (Diff( b.w[7], b.w[3] )) PIXEL10_0 else PIXEL10_20 PIXEL11_10 break; case 203: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_20 PIXEL01_21 PIXEL10_10 PIXEL11_11 break; case 62: PIXEL00_10 if (Diff( b.w[1], b.w[5] )) PIXEL01_0 else PIXEL01_20 PIXEL10_11 PIXEL11_21 break; case 211: PIXEL00_11 PIXEL01_10 PIXEL10_21 if (Diff( b.w[5], b.w[7] )) PIXEL11_0 else PIXEL11_20 break; case 118: PIXEL00_22 if (Diff( b.w[1], b.w[5] )) PIXEL01_0 else PIXEL01_20 PIXEL10_12 PIXEL11_10 break; case 217: PIXEL00_12 PIXEL01_22 PIXEL10_10 if (Diff( b.w[5], b.w[7] )) PIXEL11_0 else PIXEL11_20 break; case 110: PIXEL00_10 PIXEL01_12 if (Diff( b.w[7], b.w[3] )) PIXEL10_0 else PIXEL10_20 PIXEL11_22 break; case 155: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_20 PIXEL01_10 PIXEL10_22 PIXEL11_12 break; case 188: PIXEL00_21 PIXEL01_11 PIXEL10_11 PIXEL11_12 break; case 185: PIXEL00_12 PIXEL01_22 PIXEL10_11 PIXEL11_12 break; case 61: PIXEL00_12 PIXEL01_11 PIXEL10_11 PIXEL11_21 break; case 157: PIXEL00_12 PIXEL01_11 PIXEL10_22 PIXEL11_12 break; case 103: PIXEL00_11 PIXEL01_12 PIXEL10_12 PIXEL11_22 break; case 227: PIXEL00_11 PIXEL01_21 PIXEL10_12 PIXEL11_11 break; case 230: PIXEL00_22 PIXEL01_12 PIXEL10_12 PIXEL11_11 break; case 199: PIXEL00_11 PIXEL01_12 PIXEL10_21 PIXEL11_11 break; case 220: PIXEL00_21 PIXEL01_11 if (Diff( b.w[7], b.w[3] )) PIXEL10_10 else PIXEL10_70 if (Diff( b.w[5], b.w[7] )) PIXEL11_0 else PIXEL11_20 break; case 158: if (Diff( b.w[3], b.w[1] )) PIXEL00_10 else PIXEL00_70 if (Diff( b.w[1], b.w[5] )) PIXEL01_0 else PIXEL01_20 PIXEL10_22 PIXEL11_12 break; case 234: if (Diff( b.w[3], b.w[1] )) PIXEL00_10 else PIXEL00_70 PIXEL01_21 if (Diff( b.w[7], b.w[3] )) PIXEL10_0 else PIXEL10_20 PIXEL11_11 break; case 242: PIXEL00_22 if (Diff( b.w[1], b.w[5] )) PIXEL01_10 else PIXEL01_70 PIXEL10_12 if (Diff( b.w[5], b.w[7] )) PIXEL11_0 else PIXEL11_20 break; case 59: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_20 if (Diff( b.w[1], b.w[5] )) PIXEL01_10 else PIXEL01_70 PIXEL10_11 PIXEL11_21 break; case 121: PIXEL00_12 PIXEL01_22 if (Diff( b.w[7], b.w[3] )) PIXEL10_0 else PIXEL10_20 if (Diff( b.w[5], b.w[7])) PIXEL11_10 else PIXEL11_70 break; case 87: PIXEL00_11 if (Diff( b.w[1], b.w[5] )) PIXEL01_0 else PIXEL01_20 PIXEL10_21 if (Diff( b.w[5], b.w[7] )) PIXEL11_10 else PIXEL11_70 break; case 79: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_20 PIXEL01_12 if (Diff( b.w[7], b.w[3] )) PIXEL10_10 else PIXEL10_70 PIXEL11_22 break; case 122: if (Diff( b.w[3], b.w[1] )) PIXEL00_10 else PIXEL00_70 if (Diff( b.w[1], b.w[5] )) PIXEL01_10 else PIXEL01_70 if (Diff( b.w[7], b.w[3] )) PIXEL10_0 else PIXEL10_20 if (Diff( b.w[5], b.w[7] )) PIXEL11_10 else PIXEL11_70 break; case 94: if (Diff( b.w[3], b.w[1] )) PIXEL00_10 else PIXEL00_70 if (Diff( b.w[1], b.w[5] )) PIXEL01_0 else PIXEL01_20 if (Diff( b.w[7], b.w[3] )) PIXEL10_10 else PIXEL10_70 if (Diff( b.w[5], b.w[7] )) PIXEL11_10 else PIXEL11_70 break; case 218: if (Diff( b.w[3], b.w[1] )) PIXEL00_10 else PIXEL00_70 if (Diff( b.w[1], b.w[5] )) PIXEL01_10 else PIXEL01_70 if (Diff( b.w[7], b.w[3] )) PIXEL10_10 else PIXEL10_70 if (Diff( b.w[5], b.w[7] )) PIXEL11_0 else PIXEL11_20 break; case 91: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_20 if (Diff( b.w[1], b.w[5] )) PIXEL01_10 else PIXEL01_70 if (Diff( b.w[7], b.w[3] )) PIXEL10_10 else PIXEL10_70 if (Diff( b.w[5], b.w[7] )) PIXEL11_10 else PIXEL11_70 break; case 229: PIXEL00_20 PIXEL01_20 PIXEL10_12 PIXEL11_11 break; case 167: PIXEL00_11 PIXEL01_12 PIXEL10_20 PIXEL11_20 break; case 173: PIXEL00_12 PIXEL01_20 PIXEL10_11 PIXEL11_20 break; case 181: PIXEL00_20 PIXEL01_11 PIXEL10_20 PIXEL11_12 break; case 186: if (Diff( b.w[3], b.w[1] )) PIXEL00_10 else PIXEL00_70 if (Diff( b.w[1], b.w[5] )) PIXEL01_10 else PIXEL01_70 PIXEL10_11 PIXEL11_12 break; case 115: PIXEL00_11 if (Diff( b.w[1], b.w[5] )) PIXEL01_10 else PIXEL01_70 PIXEL10_12 if (Diff( b.w[5], b.w[7] )) PIXEL11_10 else PIXEL11_70 break; case 93: PIXEL00_12 PIXEL01_11 if (Diff( b.w[7], b.w[3] )) PIXEL10_10 else PIXEL10_70 if (Diff( b.w[5], b.w[7] )) PIXEL11_10 else PIXEL11_70 break; case 206: if (Diff( b.w[3], b.w[1] )) PIXEL00_10 else PIXEL00_70 PIXEL01_12 if (Diff( b.w[7], b.w[3] )) PIXEL10_10 else PIXEL10_70 PIXEL11_11 break; case 205: case 201: PIXEL00_12 PIXEL01_20 if (Diff( b.w[7], b.w[3] )) PIXEL10_10 else PIXEL10_70 PIXEL11_11 break; case 174: case 46: if (Diff( b.w[3], b.w[1] )) PIXEL00_10 else PIXEL00_70 PIXEL01_12 PIXEL10_11 PIXEL11_20 break; case 179: case 147: PIXEL00_11 if (Diff( b.w[1], b.w[5] )) PIXEL01_10 else PIXEL01_70 PIXEL10_20 PIXEL11_12 break; case 117: case 116: PIXEL00_20 PIXEL01_11 PIXEL10_12 if (Diff( b.w[5], b.w[7] )) PIXEL11_10 else PIXEL11_70 break; case 189: PIXEL00_12 PIXEL01_11 PIXEL10_11 PIXEL11_12 break; case 231: PIXEL00_11 PIXEL01_12 PIXEL10_12 PIXEL11_11 break; case 126: PIXEL00_10 if (Diff( b.w[1], b.w[5] )) PIXEL01_0 else PIXEL01_20 if (Diff( b.w[7], b.w[3] )) PIXEL10_0 else PIXEL10_20 PIXEL11_10 break; case 219: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_20 PIXEL01_10 PIXEL10_10 if (Diff( b.w[5], b.w[7] )) PIXEL11_0 else PIXEL11_20 break; case 125: if (Diff( b.w[7], b.w[3] )) { PIXEL00_12 PIXEL10_0 } else { PIXEL00_61 PIXEL10_90 } PIXEL01_11 PIXEL11_10 break; case 221: PIXEL00_12 if (Diff( b.w[5], b.w[7] )) { PIXEL01_11 PIXEL11_0 } else { PIXEL01_60 PIXEL11_90 } PIXEL10_10 break; case 207: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL01_12 } else { PIXEL00_90 PIXEL01_61 } PIXEL10_10 PIXEL11_11 break; case 238: PIXEL00_10 PIXEL01_12 if (Diff( b.w[7], b.w[3] )) { PIXEL10_0 PIXEL11_11 } else { PIXEL10_90 PIXEL11_60 } break; case 190: PIXEL00_10 if (Diff( b.w[1], b.w[5] )) { PIXEL01_0 PIXEL11_12 } else { PIXEL01_90 PIXEL11_61 } PIXEL10_11 break; case 187: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL10_11 } else { PIXEL00_90 PIXEL10_60 } PIXEL01_10 PIXEL11_12 break; case 243: PIXEL00_11 PIXEL01_10 if (Diff( b.w[5], b.w[7] )) { PIXEL10_12 PIXEL11_0 } else { PIXEL10_61 PIXEL11_90 } break; case 119: if (Diff( b.w[1], b.w[5] )) { PIXEL00_11 PIXEL01_0 } else { PIXEL00_60 PIXEL01_90 } PIXEL10_12 PIXEL11_10 break; case 237: case 233: PIXEL00_12 PIXEL01_20 if (Diff( b.w[7], b.w[3] )) PIXEL10_0 else PIXEL10_100 PIXEL11_11 break; case 175: case 47: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_100 PIXEL01_12 PIXEL10_11 PIXEL11_20 break; case 183: case 151: PIXEL00_11 if (Diff( b.w[1], b.w[5] )) PIXEL01_0 else PIXEL01_100 PIXEL10_20 PIXEL11_12 break; case 245: case 244: PIXEL00_20 PIXEL01_11 PIXEL10_12 if (Diff( b.w[5], b.w[7] )) PIXEL11_0 else PIXEL11_100 break; case 250: PIXEL00_10 PIXEL01_10 if (Diff( b.w[7], b.w[3] )) PIXEL10_0 else PIXEL10_20 if (Diff( b.w[5], b.w[7] )) PIXEL11_0 else PIXEL11_20 break; case 123: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_20 PIXEL01_10 if (Diff( b.w[7], b.w[3] )) PIXEL10_0 else PIXEL10_20 PIXEL11_10 break; case 95: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_20 if (Diff( b.w[1], b.w[5] )) PIXEL01_0 else PIXEL01_20 PIXEL10_10 PIXEL11_10 break; case 222: PIXEL00_10 if (Diff( b.w[1], b.w[5] )) PIXEL01_0 else PIXEL01_20 PIXEL10_10 if (Diff( b.w[5], b.w[7] )) PIXEL11_0 else PIXEL11_20 break; case 252: PIXEL00_21 PIXEL01_11 if (Diff( b.w[7], b.w[3] )) PIXEL10_0 else PIXEL10_20 if (Diff( b.w[5], b.w[7] )) PIXEL11_0 else PIXEL11_100 break; case 249: PIXEL00_12 PIXEL01_22 if (Diff( b.w[7], b.w[3] )) PIXEL10_0 else PIXEL10_100 if (Diff( b.w[5], b.w[7] )) PIXEL11_0 else PIXEL11_20 break; case 235: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_20 PIXEL01_21 if (Diff( b.w[7], b.w[3] )) PIXEL10_0 else PIXEL10_100 PIXEL11_11 break; case 111: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_100 PIXEL01_12 if (Diff( b.w[7], b.w[3] )) PIXEL10_0 else PIXEL10_20 PIXEL11_22 break; case 63: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_100 if (Diff( b.w[1], b.w[5] )) PIXEL01_0 else PIXEL01_20 PIXEL10_11 PIXEL11_21 break; case 159: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_20 if (Diff( b.w[1], b.w[5] )) PIXEL01_0 else PIXEL01_100 PIXEL10_22 PIXEL11_12 break; case 215: PIXEL00_11 if (Diff( b.w[1], b.w[5] )) PIXEL01_0 else PIXEL01_100 PIXEL10_21 if (Diff( b.w[5], b.w[7] )) PIXEL11_0 else PIXEL11_20 break; case 246: PIXEL00_22 if (Diff( b.w[1], b.w[5] )) PIXEL01_0 else PIXEL01_20 PIXEL10_12 if (Diff( b.w[5], b.w[7] )) PIXEL11_0 else PIXEL11_100 break; case 254: PIXEL00_10 if (Diff( b.w[1], b.w[5] )) PIXEL01_0 else PIXEL01_20 if (Diff( b.w[7], b.w[3] )) PIXEL10_0 else PIXEL10_20 if (Diff( b.w[5], b.w[7] )) PIXEL11_0 else PIXEL11_100 break; case 253: PIXEL00_12 PIXEL01_11 if (Diff( b.w[7], b.w[3] )) PIXEL10_0 else PIXEL10_100 if (Diff( b.w[5], b.w[7] )) PIXEL11_0 else PIXEL11_100 break; case 251: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_20 PIXEL01_10 if (Diff( b.w[7], b.w[3] )) PIXEL10_0 else PIXEL10_100 if (Diff( b.w[5], b.w[7] )) PIXEL11_0 else PIXEL11_20 break; case 239: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_100 PIXEL01_12 if (Diff( b.w[7], b.w[3] )) PIXEL10_0 else PIXEL10_100 PIXEL11_11 break; case 127: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_100 if (Diff( b.w[1], b.w[5] )) PIXEL01_0 else PIXEL01_20 if (Diff( b.w[7], b.w[3] )) PIXEL10_0 else PIXEL10_20 PIXEL11_10 break; case 191: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_100 if (Diff( b.w[1], b.w[5] )) PIXEL01_0 else PIXEL01_100 PIXEL10_11 PIXEL11_12 break; case 223: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_20 if (Diff( b.w[1], b.w[5] )) PIXEL01_0 else PIXEL01_100 PIXEL10_10 if (Diff( b.w[5], b.w[7] )) PIXEL11_0 else PIXEL11_20 break; case 247: PIXEL00_11 if (Diff( b.w[1], b.w[5] )) PIXEL01_0 else PIXEL01_100 PIXEL10_12 if (Diff( b.w[5], b.w[7] )) PIXEL11_0 else PIXEL11_100 break; case 255: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_100 if (Diff( b.w[1], b.w[5] )) PIXEL01_0 else PIXEL01_100 if (Diff( b.w[7], b.w[3] )) PIXEL10_0 else PIXEL10_100 if (Diff( b.w[5], b.w[7] )) PIXEL11_0 else PIXEL11_100 break; default: NST_UNREACHABLE(); } #undef PIXEL00_0 #undef PIXEL00_10 #undef PIXEL00_11 #undef PIXEL00_12 #undef PIXEL00_20 #undef PIXEL00_21 #undef PIXEL00_22 #undef PIXEL00_60 #undef PIXEL00_61 #undef PIXEL00_70 #undef PIXEL00_90 #undef PIXEL00_100 #undef PIXEL01_0 #undef PIXEL01_10 #undef PIXEL01_11 #undef PIXEL01_12 #undef PIXEL01_20 #undef PIXEL01_21 #undef PIXEL01_22 #undef PIXEL01_60 #undef PIXEL01_61 #undef PIXEL01_70 #undef PIXEL01_90 #undef PIXEL01_100 #undef PIXEL10_0 #undef PIXEL10_10 #undef PIXEL10_11 #undef PIXEL10_12 #undef PIXEL10_20 #undef PIXEL10_21 #undef PIXEL10_22 #undef PIXEL10_60 #undef PIXEL10_61 #undef PIXEL10_70 #undef PIXEL10_90 #undef PIXEL10_100 #undef PIXEL11_0 #undef PIXEL11_10 #undef PIXEL11_11 #undef PIXEL11_12 #undef PIXEL11_20 #undef PIXEL11_21 #undef PIXEL11_22 #undef PIXEL11_60 #undef PIXEL11_61 #undef PIXEL11_70 #undef PIXEL11_90 #undef PIXEL11_100 nestopia-1.51.1/source/core/NstVideoFilterHq3x.inl000066400000000000000000001265511411157722000220340ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003 MaxSt ( maxst@hiend3d.com ) // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// switch ( (b.w[4] != b.w[0] && ((yuv5 - lut.yuv[b.w[0]]) & Lut::YUV_MASK) ? 0x01U : 0x0U) | (b.w[4] != b.w[1] && ((yuv5 - lut.yuv[b.w[1]]) & Lut::YUV_MASK) ? 0x02U : 0x0U) | (b.w[4] != b.w[2] && ((yuv5 - lut.yuv[b.w[2]]) & Lut::YUV_MASK) ? 0x04U : 0x0U) | (b.w[4] != b.w[3] && ((yuv5 - lut.yuv[b.w[3]]) & Lut::YUV_MASK) ? 0x08U : 0x0U) | (b.w[4] != b.w[5] && ((yuv5 - lut.yuv[b.w[5]]) & Lut::YUV_MASK) ? 0x10U : 0x0U) | (b.w[4] != b.w[6] && ((yuv5 - lut.yuv[b.w[6]]) & Lut::YUV_MASK) ? 0x20U : 0x0U) | (b.w[4] != b.w[7] && ((yuv5 - lut.yuv[b.w[7]]) & Lut::YUV_MASK) ? 0x40U : 0x0U) | (b.w[4] != b.w[8] && ((yuv5 - lut.yuv[b.w[8]]) & Lut::YUV_MASK) ? 0x80U : 0x0U) ) #define PIXEL00_1M dst[0][0] = Interpolate1( b.c[4], b.c[0] ); #define PIXEL00_1U dst[0][0] = Interpolate1( b.c[4], b.c[1] ); #define PIXEL00_1L dst[0][0] = Interpolate1( b.c[4], b.c[3] ); #define PIXEL00_2 dst[0][0] = Interpolate2( b.c[4], b.c[3], b.c[1] ); #define PIXEL00_4 dst[0][0] = Interpolate4( b.c[4], b.c[3], b.c[1] ); #define PIXEL00_5 dst[0][0] = Interpolate5( b.c[3], b.c[1] ); #define PIXEL00_C dst[0][0] = b.c[4]; #define PIXEL01_1 dst[0][1] = Interpolate1( b.c[4], b.c[1] ); #define PIXEL01_3 dst[0][1] = Interpolate3( b.c[4], b.c[1] ); #define PIXEL01_6 dst[0][1] = Interpolate1( b.c[1], b.c[4] ); #define PIXEL01_C dst[0][1] = b.c[4]; #define PIXEL02_1M dst[0][2] = Interpolate1( b.c[4], b.c[2] ); #define PIXEL02_1U dst[0][2] = Interpolate1( b.c[4], b.c[1] ); #define PIXEL02_1R dst[0][2] = Interpolate1( b.c[4], b.c[5] ); #define PIXEL02_2 dst[0][2] = Interpolate2( b.c[4], b.c[1], b.c[5] ); #define PIXEL02_4 dst[0][2] = Interpolate4( b.c[4], b.c[1], b.c[5] ); #define PIXEL02_5 dst[0][2] = Interpolate5( b.c[1], b.c[5] ); #define PIXEL02_C dst[0][2] = b.c[4]; #define PIXEL10_1 dst[1][0] = Interpolate1( b.c[4], b.c[3] ); #define PIXEL10_3 dst[1][0] = Interpolate3( b.c[4], b.c[3] ); #define PIXEL10_6 dst[1][0] = Interpolate1( b.c[3], b.c[4] ); #define PIXEL10_C dst[1][0] = b.c[4]; #define PIXEL11 dst[1][1] = b.c[4]; #define PIXEL12_1 dst[1][2] = Interpolate1( b.c[4], b.c[5] ); #define PIXEL12_3 dst[1][2] = Interpolate3( b.c[4], b.c[5] ); #define PIXEL12_6 dst[1][2] = Interpolate1( b.c[5], b.c[4] ); #define PIXEL12_C dst[1][2] = b.c[4]; #define PIXEL20_1M dst[2][0] = Interpolate1( b.c[4], b.c[6] ); #define PIXEL20_1D dst[2][0] = Interpolate1( b.c[4], b.c[7] ); #define PIXEL20_1L dst[2][0] = Interpolate1( b.c[4], b.c[3] ); #define PIXEL20_2 dst[2][0] = Interpolate2( b.c[4], b.c[7], b.c[3] ); #define PIXEL20_4 dst[2][0] = Interpolate4( b.c[4], b.c[7], b.c[3] ); #define PIXEL20_5 dst[2][0] = Interpolate5( b.c[7], b.c[3]); #define PIXEL20_C dst[2][0] = b.c[4]; #define PIXEL21_1 dst[2][1] = Interpolate1( b.c[4], b.c[7] ); #define PIXEL21_3 dst[2][1] = Interpolate3( b.c[4], b.c[7] ); #define PIXEL21_6 dst[2][1] = Interpolate1( b.c[7], b.c[4] ); #define PIXEL21_C dst[2][1] = b.c[4]; #define PIXEL22_1M dst[2][2] = Interpolate1( b.c[4], b.c[8] ); #define PIXEL22_1D dst[2][2] = Interpolate1( b.c[4], b.c[7] ); #define PIXEL22_1R dst[2][2] = Interpolate1( b.c[4], b.c[5] ); #define PIXEL22_2 dst[2][2] = Interpolate2( b.c[4], b.c[5], b.c[7] ); #define PIXEL22_4 dst[2][2] = Interpolate4( b.c[4], b.c[5], b.c[7] ); #define PIXEL22_5 dst[2][2] = Interpolate5( b.c[5], b.c[7] ); #define PIXEL22_C dst[2][2] = b.c[4]; { case 0: case 1: case 4: case 32: case 128: case 5: case 132: case 160: case 33: case 129: case 36: case 133: case 164: case 161: case 37: case 165: PIXEL00_2 PIXEL01_1 PIXEL02_2 PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_2 PIXEL21_1 PIXEL22_2 break; case 2: case 34: case 130: case 162: PIXEL00_1M PIXEL01_C PIXEL02_1M PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_2 PIXEL21_1 PIXEL22_2 break; case 16: case 17: case 48: case 49: PIXEL00_2 PIXEL01_1 PIXEL02_1M PIXEL10_1 PIXEL11 PIXEL12_C PIXEL20_2 PIXEL21_1 PIXEL22_1M break; case 64: case 65: case 68: case 69: PIXEL00_2 PIXEL01_1 PIXEL02_2 PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_1M PIXEL21_C PIXEL22_1M break; case 8: case 12: case 136: case 140: PIXEL00_1M PIXEL01_1 PIXEL02_2 PIXEL10_C PIXEL11 PIXEL12_1 PIXEL20_1M PIXEL21_1 PIXEL22_2 break; case 3: case 35: case 131: case 163: PIXEL00_1L PIXEL01_C PIXEL02_1M PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_2 PIXEL21_1 PIXEL22_2 break; case 6: case 38: case 134: case 166: PIXEL00_1M PIXEL01_C PIXEL02_1R PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_2 PIXEL21_1 PIXEL22_2 break; case 20: case 21: case 52: case 53: PIXEL00_2 PIXEL01_1 PIXEL02_1U PIXEL10_1 PIXEL11 PIXEL12_C PIXEL20_2 PIXEL21_1 PIXEL22_1M break; case 144: case 145: case 176: case 177: PIXEL00_2 PIXEL01_1 PIXEL02_1M PIXEL10_1 PIXEL11 PIXEL12_C PIXEL20_2 PIXEL21_1 PIXEL22_1D break; case 192: case 193: case 196: case 197: PIXEL00_2 PIXEL01_1 PIXEL02_2 PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_1M PIXEL21_C PIXEL22_1R break; case 96: case 97: case 100: case 101: PIXEL00_2 PIXEL01_1 PIXEL02_2 PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_1L PIXEL21_C PIXEL22_1M break; case 40: case 44: case 168: case 172: PIXEL00_1M PIXEL01_1 PIXEL02_2 PIXEL10_C PIXEL11 PIXEL12_1 PIXEL20_1D PIXEL21_1 PIXEL22_2 break; case 9: case 13: case 137: case 141: PIXEL00_1U PIXEL01_1 PIXEL02_2 PIXEL10_C PIXEL11 PIXEL12_1 PIXEL20_1M PIXEL21_1 PIXEL22_2 break; case 18: case 50: PIXEL00_1M if (Diff(b.w[1], b.w[5])) { PIXEL01_C PIXEL02_1M PIXEL12_C } else { PIXEL01_3 PIXEL02_4 PIXEL12_3 } PIXEL10_1 PIXEL11 PIXEL20_2 PIXEL21_1 PIXEL22_1M break; case 80: case 81: PIXEL00_2 PIXEL01_1 PIXEL02_1M PIXEL10_1 PIXEL11 PIXEL20_1M if (Diff(b.w[5], b.w[7])) { PIXEL12_C PIXEL21_C PIXEL22_1M } else { PIXEL12_3 PIXEL21_3 PIXEL22_4 } break; case 72: case 76: PIXEL00_1M PIXEL01_1 PIXEL02_2 PIXEL11 PIXEL12_1 if (Diff(b.w[7], b.w[3])) { PIXEL10_C PIXEL20_1M PIXEL21_C } else { PIXEL10_3 PIXEL20_4 PIXEL21_3 } PIXEL22_1M break; case 10: case 138: if (Diff(b.w[3], b.w[1])) { PIXEL00_1M PIXEL01_C PIXEL10_C } else { PIXEL00_4 PIXEL01_3 PIXEL10_3 } PIXEL02_1M PIXEL11 PIXEL12_1 PIXEL20_1M PIXEL21_1 PIXEL22_2 break; case 66: PIXEL00_1M PIXEL01_C PIXEL02_1M PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_1M PIXEL21_C PIXEL22_1M break; case 24: PIXEL00_1M PIXEL01_1 PIXEL02_1M PIXEL10_C PIXEL11 PIXEL12_C PIXEL20_1M PIXEL21_1 PIXEL22_1M break; case 7: case 39: case 135: PIXEL00_1L PIXEL01_C PIXEL02_1R PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_2 PIXEL21_1 PIXEL22_2 break; case 148: case 149: case 180: PIXEL00_2 PIXEL01_1 PIXEL02_1U PIXEL10_1 PIXEL11 PIXEL12_C PIXEL20_2 PIXEL21_1 PIXEL22_1D break; case 224: case 228: case 225: PIXEL00_2 PIXEL01_1 PIXEL02_2 PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_1L PIXEL21_C PIXEL22_1R break; case 41: case 169: case 45: PIXEL00_1U PIXEL01_1 PIXEL02_2 PIXEL10_C PIXEL11 PIXEL12_1 PIXEL20_1D PIXEL21_1 PIXEL22_2 break; case 22: case 54: PIXEL00_1M if (Diff(b.w[1], b.w[5])) { PIXEL01_C PIXEL02_C PIXEL12_C } else { PIXEL01_3 PIXEL02_4 PIXEL12_3 } PIXEL10_1 PIXEL11 PIXEL20_2 PIXEL21_1 PIXEL22_1M break; case 208: case 209: PIXEL00_2 PIXEL01_1 PIXEL02_1M PIXEL10_1 PIXEL11 PIXEL20_1M if (Diff(b.w[5], b.w[7])) { PIXEL12_C PIXEL21_C PIXEL22_C } else { PIXEL12_3 PIXEL21_3 PIXEL22_4 } break; case 104: case 108: PIXEL00_1M PIXEL01_1 PIXEL02_2 PIXEL11 PIXEL12_1 if (Diff(b.w[7], b.w[3])) { PIXEL10_C PIXEL20_C PIXEL21_C } else { PIXEL10_3 PIXEL20_4 PIXEL21_3 } PIXEL22_1M break; case 11: case 139: if (Diff(b.w[3], b.w[1])) { PIXEL00_C PIXEL01_C PIXEL10_C } else { PIXEL00_4 PIXEL01_3 PIXEL10_3 } PIXEL02_1M PIXEL11 PIXEL12_1 PIXEL20_1M PIXEL21_1 PIXEL22_2 break; case 19: case 51: if (Diff(b.w[1], b.w[5])) { PIXEL00_1L PIXEL01_C PIXEL02_1M PIXEL12_C } else { PIXEL00_2 PIXEL01_6 PIXEL02_5 PIXEL12_1 } PIXEL10_1 PIXEL11 PIXEL20_2 PIXEL21_1 PIXEL22_1M break; case 146: case 178: if (Diff(b.w[1], b.w[5])) { PIXEL01_C PIXEL02_1M PIXEL12_C PIXEL22_1D } else { PIXEL01_1 PIXEL02_5 PIXEL12_6 PIXEL22_2 } PIXEL00_1M PIXEL10_1 PIXEL11 PIXEL20_2 PIXEL21_1 break; case 84: case 85: if (Diff(b.w[5], b.w[7])) { PIXEL02_1U PIXEL12_C PIXEL21_C PIXEL22_1M } else { PIXEL02_2 PIXEL12_6 PIXEL21_1 PIXEL22_5 } PIXEL00_2 PIXEL01_1 PIXEL10_1 PIXEL11 PIXEL20_1M break; case 112: case 113: if (Diff(b.w[5], b.w[7])) { PIXEL12_C PIXEL20_1L PIXEL21_C PIXEL22_1M } else { PIXEL12_1 PIXEL20_2 PIXEL21_6 PIXEL22_5 } PIXEL00_2 PIXEL01_1 PIXEL02_1M PIXEL10_1 PIXEL11 break; case 200: case 204: if (Diff(b.w[7], b.w[3])) { PIXEL10_C PIXEL20_1M PIXEL21_C PIXEL22_1R } else { PIXEL10_1 PIXEL20_5 PIXEL21_6 PIXEL22_2 } PIXEL00_1M PIXEL01_1 PIXEL02_2 PIXEL11 PIXEL12_1 break; case 73: case 77: if (Diff(b.w[7], b.w[3])) { PIXEL00_1U PIXEL10_C PIXEL20_1M PIXEL21_C } else { PIXEL00_2 PIXEL10_6 PIXEL20_5 PIXEL21_1 } PIXEL01_1 PIXEL02_2 PIXEL11 PIXEL12_1 PIXEL22_1M break; case 42: case 170: if (Diff(b.w[3], b.w[1])) { PIXEL00_1M PIXEL01_C PIXEL10_C PIXEL20_1D } else { PIXEL00_5 PIXEL01_1 PIXEL10_6 PIXEL20_2 } PIXEL02_1M PIXEL11 PIXEL12_1 PIXEL21_1 PIXEL22_2 break; case 14: case 142: if (Diff(b.w[3], b.w[1])) { PIXEL00_1M PIXEL01_C PIXEL02_1R PIXEL10_C } else { PIXEL00_5 PIXEL01_6 PIXEL02_2 PIXEL10_1 } PIXEL11 PIXEL12_1 PIXEL20_1M PIXEL21_1 PIXEL22_2 break; case 67: PIXEL00_1L PIXEL01_C PIXEL02_1M PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_1M PIXEL21_C PIXEL22_1M break; case 70: PIXEL00_1M PIXEL01_C PIXEL02_1R PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_1M PIXEL21_C PIXEL22_1M break; case 28: PIXEL00_1M PIXEL01_1 PIXEL02_1U PIXEL10_C PIXEL11 PIXEL12_C PIXEL20_1M PIXEL21_1 PIXEL22_1M break; case 152: PIXEL00_1M PIXEL01_1 PIXEL02_1M PIXEL10_C PIXEL11 PIXEL12_C PIXEL20_1M PIXEL21_1 PIXEL22_1D break; case 194: PIXEL00_1M PIXEL01_C PIXEL02_1M PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_1M PIXEL21_C PIXEL22_1R break; case 98: PIXEL00_1M PIXEL01_C PIXEL02_1M PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_1L PIXEL21_C PIXEL22_1M break; case 56: PIXEL00_1M PIXEL01_1 PIXEL02_1M PIXEL10_C PIXEL11 PIXEL12_C PIXEL20_1D PIXEL21_1 PIXEL22_1M break; case 25: PIXEL00_1U PIXEL01_1 PIXEL02_1M PIXEL10_C PIXEL11 PIXEL12_C PIXEL20_1M PIXEL21_1 PIXEL22_1M break; case 26: case 31: if (Diff(b.w[3], b.w[1])) { PIXEL00_C PIXEL10_C } else { PIXEL00_4 PIXEL10_3 } PIXEL01_C if (Diff(b.w[1], b.w[5])) { PIXEL02_C PIXEL12_C } else { PIXEL02_4 PIXEL12_3 } PIXEL11 PIXEL20_1M PIXEL21_1 PIXEL22_1M break; case 82: case 214: PIXEL00_1M if (Diff(b.w[1], b.w[5])) { PIXEL01_C PIXEL02_C } else { PIXEL01_3 PIXEL02_4 } PIXEL10_1 PIXEL11 PIXEL12_C PIXEL20_1M if (Diff(b.w[5], b.w[7])) { PIXEL21_C PIXEL22_C } else { PIXEL21_3 PIXEL22_4 } break; case 88: case 248: PIXEL00_1M PIXEL01_1 PIXEL02_1M PIXEL11 if (Diff(b.w[7], b.w[3])) { PIXEL10_C PIXEL20_C } else { PIXEL10_3 PIXEL20_4 } PIXEL21_C if (Diff(b.w[5], b.w[7])) { PIXEL12_C PIXEL22_C } else { PIXEL12_3 PIXEL22_4 } break; case 74: case 107: if (Diff(b.w[3], b.w[1])) { PIXEL00_C PIXEL01_C } else { PIXEL00_4 PIXEL01_3 } PIXEL02_1M PIXEL10_C PIXEL11 PIXEL12_1 if (Diff(b.w[7], b.w[3])) { PIXEL20_C PIXEL21_C } else { PIXEL20_4 PIXEL21_3 } PIXEL22_1M break; case 27: if (Diff(b.w[3], b.w[1])) { PIXEL00_C PIXEL01_C PIXEL10_C } else { PIXEL00_4 PIXEL01_3 PIXEL10_3 } PIXEL02_1M PIXEL11 PIXEL12_C PIXEL20_1M PIXEL21_1 PIXEL22_1M break; case 86: PIXEL00_1M if (Diff(b.w[1], b.w[5])) { PIXEL01_C PIXEL02_C PIXEL12_C } else { PIXEL01_3 PIXEL02_4 PIXEL12_3 } PIXEL10_1 PIXEL11 PIXEL20_1M PIXEL21_C PIXEL22_1M break; case 216: PIXEL00_1M PIXEL01_1 PIXEL02_1M PIXEL10_C PIXEL11 PIXEL20_1M if (Diff(b.w[5], b.w[7])) { PIXEL12_C PIXEL21_C PIXEL22_C } else { PIXEL12_3 PIXEL21_3 PIXEL22_4 } break; case 106: PIXEL00_1M PIXEL01_C PIXEL02_1M PIXEL11 PIXEL12_1 if (Diff(b.w[7], b.w[3])) { PIXEL10_C PIXEL20_C PIXEL21_C } else { PIXEL10_3 PIXEL20_4 PIXEL21_3 } PIXEL22_1M break; case 30: PIXEL00_1M if (Diff(b.w[1], b.w[5])) { PIXEL01_C PIXEL02_C PIXEL12_C } else { PIXEL01_3 PIXEL02_4 PIXEL12_3 } PIXEL10_C PIXEL11 PIXEL20_1M PIXEL21_1 PIXEL22_1M break; case 210: PIXEL00_1M PIXEL01_C PIXEL02_1M PIXEL10_1 PIXEL11 PIXEL20_1M if (Diff(b.w[5], b.w[7])) { PIXEL12_C PIXEL21_C PIXEL22_C } else { PIXEL12_3 PIXEL21_3 PIXEL22_4 } break; case 120: PIXEL00_1M PIXEL01_1 PIXEL02_1M PIXEL11 PIXEL12_C if (Diff(b.w[7], b.w[3])) { PIXEL10_C PIXEL20_C PIXEL21_C } else { PIXEL10_3 PIXEL20_4 PIXEL21_3 } PIXEL22_1M break; case 75: if (Diff(b.w[3], b.w[1])) { PIXEL00_C PIXEL01_C PIXEL10_C } else { PIXEL00_4 PIXEL01_3 PIXEL10_3 } PIXEL02_1M PIXEL11 PIXEL12_1 PIXEL20_1M PIXEL21_C PIXEL22_1M break; case 29: PIXEL00_1U PIXEL01_1 PIXEL02_1U PIXEL10_C PIXEL11 PIXEL12_C PIXEL20_1M PIXEL21_1 PIXEL22_1M break; case 198: PIXEL00_1M PIXEL01_C PIXEL02_1R PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_1M PIXEL21_C PIXEL22_1R break; case 184: PIXEL00_1M PIXEL01_1 PIXEL02_1M PIXEL10_C PIXEL11 PIXEL12_C PIXEL20_1D PIXEL21_1 PIXEL22_1D break; case 99: PIXEL00_1L PIXEL01_C PIXEL02_1M PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_1L PIXEL21_C PIXEL22_1M break; case 57: PIXEL00_1U PIXEL01_1 PIXEL02_1M PIXEL10_C PIXEL11 PIXEL12_C PIXEL20_1D PIXEL21_1 PIXEL22_1M break; case 71: PIXEL00_1L PIXEL01_C PIXEL02_1R PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_1M PIXEL21_C PIXEL22_1M break; case 156: PIXEL00_1M PIXEL01_1 PIXEL02_1U PIXEL10_C PIXEL11 PIXEL12_C PIXEL20_1M PIXEL21_1 PIXEL22_1D break; case 226: PIXEL00_1M PIXEL01_C PIXEL02_1M PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_1L PIXEL21_C PIXEL22_1R break; case 60: PIXEL00_1M PIXEL01_1 PIXEL02_1U PIXEL10_C PIXEL11 PIXEL12_C PIXEL20_1D PIXEL21_1 PIXEL22_1M break; case 195: PIXEL00_1L PIXEL01_C PIXEL02_1M PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_1M PIXEL21_C PIXEL22_1R break; case 102: PIXEL00_1M PIXEL01_C PIXEL02_1R PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_1L PIXEL21_C PIXEL22_1M break; case 153: PIXEL00_1U PIXEL01_1 PIXEL02_1M PIXEL10_C PIXEL11 PIXEL12_C PIXEL20_1M PIXEL21_1 PIXEL22_1D break; case 58: if (Diff(b.w[3], b.w[1])) PIXEL00_1M else PIXEL00_2 PIXEL01_C if (Diff(b.w[1], b.w[5])) PIXEL02_1M else PIXEL02_2 PIXEL10_C PIXEL11 PIXEL12_C PIXEL20_1D PIXEL21_1 PIXEL22_1M break; case 83: PIXEL00_1L PIXEL01_C if (Diff(b.w[1], b.w[5])) PIXEL02_1M else PIXEL02_2 PIXEL10_1 PIXEL11 PIXEL12_C PIXEL20_1M PIXEL21_C if (Diff(b.w[5], b.w[7])) PIXEL22_1M else PIXEL22_2 break; case 92: PIXEL00_1M PIXEL01_1 PIXEL02_1U PIXEL10_C PIXEL11 PIXEL12_C if (Diff(b.w[7], b.w[3])) PIXEL20_1M else PIXEL20_2 PIXEL21_C if (Diff(b.w[5], b.w[7])) PIXEL22_1M else PIXEL22_2 break; case 202: if (Diff(b.w[3], b.w[1])) PIXEL00_1M else PIXEL00_2 PIXEL01_C PIXEL02_1M PIXEL10_C PIXEL11 PIXEL12_1 if (Diff(b.w[7], b.w[3])) PIXEL20_1M else PIXEL20_2 PIXEL21_C PIXEL22_1R break; case 78: if (Diff(b.w[3], b.w[1])) PIXEL00_1M else PIXEL00_2 PIXEL01_C PIXEL02_1R PIXEL10_C PIXEL11 PIXEL12_1 if (Diff(b.w[7], b.w[3])) PIXEL20_1M else PIXEL20_2 PIXEL21_C PIXEL22_1M break; case 154: if (Diff(b.w[3], b.w[1])) PIXEL00_1M else PIXEL00_2 PIXEL01_C if (Diff(b.w[1], b.w[5])) PIXEL02_1M else PIXEL02_2 PIXEL10_C PIXEL11 PIXEL12_C PIXEL20_1M PIXEL21_1 PIXEL22_1D break; case 114: PIXEL00_1M PIXEL01_C if (Diff(b.w[1], b.w[5])) PIXEL02_1M else PIXEL02_2 PIXEL10_1 PIXEL11 PIXEL12_C PIXEL20_1L PIXEL21_C if (Diff(b.w[5], b.w[7])) PIXEL22_1M else PIXEL22_2 break; case 89: PIXEL00_1U PIXEL01_1 PIXEL02_1M PIXEL10_C PIXEL11 PIXEL12_C if (Diff(b.w[7], b.w[3])) PIXEL20_1M else PIXEL20_2 PIXEL21_C if (Diff(b.w[5], b.w[7])) PIXEL22_1M else PIXEL22_2 break; case 90: if (Diff(b.w[3], b.w[1])) PIXEL00_1M else PIXEL00_2 PIXEL01_C if (Diff(b.w[1], b.w[5])) PIXEL02_1M else PIXEL02_2 PIXEL10_C PIXEL11 PIXEL12_C if (Diff(b.w[7], b.w[3])) PIXEL20_1M else PIXEL20_2 PIXEL21_C if (Diff(b.w[5], b.w[7])) PIXEL22_1M else PIXEL22_2 break; case 55: case 23: if (Diff(b.w[1], b.w[5])) { PIXEL00_1L PIXEL01_C PIXEL02_C PIXEL12_C } else { PIXEL00_2 PIXEL01_6 PIXEL02_5 PIXEL12_1 } PIXEL10_1 PIXEL11 PIXEL20_2 PIXEL21_1 PIXEL22_1M break; case 182: case 150: if (Diff(b.w[1], b.w[5])) { PIXEL01_C PIXEL02_C PIXEL12_C PIXEL22_1D } else { PIXEL01_1 PIXEL02_5 PIXEL12_6 PIXEL22_2 } PIXEL00_1M PIXEL10_1 PIXEL11 PIXEL20_2 PIXEL21_1 break; case 213: case 212: if (Diff(b.w[5], b.w[7])) { PIXEL02_1U PIXEL12_C PIXEL21_C PIXEL22_C } else { PIXEL02_2 PIXEL12_6 PIXEL21_1 PIXEL22_5 } PIXEL00_2 PIXEL01_1 PIXEL10_1 PIXEL11 PIXEL20_1M break; case 241: case 240: if (Diff(b.w[5], b.w[7])) { PIXEL12_C PIXEL20_1L PIXEL21_C PIXEL22_C } else { PIXEL12_1 PIXEL20_2 PIXEL21_6 PIXEL22_5 } PIXEL00_2 PIXEL01_1 PIXEL02_1M PIXEL10_1 PIXEL11 break; case 236: case 232: if (Diff(b.w[7], b.w[3])) { PIXEL10_C PIXEL20_C PIXEL21_C PIXEL22_1R } else { PIXEL10_1 PIXEL20_5 PIXEL21_6 PIXEL22_2 } PIXEL00_1M PIXEL01_1 PIXEL02_2 PIXEL11 PIXEL12_1 break; case 109: case 105: if (Diff(b.w[7], b.w[3])) { PIXEL00_1U PIXEL10_C PIXEL20_C PIXEL21_C } else { PIXEL00_2 PIXEL10_6 PIXEL20_5 PIXEL21_1 } PIXEL01_1 PIXEL02_2 PIXEL11 PIXEL12_1 PIXEL22_1M break; case 171: case 43: if (Diff(b.w[3], b.w[1])) { PIXEL00_C PIXEL01_C PIXEL10_C PIXEL20_1D } else { PIXEL00_5 PIXEL01_1 PIXEL10_6 PIXEL20_2 } PIXEL02_1M PIXEL11 PIXEL12_1 PIXEL21_1 PIXEL22_2 break; case 143: case 15: if (Diff(b.w[3], b.w[1])) { PIXEL00_C PIXEL01_C PIXEL02_1R PIXEL10_C } else { PIXEL00_5 PIXEL01_6 PIXEL02_2 PIXEL10_1 } PIXEL11 PIXEL12_1 PIXEL20_1M PIXEL21_1 PIXEL22_2 break; case 124: PIXEL00_1M PIXEL01_1 PIXEL02_1U PIXEL11 PIXEL12_C if (Diff(b.w[7], b.w[3])) { PIXEL10_C PIXEL20_C PIXEL21_C } else { PIXEL10_3 PIXEL20_4 PIXEL21_3 } PIXEL22_1M break; case 203: if (Diff(b.w[3], b.w[1])) { PIXEL00_C PIXEL01_C PIXEL10_C } else { PIXEL00_4 PIXEL01_3 PIXEL10_3 } PIXEL02_1M PIXEL11 PIXEL12_1 PIXEL20_1M PIXEL21_C PIXEL22_1R break; case 62: PIXEL00_1M if (Diff(b.w[1], b.w[5])) { PIXEL01_C PIXEL02_C PIXEL12_C } else { PIXEL01_3 PIXEL02_4 PIXEL12_3 } PIXEL10_C PIXEL11 PIXEL20_1D PIXEL21_1 PIXEL22_1M break; case 211: PIXEL00_1L PIXEL01_C PIXEL02_1M PIXEL10_1 PIXEL11 PIXEL20_1M if (Diff(b.w[5], b.w[7])) { PIXEL12_C PIXEL21_C PIXEL22_C } else { PIXEL12_3 PIXEL21_3 PIXEL22_4 } break; case 118: PIXEL00_1M if (Diff(b.w[1], b.w[5])) { PIXEL01_C PIXEL02_C PIXEL12_C } else { PIXEL01_3 PIXEL02_4 PIXEL12_3 } PIXEL10_1 PIXEL11 PIXEL20_1L PIXEL21_C PIXEL22_1M break; case 217: PIXEL00_1U PIXEL01_1 PIXEL02_1M PIXEL10_C PIXEL11 PIXEL20_1M if (Diff(b.w[5], b.w[7])) { PIXEL12_C PIXEL21_C PIXEL22_C } else { PIXEL12_3 PIXEL21_3 PIXEL22_4 } break; case 110: PIXEL00_1M PIXEL01_C PIXEL02_1R PIXEL11 PIXEL12_1 if (Diff(b.w[7], b.w[3])) { PIXEL10_C PIXEL20_C PIXEL21_C } else { PIXEL10_3 PIXEL20_4 PIXEL21_3 } PIXEL22_1M break; case 155: if (Diff(b.w[3], b.w[1])) { PIXEL00_C PIXEL01_C PIXEL10_C } else { PIXEL00_4 PIXEL01_3 PIXEL10_3 } PIXEL02_1M PIXEL11 PIXEL12_C PIXEL20_1M PIXEL21_1 PIXEL22_1D break; case 188: PIXEL00_1M PIXEL01_1 PIXEL02_1U PIXEL10_C PIXEL11 PIXEL12_C PIXEL20_1D PIXEL21_1 PIXEL22_1D break; case 185: PIXEL00_1U PIXEL01_1 PIXEL02_1M PIXEL10_C PIXEL11 PIXEL12_C PIXEL20_1D PIXEL21_1 PIXEL22_1D break; case 61: PIXEL00_1U PIXEL01_1 PIXEL02_1U PIXEL10_C PIXEL11 PIXEL12_C PIXEL20_1D PIXEL21_1 PIXEL22_1M break; case 157: PIXEL00_1U PIXEL01_1 PIXEL02_1U PIXEL10_C PIXEL11 PIXEL12_C PIXEL20_1M PIXEL21_1 PIXEL22_1D break; case 103: PIXEL00_1L PIXEL01_C PIXEL02_1R PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_1L PIXEL21_C PIXEL22_1M break; case 227: PIXEL00_1L PIXEL01_C PIXEL02_1M PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_1L PIXEL21_C PIXEL22_1R break; case 230: PIXEL00_1M PIXEL01_C PIXEL02_1R PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_1L PIXEL21_C PIXEL22_1R break; case 199: PIXEL00_1L PIXEL01_C PIXEL02_1R PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_1M PIXEL21_C PIXEL22_1R break; case 220: PIXEL00_1M PIXEL01_1 PIXEL02_1U PIXEL10_C PIXEL11 if (Diff(b.w[7], b.w[3])) PIXEL20_1M else PIXEL20_2 if (Diff(b.w[5], b.w[7])) { PIXEL12_C PIXEL21_C PIXEL22_C } else { PIXEL12_3 PIXEL21_3 PIXEL22_4 } break; case 158: if (Diff(b.w[3], b.w[1])) PIXEL00_1M else PIXEL00_2 if (Diff(b.w[1], b.w[5])) { PIXEL01_C PIXEL02_C PIXEL12_C } else { PIXEL01_3 PIXEL02_4 PIXEL12_3 } PIXEL10_C PIXEL11 PIXEL20_1M PIXEL21_1 PIXEL22_1D break; case 234: if (Diff(b.w[3], b.w[1])) PIXEL00_1M else PIXEL00_2 PIXEL01_C PIXEL02_1M PIXEL11 PIXEL12_1 if (Diff(b.w[7], b.w[3])) { PIXEL10_C PIXEL20_C PIXEL21_C } else { PIXEL10_3 PIXEL20_4 PIXEL21_3 } PIXEL22_1R break; case 242: PIXEL00_1M PIXEL01_C if (Diff(b.w[1], b.w[5])) PIXEL02_1M else PIXEL02_2 PIXEL10_1 PIXEL11 PIXEL20_1L if (Diff(b.w[5], b.w[7])) { PIXEL12_C PIXEL21_C PIXEL22_C } else { PIXEL12_3 PIXEL21_3 PIXEL22_4 } break; case 59: if (Diff(b.w[3], b.w[1])) { PIXEL00_C PIXEL01_C PIXEL10_C } else { PIXEL00_4 PIXEL01_3 PIXEL10_3 } if (Diff(b.w[1], b.w[5])) PIXEL02_1M else PIXEL02_2 PIXEL11 PIXEL12_C PIXEL20_1D PIXEL21_1 PIXEL22_1M break; case 121: PIXEL00_1U PIXEL01_1 PIXEL02_1M PIXEL11 PIXEL12_C if (Diff(b.w[7], b.w[3])) { PIXEL10_C PIXEL20_C PIXEL21_C } else { PIXEL10_3 PIXEL20_4 PIXEL21_3 } if (Diff(b.w[5], b.w[7])) PIXEL22_1M else PIXEL22_2 break; case 87: PIXEL00_1L if (Diff(b.w[1], b.w[5])) { PIXEL01_C PIXEL02_C PIXEL12_C } else { PIXEL01_3 PIXEL02_4 PIXEL12_3 } PIXEL10_1 PIXEL11 PIXEL20_1M PIXEL21_C if (Diff(b.w[5], b.w[7])) PIXEL22_1M else PIXEL22_2 break; case 79: if (Diff(b.w[3], b.w[1])) { PIXEL00_C PIXEL01_C PIXEL10_C } else { PIXEL00_4 PIXEL01_3 PIXEL10_3 } PIXEL02_1R PIXEL11 PIXEL12_1 if (Diff(b.w[7], b.w[3])) PIXEL20_1M else PIXEL20_2 PIXEL21_C PIXEL22_1M break; case 122: if (Diff(b.w[3], b.w[1])) PIXEL00_1M else PIXEL00_2 PIXEL01_C if (Diff(b.w[1], b.w[5])) PIXEL02_1M else PIXEL02_2 PIXEL11 PIXEL12_C if (Diff(b.w[7], b.w[3])) { PIXEL10_C PIXEL20_C PIXEL21_C } else { PIXEL10_3 PIXEL20_4 PIXEL21_3 } if (Diff(b.w[5], b.w[7])) PIXEL22_1M else PIXEL22_2 break; case 94: if (Diff(b.w[3], b.w[1])) PIXEL00_1M else PIXEL00_2 if (Diff(b.w[1], b.w[5])) { PIXEL01_C PIXEL02_C PIXEL12_C } else { PIXEL01_3 PIXEL02_4 PIXEL12_3 } PIXEL10_C PIXEL11 if (Diff(b.w[7], b.w[3])) PIXEL20_1M else PIXEL20_2 PIXEL21_C if (Diff(b.w[5], b.w[7])) PIXEL22_1M else PIXEL22_2 break; case 218: if (Diff(b.w[3], b.w[1])) PIXEL00_1M else PIXEL00_2 PIXEL01_C if (Diff(b.w[1], b.w[5])) PIXEL02_1M else PIXEL02_2 PIXEL10_C PIXEL11 if (Diff(b.w[7], b.w[3])) PIXEL20_1M else PIXEL20_2 if (Diff(b.w[5], b.w[7])) { PIXEL12_C PIXEL21_C PIXEL22_C } else { PIXEL12_3 PIXEL21_3 PIXEL22_4 } break; case 91: if (Diff(b.w[3], b.w[1])) { PIXEL00_C PIXEL01_C PIXEL10_C } else { PIXEL00_4 PIXEL01_3 PIXEL10_3 } if (Diff(b.w[1], b.w[5])) PIXEL02_1M else PIXEL02_2 PIXEL11 PIXEL12_C if (Diff(b.w[7], b.w[3])) PIXEL20_1M else PIXEL20_2 PIXEL21_C if (Diff(b.w[5], b.w[7])) PIXEL22_1M else PIXEL22_2 break; case 229: PIXEL00_2 PIXEL01_1 PIXEL02_2 PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_1L PIXEL21_C PIXEL22_1R break; case 167: PIXEL00_1L PIXEL01_C PIXEL02_1R PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_2 PIXEL21_1 PIXEL22_2 break; case 173: PIXEL00_1U PIXEL01_1 PIXEL02_2 PIXEL10_C PIXEL11 PIXEL12_1 PIXEL20_1D PIXEL21_1 PIXEL22_2 break; case 181: PIXEL00_2 PIXEL01_1 PIXEL02_1U PIXEL10_1 PIXEL11 PIXEL12_C PIXEL20_2 PIXEL21_1 PIXEL22_1D break; case 186: if (Diff(b.w[3], b.w[1])) PIXEL00_1M else PIXEL00_2 PIXEL01_C if (Diff(b.w[1], b.w[5])) PIXEL02_1M else PIXEL02_2 PIXEL10_C PIXEL11 PIXEL12_C PIXEL20_1D PIXEL21_1 PIXEL22_1D break; case 115: PIXEL00_1L PIXEL01_C if (Diff(b.w[1], b.w[5])) PIXEL02_1M else PIXEL02_2 PIXEL10_1 PIXEL11 PIXEL12_C PIXEL20_1L PIXEL21_C if (Diff(b.w[5], b.w[7])) PIXEL22_1M else PIXEL22_2 break; case 93: PIXEL00_1U PIXEL01_1 PIXEL02_1U PIXEL10_C PIXEL11 PIXEL12_C if (Diff(b.w[7], b.w[3])) PIXEL20_1M else PIXEL20_2 PIXEL21_C if (Diff(b.w[5], b.w[7])) PIXEL22_1M else PIXEL22_2 break; case 206: if (Diff(b.w[3], b.w[1])) PIXEL00_1M else PIXEL00_2 PIXEL01_C PIXEL02_1R PIXEL10_C PIXEL11 PIXEL12_1 if (Diff(b.w[7], b.w[3])) PIXEL20_1M else PIXEL20_2 PIXEL21_C PIXEL22_1R break; case 205: case 201: PIXEL00_1U PIXEL01_1 PIXEL02_2 PIXEL10_C PIXEL11 PIXEL12_1 if (Diff(b.w[7], b.w[3])) PIXEL20_1M else PIXEL20_2 PIXEL21_C PIXEL22_1R break; case 174: case 46: if (Diff(b.w[3], b.w[1])) PIXEL00_1M else PIXEL00_2 PIXEL01_C PIXEL02_1R PIXEL10_C PIXEL11 PIXEL12_1 PIXEL20_1D PIXEL21_1 PIXEL22_2 break; case 179: case 147: PIXEL00_1L PIXEL01_C if (Diff(b.w[1], b.w[5])) PIXEL02_1M else PIXEL02_2 PIXEL10_1 PIXEL11 PIXEL12_C PIXEL20_2 PIXEL21_1 PIXEL22_1D break; case 117: case 116: PIXEL00_2 PIXEL01_1 PIXEL02_1U PIXEL10_1 PIXEL11 PIXEL12_C PIXEL20_1L PIXEL21_C if (Diff(b.w[5], b.w[7])) PIXEL22_1M else PIXEL22_2 break; case 189: PIXEL00_1U PIXEL01_1 PIXEL02_1U PIXEL10_C PIXEL11 PIXEL12_C PIXEL20_1D PIXEL21_1 PIXEL22_1D break; case 231: PIXEL00_1L PIXEL01_C PIXEL02_1R PIXEL10_1 PIXEL11 PIXEL12_1 PIXEL20_1L PIXEL21_C PIXEL22_1R break; case 126: PIXEL00_1M if (Diff(b.w[1], b.w[5])) { PIXEL01_C PIXEL02_C PIXEL12_C } else { PIXEL01_3 PIXEL02_4 PIXEL12_3 } PIXEL11 if (Diff(b.w[7], b.w[3])) { PIXEL10_C PIXEL20_C PIXEL21_C } else { PIXEL10_3 PIXEL20_4 PIXEL21_3 } PIXEL22_1M break; case 219: if (Diff(b.w[3], b.w[1])) { PIXEL00_C PIXEL01_C PIXEL10_C } else { PIXEL00_4 PIXEL01_3 PIXEL10_3 } PIXEL02_1M PIXEL11 PIXEL20_1M if (Diff(b.w[5], b.w[7])) { PIXEL12_C PIXEL21_C PIXEL22_C } else { PIXEL12_3 PIXEL21_3 PIXEL22_4 } break; case 125: if (Diff(b.w[7], b.w[3])) { PIXEL00_1U PIXEL10_C PIXEL20_C PIXEL21_C } else { PIXEL00_2 PIXEL10_6 PIXEL20_5 PIXEL21_1 } PIXEL01_1 PIXEL02_1U PIXEL11 PIXEL12_C PIXEL22_1M break; case 221: if (Diff(b.w[5], b.w[7])) { PIXEL02_1U PIXEL12_C PIXEL21_C PIXEL22_C } else { PIXEL02_2 PIXEL12_6 PIXEL21_1 PIXEL22_5 } PIXEL00_1U PIXEL01_1 PIXEL10_C PIXEL11 PIXEL20_1M break; case 207: if (Diff(b.w[3], b.w[1])) { PIXEL00_C PIXEL01_C PIXEL02_1R PIXEL10_C } else { PIXEL00_5 PIXEL01_6 PIXEL02_2 PIXEL10_1 } PIXEL11 PIXEL12_1 PIXEL20_1M PIXEL21_C PIXEL22_1R break; case 238: if (Diff(b.w[7], b.w[3])) { PIXEL10_C PIXEL20_C PIXEL21_C PIXEL22_1R } else { PIXEL10_1 PIXEL20_5 PIXEL21_6 PIXEL22_2 } PIXEL00_1M PIXEL01_C PIXEL02_1R PIXEL11 PIXEL12_1 break; case 190: if (Diff(b.w[1], b.w[5])) { PIXEL01_C PIXEL02_C PIXEL12_C PIXEL22_1D } else { PIXEL01_1 PIXEL02_5 PIXEL12_6 PIXEL22_2 } PIXEL00_1M PIXEL10_C PIXEL11 PIXEL20_1D PIXEL21_1 break; case 187: if (Diff(b.w[3], b.w[1])) { PIXEL00_C PIXEL01_C PIXEL10_C PIXEL20_1D } else { PIXEL00_5 PIXEL01_1 PIXEL10_6 PIXEL20_2 } PIXEL02_1M PIXEL11 PIXEL12_C PIXEL21_1 PIXEL22_1D break; case 243: if (Diff(b.w[5], b.w[7])) { PIXEL12_C PIXEL20_1L PIXEL21_C PIXEL22_C } else { PIXEL12_1 PIXEL20_2 PIXEL21_6 PIXEL22_5 } PIXEL00_1L PIXEL01_C PIXEL02_1M PIXEL10_1 PIXEL11 break; case 119: if (Diff(b.w[1], b.w[5])) { PIXEL00_1L PIXEL01_C PIXEL02_C PIXEL12_C } else { PIXEL00_2 PIXEL01_6 PIXEL02_5 PIXEL12_1 } PIXEL10_1 PIXEL11 PIXEL20_1L PIXEL21_C PIXEL22_1M break; case 237: case 233: PIXEL00_1U PIXEL01_1 PIXEL02_2 PIXEL10_C PIXEL11 PIXEL12_1 if (Diff(b.w[7], b.w[3])) PIXEL20_C else PIXEL20_2 PIXEL21_C PIXEL22_1R break; case 175: case 47: if (Diff(b.w[3], b.w[1])) PIXEL00_C else PIXEL00_2 PIXEL01_C PIXEL02_1R PIXEL10_C PIXEL11 PIXEL12_1 PIXEL20_1D PIXEL21_1 PIXEL22_2 break; case 183: case 151: PIXEL00_1L PIXEL01_C if (Diff(b.w[1], b.w[5])) PIXEL02_C else PIXEL02_2 PIXEL10_1 PIXEL11 PIXEL12_C PIXEL20_2 PIXEL21_1 PIXEL22_1D break; case 245: case 244: PIXEL00_2 PIXEL01_1 PIXEL02_1U PIXEL10_1 PIXEL11 PIXEL12_C PIXEL20_1L PIXEL21_C if (Diff(b.w[5], b.w[7])) PIXEL22_C else PIXEL22_2 break; case 250: PIXEL00_1M PIXEL01_C PIXEL02_1M PIXEL11 if (Diff(b.w[7], b.w[3])) { PIXEL10_C PIXEL20_C } else { PIXEL10_3 PIXEL20_4 } PIXEL21_C if (Diff(b.w[5], b.w[7])) { PIXEL12_C PIXEL22_C } else { PIXEL12_3 PIXEL22_4 } break; case 123: if (Diff(b.w[3], b.w[1])) { PIXEL00_C PIXEL01_C } else { PIXEL00_4 PIXEL01_3 } PIXEL02_1M PIXEL10_C PIXEL11 PIXEL12_C if (Diff(b.w[7], b.w[3])) { PIXEL20_C PIXEL21_C } else { PIXEL20_4 PIXEL21_3 } PIXEL22_1M break; case 95: if (Diff(b.w[3], b.w[1])) { PIXEL00_C PIXEL10_C } else { PIXEL00_4 PIXEL10_3 } PIXEL01_C if (Diff(b.w[1], b.w[5])) { PIXEL02_C PIXEL12_C } else { PIXEL02_4 PIXEL12_3 } PIXEL11 PIXEL20_1M PIXEL21_C PIXEL22_1M break; case 222: PIXEL00_1M if (Diff(b.w[1], b.w[5])) { PIXEL01_C PIXEL02_C } else { PIXEL01_3 PIXEL02_4 } PIXEL10_C PIXEL11 PIXEL12_C PIXEL20_1M if (Diff(b.w[5], b.w[7])) { PIXEL21_C PIXEL22_C } else { PIXEL21_3 PIXEL22_4 } break; case 252: PIXEL00_1M PIXEL01_1 PIXEL02_1U PIXEL11 PIXEL12_C if (Diff(b.w[7], b.w[3])) { PIXEL10_C PIXEL20_C } else { PIXEL10_3 PIXEL20_4 } PIXEL21_C if (Diff(b.w[5], b.w[7])) PIXEL22_C else PIXEL22_2 break; case 249: PIXEL00_1U PIXEL01_1 PIXEL02_1M PIXEL10_C PIXEL11 if (Diff(b.w[7], b.w[3])) PIXEL20_C else PIXEL20_2 PIXEL21_C if (Diff(b.w[5], b.w[7])) { PIXEL12_C PIXEL22_C } else { PIXEL12_3 PIXEL22_4 } break; case 235: if (Diff(b.w[3], b.w[1])) { PIXEL00_C PIXEL01_C } else { PIXEL00_4 PIXEL01_3 } PIXEL02_1M PIXEL10_C PIXEL11 PIXEL12_1 if (Diff(b.w[7], b.w[3])) PIXEL20_C else PIXEL20_2 PIXEL21_C PIXEL22_1R break; case 111: if (Diff(b.w[3], b.w[1])) PIXEL00_C else PIXEL00_2 PIXEL01_C PIXEL02_1R PIXEL10_C PIXEL11 PIXEL12_1 if (Diff(b.w[7], b.w[3])) { PIXEL20_C PIXEL21_C } else { PIXEL20_4 PIXEL21_3 } PIXEL22_1M break; case 63: if (Diff(b.w[3], b.w[1])) PIXEL00_C else PIXEL00_2 PIXEL01_C if (Diff(b.w[1], b.w[5])) { PIXEL02_C PIXEL12_C } else { PIXEL02_4 PIXEL12_3 } PIXEL10_C PIXEL11 PIXEL20_1D PIXEL21_1 PIXEL22_1M break; case 159: if (Diff(b.w[3], b.w[1])) { PIXEL00_C PIXEL10_C } else { PIXEL00_4 PIXEL10_3 } PIXEL01_C if (Diff(b.w[1], b.w[5])) PIXEL02_C else PIXEL02_2 PIXEL11 PIXEL12_C PIXEL20_1M PIXEL21_1 PIXEL22_1D break; case 215: PIXEL00_1L PIXEL01_C if (Diff(b.w[1], b.w[5])) PIXEL02_C else PIXEL02_2 PIXEL10_1 PIXEL11 PIXEL12_C PIXEL20_1M if (Diff(b.w[5], b.w[7])) { PIXEL21_C PIXEL22_C } else { PIXEL21_3 PIXEL22_4 } break; case 246: PIXEL00_1M if (Diff(b.w[1], b.w[5])) { PIXEL01_C PIXEL02_C } else { PIXEL01_3 PIXEL02_4 } PIXEL10_1 PIXEL11 PIXEL12_C PIXEL20_1L PIXEL21_C if (Diff(b.w[5], b.w[7])) PIXEL22_C else PIXEL22_2 break; case 254: PIXEL00_1M if (Diff(b.w[1], b.w[5])) { PIXEL01_C PIXEL02_C } else { PIXEL01_3 PIXEL02_4 } PIXEL11 if (Diff(b.w[7], b.w[3])) { PIXEL10_C PIXEL20_C } else { PIXEL10_3 PIXEL20_4 } if (Diff(b.w[5], b.w[7])) { PIXEL12_C PIXEL21_C PIXEL22_C } else { PIXEL12_3 PIXEL21_3 PIXEL22_2 } break; case 253: PIXEL00_1U PIXEL01_1 PIXEL02_1U PIXEL10_C PIXEL11 PIXEL12_C if (Diff(b.w[7], b.w[3])) PIXEL20_C else PIXEL20_2 PIXEL21_C if (Diff(b.w[5], b.w[7])) PIXEL22_C else PIXEL22_2 break; case 251: if (Diff(b.w[3], b.w[1])) { PIXEL00_C PIXEL01_C } else { PIXEL00_4 PIXEL01_3 } PIXEL02_1M PIXEL11 if (Diff(b.w[7], b.w[3])) { PIXEL10_C PIXEL20_C PIXEL21_C } else { PIXEL10_3 PIXEL20_2 PIXEL21_3 } if (Diff(b.w[5], b.w[7])) { PIXEL12_C PIXEL22_C } else { PIXEL12_3 PIXEL22_4 } break; case 239: if (Diff(b.w[3], b.w[1])) PIXEL00_C else PIXEL00_2 PIXEL01_C PIXEL02_1R PIXEL10_C PIXEL11 PIXEL12_1 if (Diff(b.w[7], b.w[3])) PIXEL20_C else PIXEL20_2 PIXEL21_C PIXEL22_1R break; case 127: if (Diff(b.w[3], b.w[1])) { PIXEL00_C PIXEL01_C PIXEL10_C } else { PIXEL00_2 PIXEL01_3 PIXEL10_3 } if (Diff(b.w[1], b.w[5])) { PIXEL02_C PIXEL12_C } else { PIXEL02_4 PIXEL12_3 } PIXEL11 if (Diff(b.w[7], b.w[3])) { PIXEL20_C PIXEL21_C } else { PIXEL20_4 PIXEL21_3 } PIXEL22_1M break; case 191: if (Diff(b.w[3], b.w[1])) PIXEL00_C else PIXEL00_2 PIXEL01_C if (Diff(b.w[1], b.w[5])) PIXEL02_C else PIXEL02_2 PIXEL10_C PIXEL11 PIXEL12_C PIXEL20_1D PIXEL21_1 PIXEL22_1D break; case 223: if (Diff(b.w[3], b.w[1])) { PIXEL00_C PIXEL10_C } else { PIXEL00_4 PIXEL10_3 } if (Diff(b.w[1], b.w[5])) { PIXEL01_C PIXEL02_C PIXEL12_C } else { PIXEL01_3 PIXEL02_2 PIXEL12_3 } PIXEL11 PIXEL20_1M if (Diff(b.w[5], b.w[7])) { PIXEL21_C PIXEL22_C } else { PIXEL21_3 PIXEL22_4 } break; case 247: PIXEL00_1L PIXEL01_C if (Diff(b.w[1], b.w[5])) PIXEL02_C else PIXEL02_2 PIXEL10_1 PIXEL11 PIXEL12_C PIXEL20_1L PIXEL21_C if (Diff(b.w[5], b.w[7])) PIXEL22_C else PIXEL22_2 break; case 255: if (Diff(b.w[3], b.w[1])) PIXEL00_C else PIXEL00_2 PIXEL01_C if (Diff(b.w[1], b.w[5])) PIXEL02_C else PIXEL02_2 PIXEL10_C PIXEL11 PIXEL12_C if (Diff(b.w[7], b.w[3])) PIXEL20_C else PIXEL20_2 PIXEL21_C if (Diff(b.w[5], b.w[7])) PIXEL22_C else PIXEL22_2 break; default: NST_UNREACHABLE(); } #undef PIXEL00_1M #undef PIXEL00_1U #undef PIXEL00_1L #undef PIXEL00_2 #undef PIXEL00_4 #undef PIXEL00_5 #undef PIXEL00_C #undef PIXEL01_1 #undef PIXEL01_3 #undef PIXEL01_6 #undef PIXEL01_C #undef PIXEL02_1M #undef PIXEL02_1U #undef PIXEL02_1R #undef PIXEL02_2 #undef PIXEL02_4 #undef PIXEL02_5 #undef PIXEL02_C #undef PIXEL10_1 #undef PIXEL10_3 #undef PIXEL10_6 #undef PIXEL10_C #undef PIXEL11 #undef PIXEL12_1 #undef PIXEL12_3 #undef PIXEL12_6 #undef PIXEL12_C #undef PIXEL20_1M #undef PIXEL20_1D #undef PIXEL20_1L #undef PIXEL20_2 #undef PIXEL20_4 #undef PIXEL20_5 #undef PIXEL20_C #undef PIXEL21_1 #undef PIXEL21_3 #undef PIXEL21_6 #undef PIXEL21_C #undef PIXEL22_1M #undef PIXEL22_1D #undef PIXEL22_1R #undef PIXEL22_2 #undef PIXEL22_4 #undef PIXEL22_5 #undef PIXEL22_C nestopia-1.51.1/source/core/NstVideoFilterHq4x.inl000066400000000000000000002230561411157722000220330ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003 MaxSt ( maxst@hiend3d.com ) // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// switch ( (b.w[4] != b.w[0] && ((yuv5 - lut.yuv[b.w[0]]) & Lut::YUV_MASK) ? 0x01U : 0x0U) | (b.w[4] != b.w[1] && ((yuv5 - lut.yuv[b.w[1]]) & Lut::YUV_MASK) ? 0x02U : 0x0U) | (b.w[4] != b.w[2] && ((yuv5 - lut.yuv[b.w[2]]) & Lut::YUV_MASK) ? 0x04U : 0x0U) | (b.w[4] != b.w[3] && ((yuv5 - lut.yuv[b.w[3]]) & Lut::YUV_MASK) ? 0x08U : 0x0U) | (b.w[4] != b.w[5] && ((yuv5 - lut.yuv[b.w[5]]) & Lut::YUV_MASK) ? 0x10U : 0x0U) | (b.w[4] != b.w[6] && ((yuv5 - lut.yuv[b.w[6]]) & Lut::YUV_MASK) ? 0x20U : 0x0U) | (b.w[4] != b.w[7] && ((yuv5 - lut.yuv[b.w[7]]) & Lut::YUV_MASK) ? 0x40U : 0x0U) | (b.w[4] != b.w[8] && ((yuv5 - lut.yuv[b.w[8]]) & Lut::YUV_MASK) ? 0x80U : 0x0U) ) #define PIXEL00_0 dst[0][0] = b.c[4]; #define PIXEL00_11 dst[0][0] = Interpolate1( b.c[4], b.c[3] ); #define PIXEL00_12 dst[0][0] = Interpolate1( b.c[4], b.c[1] ); #define PIXEL00_20 dst[0][0] = Interpolate2( b.c[4], b.c[1], b.c[3] ); #define PIXEL00_50 dst[0][0] = Interpolate5( b.c[1], b.c[3] ); #define PIXEL00_80 dst[0][0] = Interpolate8( b.c[4], b.c[0] ); #define PIXEL00_81 dst[0][0] = Interpolate8( b.c[4], b.c[3] ); #define PIXEL00_82 dst[0][0] = Interpolate8( b.c[4], b.c[1] ); #define PIXEL01_0 dst[0][1] = b.c[4]; #define PIXEL01_10 dst[0][1] = Interpolate1( b.c[4], b.c[0] ); #define PIXEL01_12 dst[0][1] = Interpolate1( b.c[4], b.c[1] ); #define PIXEL01_14 dst[0][1] = Interpolate1( b.c[1], b.c[4] ); #define PIXEL01_21 dst[0][1] = Interpolate2( b.c[1], b.c[4], b.c[3] ); #define PIXEL01_31 dst[0][1] = Interpolate3( b.c[4], b.c[3] ); #define PIXEL01_50 dst[0][1] = Interpolate5( b.c[1], b.c[4] ); #define PIXEL01_60 dst[0][1] = Interpolate6( b.c[4], b.c[1], b.c[3] ); #define PIXEL01_61 dst[0][1] = Interpolate6( b.c[4], b.c[1], b.c[0] ); #define PIXEL01_82 dst[0][1] = Interpolate8( b.c[4], b.c[1] ); #define PIXEL01_83 dst[0][1] = Interpolate8( b.c[1], b.c[3] ); #define PIXEL02_0 dst[0][2] = b.c[4]; #define PIXEL02_10 dst[0][2] = Interpolate1( b.c[4], b.c[2] ); #define PIXEL02_11 dst[0][2] = Interpolate1( b.c[4], b.c[1] ); #define PIXEL02_13 dst[0][2] = Interpolate1( b.c[1], b.c[4] ); #define PIXEL02_21 dst[0][2] = Interpolate2( b.c[1], b.c[4], b.c[5] ); #define PIXEL02_32 dst[0][2] = Interpolate3( b.c[4], b.c[5] ); #define PIXEL02_50 dst[0][2] = Interpolate5( b.c[1], b.c[4] ); #define PIXEL02_60 dst[0][2] = Interpolate6( b.c[4], b.c[1], b.c[5] ); #define PIXEL02_61 dst[0][2] = Interpolate6( b.c[4], b.c[1], b.c[2] ); #define PIXEL02_81 dst[0][2] = Interpolate8( b.c[4], b.c[1] ); #define PIXEL02_83 dst[0][2] = Interpolate8( b.c[1], b.c[5] ); #define PIXEL03_0 dst[0][3] = b.c[4]; #define PIXEL03_11 dst[0][3] = Interpolate1( b.c[4], b.c[1] ); #define PIXEL03_12 dst[0][3] = Interpolate1( b.c[4], b.c[5] ); #define PIXEL03_20 dst[0][3] = Interpolate2( b.c[4], b.c[1], b.c[5] ); #define PIXEL03_50 dst[0][3] = Interpolate5( b.c[1], b.c[5] ); #define PIXEL03_80 dst[0][3] = Interpolate8( b.c[4], b.c[2] ); #define PIXEL03_81 dst[0][3] = Interpolate8( b.c[4], b.c[1] ); #define PIXEL03_82 dst[0][3] = Interpolate8( b.c[4], b.c[5] ); #define PIXEL10_0 dst[1][0] = b.c[4]; #define PIXEL10_10 dst[1][0] = Interpolate1( b.c[4], b.c[0] ); #define PIXEL10_11 dst[1][0] = Interpolate1( b.c[4], b.c[3] ); #define PIXEL10_13 dst[1][0] = Interpolate1( b.c[3], b.c[4] ); #define PIXEL10_21 dst[1][0] = Interpolate2( b.c[3], b.c[4], b.c[1]); #define PIXEL10_32 dst[1][0] = Interpolate3( b.c[4], b.c[1] ); #define PIXEL10_50 dst[1][0] = Interpolate5( b.c[3], b.c[4] ); #define PIXEL10_60 dst[1][0] = Interpolate6( b.c[4], b.c[3], b.c[1] ); #define PIXEL10_61 dst[1][0] = Interpolate6( b.c[4], b.c[3], b.c[0] ); #define PIXEL10_81 dst[1][0] = Interpolate8( b.c[4], b.c[3] ); #define PIXEL10_83 dst[1][0] = Interpolate8( b.c[3], b.c[1] ); #define PIXEL11_0 dst[1][1] = b.c[4]; #define PIXEL11_30 dst[1][1] = Interpolate3( b.c[4], b.c[0] ); #define PIXEL11_31 dst[1][1] = Interpolate3( b.c[4], b.c[3] ); #define PIXEL11_32 dst[1][1] = Interpolate3( b.c[4], b.c[1] ); #define PIXEL11_70 dst[1][1] = Interpolate7( b.c[4], b.c[3], b.c[1] ); #define PIXEL12_0 dst[1][2] = b.c[4]; #define PIXEL12_30 dst[1][2] = Interpolate3( b.c[4], b.c[2] ); #define PIXEL12_31 dst[1][2] = Interpolate3( b.c[4], b.c[1] ); #define PIXEL12_32 dst[1][2] = Interpolate3( b.c[4], b.c[5] ); #define PIXEL12_70 dst[1][2] = Interpolate7( b.c[4], b.c[5], b.c[1] ); #define PIXEL13_0 dst[1][3] = b.c[4]; #define PIXEL13_10 dst[1][3] = Interpolate1( b.c[4], b.c[2] ); #define PIXEL13_12 dst[1][3] = Interpolate1( b.c[4], b.c[5] ); #define PIXEL13_14 dst[1][3] = Interpolate1( b.c[5], b.c[4] ); #define PIXEL13_21 dst[1][3] = Interpolate2( b.c[5], b.c[4], b.c[1] ); #define PIXEL13_31 dst[1][3] = Interpolate3( b.c[4], b.c[1] ); #define PIXEL13_50 dst[1][3] = Interpolate5( b.c[5], b.c[4] ); #define PIXEL13_60 dst[1][3] = Interpolate6( b.c[4], b.c[5], b.c[1] ); #define PIXEL13_61 dst[1][3] = Interpolate6( b.c[4], b.c[5], b.c[2] ); #define PIXEL13_82 dst[1][3] = Interpolate8( b.c[4], b.c[5] ); #define PIXEL13_83 dst[1][3] = Interpolate8( b.c[5], b.c[1] ); #define PIXEL20_0 dst[2][0] = b.c[4]; #define PIXEL20_10 dst[2][0] = Interpolate1( b.c[4], b.c[6] ); #define PIXEL20_12 dst[2][0] = Interpolate1( b.c[4], b.c[3] ); #define PIXEL20_14 dst[2][0] = Interpolate1( b.c[3], b.c[4] ); #define PIXEL20_21 dst[2][0] = Interpolate2( b.c[3], b.c[4], b.c[7] ); #define PIXEL20_31 dst[2][0] = Interpolate3( b.c[4], b.c[7] ); #define PIXEL20_50 dst[2][0] = Interpolate5( b.c[3], b.c[4] ); #define PIXEL20_60 dst[2][0] = Interpolate6( b.c[4], b.c[3], b.c[7] ); #define PIXEL20_61 dst[2][0] = Interpolate6( b.c[4], b.c[3], b.c[6] ); #define PIXEL20_82 dst[2][0] = Interpolate8( b.c[4], b.c[3] ); #define PIXEL20_83 dst[2][0] = Interpolate8( b.c[3], b.c[7] ); #define PIXEL21_0 dst[2][1] = b.c[4]; #define PIXEL21_30 dst[2][1] = Interpolate3( b.c[4], b.c[6] ); #define PIXEL21_31 dst[2][1] = Interpolate3( b.c[4], b.c[7] ); #define PIXEL21_32 dst[2][1] = Interpolate3( b.c[4], b.c[3] ); #define PIXEL21_70 dst[2][1] = Interpolate7( b.c[4], b.c[3], b.c[7] ); #define PIXEL22_0 dst[2][2] = b.c[4]; #define PIXEL22_30 dst[2][2] = Interpolate3( b.c[4], b.c[8] ); #define PIXEL22_31 dst[2][2] = Interpolate3( b.c[4], b.c[5] ); #define PIXEL22_32 dst[2][2] = Interpolate3( b.c[4], b.c[7] ); #define PIXEL22_70 dst[2][2] = Interpolate7( b.c[4], b.c[5], b.c[7]); #define PIXEL23_0 dst[2][3] = b.c[4]; #define PIXEL23_10 dst[2][3] = Interpolate1( b.c[4], b.c[8]); #define PIXEL23_11 dst[2][3] = Interpolate1( b.c[4], b.c[5]); #define PIXEL23_13 dst[2][3] = Interpolate1( b.c[5], b.c[4]); #define PIXEL23_21 dst[2][3] = Interpolate2( b.c[5], b.c[4], b.c[7] ); #define PIXEL23_32 dst[2][3] = Interpolate3( b.c[4], b.c[7] ); #define PIXEL23_50 dst[2][3] = Interpolate5( b.c[5], b.c[4] ); #define PIXEL23_60 dst[2][3] = Interpolate6( b.c[4], b.c[5], b.c[7] ); #define PIXEL23_61 dst[2][3] = Interpolate6( b.c[4], b.c[5], b.c[8] ); #define PIXEL23_81 dst[2][3] = Interpolate8( b.c[4], b.c[5] ); #define PIXEL23_83 dst[2][3] = Interpolate8( b.c[5], b.c[7] ); #define PIXEL30_0 dst[3][0] = b.c[4]; #define PIXEL30_11 dst[3][0] = Interpolate1( b.c[4], b.c[7] ); #define PIXEL30_12 dst[3][0] = Interpolate1( b.c[4], b.c[3] ); #define PIXEL30_20 dst[3][0] = Interpolate2( b.c[4], b.c[7], b.c[3] ); #define PIXEL30_50 dst[3][0] = Interpolate5( b.c[7], b.c[3] ); #define PIXEL30_80 dst[3][0] = Interpolate8( b.c[4], b.c[6] ); #define PIXEL30_81 dst[3][0] = Interpolate8( b.c[4], b.c[7] ); #define PIXEL30_82 dst[3][0] = Interpolate8( b.c[4], b.c[3] ); #define PIXEL31_0 dst[3][1] = b.c[4]; #define PIXEL31_10 dst[3][1] = Interpolate1( b.c[4], b.c[6] ); #define PIXEL31_11 dst[3][1] = Interpolate1( b.c[4], b.c[7] ); #define PIXEL31_13 dst[3][1] = Interpolate1( b.c[7], b.c[4] ); #define PIXEL31_21 dst[3][1] = Interpolate2( b.c[7], b.c[4], b.c[3] ); #define PIXEL31_32 dst[3][1] = Interpolate3( b.c[4], b.c[3] ); #define PIXEL31_50 dst[3][1] = Interpolate5( b.c[7], b.c[4] ); #define PIXEL31_60 dst[3][1] = Interpolate6( b.c[4], b.c[7], b.c[3] ); #define PIXEL31_61 dst[3][1] = Interpolate6( b.c[4], b.c[7], b.c[6] ); #define PIXEL31_81 dst[3][1] = Interpolate8( b.c[4], b.c[7] ); #define PIXEL31_83 dst[3][1] = Interpolate8( b.c[7], b.c[3] ); #define PIXEL32_0 dst[3][2] = b.c[4]; #define PIXEL32_10 dst[3][2] = Interpolate1( b.c[4], b.c[8] ); #define PIXEL32_12 dst[3][2] = Interpolate1( b.c[4], b.c[7] ); #define PIXEL32_14 dst[3][2] = Interpolate1( b.c[7], b.c[4] ); #define PIXEL32_21 dst[3][2] = Interpolate2( b.c[7], b.c[4], b.c[5] ); #define PIXEL32_31 dst[3][2] = Interpolate3( b.c[4], b.c[5] ); #define PIXEL32_50 dst[3][2] = Interpolate5( b.c[7], b.c[4] ); #define PIXEL32_60 dst[3][2] = Interpolate6( b.c[4], b.c[7], b.c[5] ); #define PIXEL32_61 dst[3][2] = Interpolate6( b.c[4], b.c[7], b.c[8] ); #define PIXEL32_82 dst[3][2] = Interpolate8( b.c[4], b.c[7] ); #define PIXEL32_83 dst[3][2] = Interpolate8( b.c[7], b.c[5] ); #define PIXEL33_0 dst[3][3] = b.c[4]; #define PIXEL33_11 dst[3][3] = Interpolate1( b.c[4], b.c[5] ); #define PIXEL33_12 dst[3][3] = Interpolate1( b.c[4], b.c[7] ); #define PIXEL33_20 dst[3][3] = Interpolate2( b.c[4], b.c[7], b.c[5] ); #define PIXEL33_50 dst[3][3] = Interpolate5( b.c[7], b.c[5] ); #define PIXEL33_80 dst[3][3] = Interpolate8( b.c[4], b.c[8] ); #define PIXEL33_81 dst[3][3] = Interpolate8( b.c[4], b.c[5] ); #define PIXEL33_82 dst[3][3] = Interpolate8( b.c[4], b.c[7] ); { case 0: case 1: case 4: case 32: case 128: case 5: case 132: case 160: case 33: case 129: case 36: case 133: case 164: case 161: case 37: case 165: PIXEL00_20 PIXEL01_60 PIXEL02_60 PIXEL03_20 PIXEL10_60 PIXEL11_70 PIXEL12_70 PIXEL13_60 PIXEL20_60 PIXEL21_70 PIXEL22_70 PIXEL23_60 PIXEL30_20 PIXEL31_60 PIXEL32_60 PIXEL33_20 break; case 2: case 34: case 130: case 162: PIXEL00_80 PIXEL01_10 PIXEL02_10 PIXEL03_80 PIXEL10_61 PIXEL11_30 PIXEL12_30 PIXEL13_61 PIXEL20_60 PIXEL21_70 PIXEL22_70 PIXEL23_60 PIXEL30_20 PIXEL31_60 PIXEL32_60 PIXEL33_20 break; case 16: case 17: case 48: case 49: PIXEL00_20 PIXEL01_60 PIXEL02_61 PIXEL03_80 PIXEL10_60 PIXEL11_70 PIXEL12_30 PIXEL13_10 PIXEL20_60 PIXEL21_70 PIXEL22_30 PIXEL23_10 PIXEL30_20 PIXEL31_60 PIXEL32_61 PIXEL33_80 break; case 64: case 65: case 68: case 69: PIXEL00_20 PIXEL01_60 PIXEL02_60 PIXEL03_20 PIXEL10_60 PIXEL11_70 PIXEL12_70 PIXEL13_60 PIXEL20_61 PIXEL21_30 PIXEL22_30 PIXEL23_61 PIXEL30_80 PIXEL31_10 PIXEL32_10 PIXEL33_80 break; case 8: case 12: case 136: case 140: PIXEL00_80 PIXEL01_61 PIXEL02_60 PIXEL03_20 PIXEL10_10 PIXEL11_30 PIXEL12_70 PIXEL13_60 PIXEL20_10 PIXEL21_30 PIXEL22_70 PIXEL23_60 PIXEL30_80 PIXEL31_61 PIXEL32_60 PIXEL33_20 break; case 3: case 35: case 131: case 163: PIXEL00_81 PIXEL01_31 PIXEL02_10 PIXEL03_80 PIXEL10_81 PIXEL11_31 PIXEL12_30 PIXEL13_61 PIXEL20_60 PIXEL21_70 PIXEL22_70 PIXEL23_60 PIXEL30_20 PIXEL31_60 PIXEL32_60 PIXEL33_20 break; case 6: case 38: case 134: case 166: PIXEL00_80 PIXEL01_10 PIXEL02_32 PIXEL03_82 PIXEL10_61 PIXEL11_30 PIXEL12_32 PIXEL13_82 PIXEL20_60 PIXEL21_70 PIXEL22_70 PIXEL23_60 PIXEL30_20 PIXEL31_60 PIXEL32_60 PIXEL33_20 break; case 20: case 21: case 52: case 53: PIXEL00_20 PIXEL01_60 PIXEL02_81 PIXEL03_81 PIXEL10_60 PIXEL11_70 PIXEL12_31 PIXEL13_31 PIXEL20_60 PIXEL21_70 PIXEL22_30 PIXEL23_10 PIXEL30_20 PIXEL31_60 PIXEL32_61 PIXEL33_80 break; case 144: case 145: case 176: case 177: PIXEL00_20 PIXEL01_60 PIXEL02_61 PIXEL03_80 PIXEL10_60 PIXEL11_70 PIXEL12_30 PIXEL13_10 PIXEL20_60 PIXEL21_70 PIXEL22_32 PIXEL23_32 PIXEL30_20 PIXEL31_60 PIXEL32_82 PIXEL33_82 break; case 192: case 193: case 196: case 197: PIXEL00_20 PIXEL01_60 PIXEL02_60 PIXEL03_20 PIXEL10_60 PIXEL11_70 PIXEL12_70 PIXEL13_60 PIXEL20_61 PIXEL21_30 PIXEL22_31 PIXEL23_81 PIXEL30_80 PIXEL31_10 PIXEL32_31 PIXEL33_81 break; case 96: case 97: case 100: case 101: PIXEL00_20 PIXEL01_60 PIXEL02_60 PIXEL03_20 PIXEL10_60 PIXEL11_70 PIXEL12_70 PIXEL13_60 PIXEL20_82 PIXEL21_32 PIXEL22_30 PIXEL23_61 PIXEL30_82 PIXEL31_32 PIXEL32_10 PIXEL33_80 break; case 40: case 44: case 168: case 172: PIXEL00_80 PIXEL01_61 PIXEL02_60 PIXEL03_20 PIXEL10_10 PIXEL11_30 PIXEL12_70 PIXEL13_60 PIXEL20_31 PIXEL21_31 PIXEL22_70 PIXEL23_60 PIXEL30_81 PIXEL31_81 PIXEL32_60 PIXEL33_20 break; case 9: case 13: case 137: case 141: PIXEL00_82 PIXEL01_82 PIXEL02_60 PIXEL03_20 PIXEL10_32 PIXEL11_32 PIXEL12_70 PIXEL13_60 PIXEL20_10 PIXEL21_30 PIXEL22_70 PIXEL23_60 PIXEL30_80 PIXEL31_61 PIXEL32_60 PIXEL33_20 break; case 18: case 50: PIXEL00_80 PIXEL01_10 if (Diff( b.w[1], b.w[5] )) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_50 PIXEL03_50 PIXEL12_0 PIXEL13_50 } PIXEL10_61 PIXEL11_30 PIXEL20_60 PIXEL21_70 PIXEL22_30 PIXEL23_10 PIXEL30_20 PIXEL31_60 PIXEL32_61 PIXEL33_80 break; case 80: case 81: PIXEL00_20 PIXEL01_60 PIXEL02_61 PIXEL03_80 PIXEL10_60 PIXEL11_70 PIXEL12_30 PIXEL13_10 PIXEL20_61 PIXEL21_30 if (Diff( b.w[5], b.w[7] )) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; case 72: case 76: PIXEL00_80 PIXEL01_61 PIXEL02_60 PIXEL03_20 PIXEL10_10 PIXEL11_30 PIXEL12_70 PIXEL13_60 if (Diff( b.w[7], b.w[3] )) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_50 PIXEL21_0 PIXEL30_50 PIXEL31_50 } PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; case 10: case 138: if (Diff( b.w[3], b.w[1] )) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 PIXEL11_0 } PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_61 PIXEL20_10 PIXEL21_30 PIXEL22_70 PIXEL23_60 PIXEL30_80 PIXEL31_61 PIXEL32_60 PIXEL33_20 break; case 66: PIXEL00_80 PIXEL01_10 PIXEL02_10 PIXEL03_80 PIXEL10_61 PIXEL11_30 PIXEL12_30 PIXEL13_61 PIXEL20_61 PIXEL21_30 PIXEL22_30 PIXEL23_61 PIXEL30_80 PIXEL31_10 PIXEL32_10 PIXEL33_80 break; case 24: PIXEL00_80 PIXEL01_61 PIXEL02_61 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_61 PIXEL32_61 PIXEL33_80 break; case 7: case 39: case 135: PIXEL00_81 PIXEL01_31 PIXEL02_32 PIXEL03_82 PIXEL10_81 PIXEL11_31 PIXEL12_32 PIXEL13_82 PIXEL20_60 PIXEL21_70 PIXEL22_70 PIXEL23_60 PIXEL30_20 PIXEL31_60 PIXEL32_60 PIXEL33_20 break; case 148: case 149: case 180: PIXEL00_20 PIXEL01_60 PIXEL02_81 PIXEL03_81 PIXEL10_60 PIXEL11_70 PIXEL12_31 PIXEL13_31 PIXEL20_60 PIXEL21_70 PIXEL22_32 PIXEL23_32 PIXEL30_20 PIXEL31_60 PIXEL32_82 PIXEL33_82 break; case 224: case 228: case 225: PIXEL00_20 PIXEL01_60 PIXEL02_60 PIXEL03_20 PIXEL10_60 PIXEL11_70 PIXEL12_70 PIXEL13_60 PIXEL20_82 PIXEL21_32 PIXEL22_31 PIXEL23_81 PIXEL30_82 PIXEL31_32 PIXEL32_31 PIXEL33_81 break; case 41: case 169: case 45: PIXEL00_82 PIXEL01_82 PIXEL02_60 PIXEL03_20 PIXEL10_32 PIXEL11_32 PIXEL12_70 PIXEL13_60 PIXEL20_31 PIXEL21_31 PIXEL22_70 PIXEL23_60 PIXEL30_81 PIXEL31_81 PIXEL32_60 PIXEL33_20 break; case 22: case 54: PIXEL00_80 PIXEL01_10 if (Diff( b.w[1], b.w[5] )) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_61 PIXEL11_30 PIXEL12_0 PIXEL20_60 PIXEL21_70 PIXEL22_30 PIXEL23_10 PIXEL30_20 PIXEL31_60 PIXEL32_61 PIXEL33_80 break; case 208: case 209: PIXEL00_20 PIXEL01_60 PIXEL02_61 PIXEL03_80 PIXEL10_60 PIXEL11_70 PIXEL12_30 PIXEL13_10 PIXEL20_61 PIXEL21_30 PIXEL22_0 if (Diff( b.w[5], b.w[7] )) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; case 104: case 108: PIXEL00_80 PIXEL01_61 PIXEL02_60 PIXEL03_20 PIXEL10_10 PIXEL11_30 PIXEL12_70 PIXEL13_60 if (Diff( b.w[7], b.w[3] )) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; case 11: case 139: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_61 PIXEL20_10 PIXEL21_30 PIXEL22_70 PIXEL23_60 PIXEL30_80 PIXEL31_61 PIXEL32_60 PIXEL33_20 break; case 19: case 51: if (Diff( b.w[1], b.w[5] )) { PIXEL00_81 PIXEL01_31 PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL00_12 PIXEL01_14 PIXEL02_83 PIXEL03_50 PIXEL12_70 PIXEL13_21 } PIXEL10_81 PIXEL11_31 PIXEL20_60 PIXEL21_70 PIXEL22_30 PIXEL23_10 PIXEL30_20 PIXEL31_60 PIXEL32_61 PIXEL33_80 break; case 146: case 178: { PIXEL00_80 PIXEL01_10 if (Diff( b.w[1], b.w[5] )) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 PIXEL23_32 PIXEL33_82 } else { PIXEL02_21 PIXEL03_50 PIXEL12_70 PIXEL13_83 PIXEL23_13 PIXEL33_11 } PIXEL10_61 PIXEL11_30 PIXEL20_60 PIXEL21_70 PIXEL22_32 PIXEL30_20 PIXEL31_60 PIXEL32_82 break; } case 84: case 85: PIXEL00_20 PIXEL01_60 PIXEL02_81 if (Diff( b.w[5], b.w[7] )) { PIXEL03_81 PIXEL13_31 PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL03_12 PIXEL13_14 PIXEL22_70 PIXEL23_83 PIXEL32_21 PIXEL33_50 } PIXEL10_60 PIXEL11_70 PIXEL12_31 PIXEL20_61 PIXEL21_30 PIXEL30_80 PIXEL31_10 break; case 112: case 113: PIXEL00_20 PIXEL01_60 PIXEL02_61 PIXEL03_80 PIXEL10_60 PIXEL11_70 PIXEL12_30 PIXEL13_10 PIXEL20_82 PIXEL21_32 if (Diff( b.w[5], b.w[7] )) { PIXEL22_30 PIXEL23_10 PIXEL30_82 PIXEL31_32 PIXEL32_10 PIXEL33_80 } else { PIXEL22_70 PIXEL23_21 PIXEL30_11 PIXEL31_13 PIXEL32_83 PIXEL33_50 } break; case 200: case 204: PIXEL00_80 PIXEL01_61 PIXEL02_60 PIXEL03_20 PIXEL10_10 PIXEL11_30 PIXEL12_70 PIXEL13_60 if (Diff( b.w[7], b.w[3] )) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 PIXEL32_31 PIXEL33_81 } else { PIXEL20_21 PIXEL21_70 PIXEL30_50 PIXEL31_83 PIXEL32_14 PIXEL33_12 } PIXEL22_31 PIXEL23_81 break; case 73: case 77: if (Diff( b.w[7], b.w[3] )) { PIXEL00_82 PIXEL10_32 PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL00_11 PIXEL10_13 PIXEL20_83 PIXEL21_70 PIXEL30_50 PIXEL31_21 } PIXEL01_82 PIXEL02_60 PIXEL03_20 PIXEL11_32 PIXEL12_70 PIXEL13_60 PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; case 42: case 170: if (Diff( b.w[3], b.w[1] )) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 PIXEL20_31 PIXEL30_81 } else { PIXEL00_50 PIXEL01_21 PIXEL10_83 PIXEL11_70 PIXEL20_14 PIXEL30_12 } PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_61 PIXEL21_31 PIXEL22_70 PIXEL23_60 PIXEL31_81 PIXEL32_60 PIXEL33_20 break; case 14: case 142: if (Diff( b.w[3], b.w[1] )) { PIXEL00_80 PIXEL01_10 PIXEL02_32 PIXEL03_82 PIXEL10_10 PIXEL11_30 } else { PIXEL00_50 PIXEL01_83 PIXEL02_13 PIXEL03_11 PIXEL10_21 PIXEL11_70 } PIXEL12_32 PIXEL13_82 PIXEL20_10 PIXEL21_30 PIXEL22_70 PIXEL23_60 PIXEL30_80 PIXEL31_61 PIXEL32_60 PIXEL33_20 break; case 67: PIXEL00_81 PIXEL01_31 PIXEL02_10 PIXEL03_80 PIXEL10_81 PIXEL11_31 PIXEL12_30 PIXEL13_61 PIXEL20_61 PIXEL21_30 PIXEL22_30 PIXEL23_61 PIXEL30_80 PIXEL31_10 PIXEL32_10 PIXEL33_80 break; case 70: PIXEL00_80 PIXEL01_10 PIXEL02_32 PIXEL03_82 PIXEL10_61 PIXEL11_30 PIXEL12_32 PIXEL13_82 PIXEL20_61 PIXEL21_30 PIXEL22_30 PIXEL23_61 PIXEL30_80 PIXEL31_10 PIXEL32_10 PIXEL33_80 break; case 28: PIXEL00_80 PIXEL01_61 PIXEL02_81 PIXEL03_81 PIXEL10_10 PIXEL11_30 PIXEL12_31 PIXEL13_31 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_61 PIXEL32_61 PIXEL33_80 break; case 152: PIXEL00_80 PIXEL01_61 PIXEL02_61 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_32 PIXEL23_32 PIXEL30_80 PIXEL31_61 PIXEL32_82 PIXEL33_82 break; case 194: PIXEL00_80 PIXEL01_10 PIXEL02_10 PIXEL03_80 PIXEL10_61 PIXEL11_30 PIXEL12_30 PIXEL13_61 PIXEL20_61 PIXEL21_30 PIXEL22_31 PIXEL23_81 PIXEL30_80 PIXEL31_10 PIXEL32_31 PIXEL33_81 break; case 98: PIXEL00_80 PIXEL01_10 PIXEL02_10 PIXEL03_80 PIXEL10_61 PIXEL11_30 PIXEL12_30 PIXEL13_61 PIXEL20_82 PIXEL21_32 PIXEL22_30 PIXEL23_61 PIXEL30_82 PIXEL31_32 PIXEL32_10 PIXEL33_80 break; case 56: PIXEL00_80 PIXEL01_61 PIXEL02_61 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_10 PIXEL20_31 PIXEL21_31 PIXEL22_30 PIXEL23_10 PIXEL30_81 PIXEL31_81 PIXEL32_61 PIXEL33_80 break; case 25: PIXEL00_82 PIXEL01_82 PIXEL02_61 PIXEL03_80 PIXEL10_32 PIXEL11_32 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_61 PIXEL32_61 PIXEL33_80 break; case 26: case 31: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } if (Diff( b.w[1], b.w[5] )) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL11_0 PIXEL12_0 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_61 PIXEL32_61 PIXEL33_80 break; case 82: case 214: PIXEL00_80 PIXEL01_10 if (Diff( b.w[1], b.w[5] )) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_61 PIXEL11_30 PIXEL12_0 PIXEL20_61 PIXEL21_30 PIXEL22_0 if (Diff( b.w[5], b.w[7] )) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; case 88: case 248: PIXEL00_80 PIXEL01_61 PIXEL02_61 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_10 if (Diff( b.w[7], b.w[3] )) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_0 if (Diff( b.w[5], b.w[7] )) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } break; case 74: case 107: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_61 if (Diff( b.w[7], b.w[3] )) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; case 27: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_61 PIXEL32_61 PIXEL33_80 break; case 86: PIXEL00_80 PIXEL01_10 if (Diff( b.w[1], b.w[5] )) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_61 PIXEL11_30 PIXEL12_0 PIXEL20_61 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_10 PIXEL32_10 PIXEL33_80 break; case 216: PIXEL00_80 PIXEL01_61 PIXEL02_61 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_0 if (Diff( b.w[5], b.w[7] )) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; case 106: PIXEL00_80 PIXEL01_10 PIXEL02_10 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_61 if (Diff( b.w[7], b.w[3] )) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; case 30: PIXEL00_80 PIXEL01_10 if (Diff( b.w[1], b.w[5] )) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_10 PIXEL11_30 PIXEL12_0 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_61 PIXEL32_61 PIXEL33_80 break; case 210: PIXEL00_80 PIXEL01_10 PIXEL02_10 PIXEL03_80 PIXEL10_61 PIXEL11_30 PIXEL12_30 PIXEL13_10 PIXEL20_61 PIXEL21_30 PIXEL22_0 if (Diff( b.w[5], b.w[7] )) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; case 120: PIXEL00_80 PIXEL01_61 PIXEL02_61 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_10 if (Diff( b.w[7], b.w[3] )) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 break; case 75: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_61 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_61 PIXEL30_80 PIXEL31_10 PIXEL32_10 PIXEL33_80 break; case 29: PIXEL00_82 PIXEL01_82 PIXEL02_81 PIXEL03_81 PIXEL10_32 PIXEL11_32 PIXEL12_31 PIXEL13_31 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_61 PIXEL32_61 PIXEL33_80 break; case 198: PIXEL00_80 PIXEL01_10 PIXEL02_32 PIXEL03_82 PIXEL10_61 PIXEL11_30 PIXEL12_32 PIXEL13_82 PIXEL20_61 PIXEL21_30 PIXEL22_31 PIXEL23_81 PIXEL30_80 PIXEL31_10 PIXEL32_31 PIXEL33_81 break; case 184: PIXEL00_80 PIXEL01_61 PIXEL02_61 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_10 PIXEL20_31 PIXEL21_31 PIXEL22_32 PIXEL23_32 PIXEL30_81 PIXEL31_81 PIXEL32_82 PIXEL33_82 break; case 99: PIXEL00_81 PIXEL01_31 PIXEL02_10 PIXEL03_80 PIXEL10_81 PIXEL11_31 PIXEL12_30 PIXEL13_61 PIXEL20_82 PIXEL21_32 PIXEL22_30 PIXEL23_61 PIXEL30_82 PIXEL31_32 PIXEL32_10 PIXEL33_80 break; case 57: PIXEL00_82 PIXEL01_82 PIXEL02_61 PIXEL03_80 PIXEL10_32 PIXEL11_32 PIXEL12_30 PIXEL13_10 PIXEL20_31 PIXEL21_31 PIXEL22_30 PIXEL23_10 PIXEL30_81 PIXEL31_81 PIXEL32_61 PIXEL33_80 break; case 71: PIXEL00_81 PIXEL01_31 PIXEL02_32 PIXEL03_82 PIXEL10_81 PIXEL11_31 PIXEL12_32 PIXEL13_82 PIXEL20_61 PIXEL21_30 PIXEL22_30 PIXEL23_61 PIXEL30_80 PIXEL31_10 PIXEL32_10 PIXEL33_80 break; case 156: PIXEL00_80 PIXEL01_61 PIXEL02_81 PIXEL03_81 PIXEL10_10 PIXEL11_30 PIXEL12_31 PIXEL13_31 PIXEL20_10 PIXEL21_30 PIXEL22_32 PIXEL23_32 PIXEL30_80 PIXEL31_61 PIXEL32_82 PIXEL33_82 break; case 226: PIXEL00_80 PIXEL01_10 PIXEL02_10 PIXEL03_80 PIXEL10_61 PIXEL11_30 PIXEL12_30 PIXEL13_61 PIXEL20_82 PIXEL21_32 PIXEL22_31 PIXEL23_81 PIXEL30_82 PIXEL31_32 PIXEL32_31 PIXEL33_81 break; case 60: PIXEL00_80 PIXEL01_61 PIXEL02_81 PIXEL03_81 PIXEL10_10 PIXEL11_30 PIXEL12_31 PIXEL13_31 PIXEL20_31 PIXEL21_31 PIXEL22_30 PIXEL23_10 PIXEL30_81 PIXEL31_81 PIXEL32_61 PIXEL33_80 break; case 195: PIXEL00_81 PIXEL01_31 PIXEL02_10 PIXEL03_80 PIXEL10_81 PIXEL11_31 PIXEL12_30 PIXEL13_61 PIXEL20_61 PIXEL21_30 PIXEL22_31 PIXEL23_81 PIXEL30_80 PIXEL31_10 PIXEL32_31 PIXEL33_81 break; case 102: PIXEL00_80 PIXEL01_10 PIXEL02_32 PIXEL03_82 PIXEL10_61 PIXEL11_30 PIXEL12_32 PIXEL13_82 PIXEL20_82 PIXEL21_32 PIXEL22_30 PIXEL23_61 PIXEL30_82 PIXEL31_32 PIXEL32_10 PIXEL33_80 break; case 153: PIXEL00_82 PIXEL01_82 PIXEL02_61 PIXEL03_80 PIXEL10_32 PIXEL11_32 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_32 PIXEL23_32 PIXEL30_80 PIXEL31_61 PIXEL32_82 PIXEL33_82 break; case 58: if (Diff( b.w[3], b.w[1] )) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } if (Diff( b.w[1], b.w[5] )) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL20_31 PIXEL21_31 PIXEL22_30 PIXEL23_10 PIXEL30_81 PIXEL31_81 PIXEL32_61 PIXEL33_80 break; case 83: PIXEL00_81 PIXEL01_31 if (Diff( b.w[1], b.w[5] )) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL10_81 PIXEL11_31 PIXEL20_61 PIXEL21_30 if (Diff( b.w[5], b.w[7] )) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } PIXEL30_80 PIXEL31_10 break; case 92: PIXEL00_80 PIXEL01_61 PIXEL02_81 PIXEL03_81 PIXEL10_10 PIXEL11_30 PIXEL12_31 PIXEL13_31 if (Diff( b.w[7], b.w[3] )) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } if (Diff( b.w[5], b.w[7] )) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } break; case 202: if (Diff( b.w[3], b.w[1] )) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_61 if (Diff( b.w[7], b.w[3] )) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } PIXEL22_31 PIXEL23_81 PIXEL32_31 PIXEL33_81 break; case 78: if (Diff( b.w[3], b.w[1] )) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } PIXEL02_32 PIXEL03_82 PIXEL12_32 PIXEL13_82 if (Diff( b.w[7], b.w[3] )) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; case 154: if (Diff( b.w[3], b.w[1] )) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } if (Diff( b.w[1], b.w[5] )) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL20_10 PIXEL21_30 PIXEL22_32 PIXEL23_32 PIXEL30_80 PIXEL31_61 PIXEL32_82 PIXEL33_82 break; case 114: PIXEL00_80 PIXEL01_10 if (Diff( b.w[1], b.w[5] )) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL10_61 PIXEL11_30 PIXEL20_82 PIXEL21_32 if (Diff( b.w[5], b.w[7] )) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } PIXEL30_82 PIXEL31_32 break; case 89: PIXEL00_82 PIXEL01_82 PIXEL02_61 PIXEL03_80 PIXEL10_32 PIXEL11_32 PIXEL12_30 PIXEL13_10 if (Diff( b.w[7], b.w[3] )) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } if (Diff( b.w[5], b.w[7] )) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } break; case 90: if (Diff( b.w[3], b.w[1] )) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } if (Diff( b.w[1], b.w[5] )) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } if (Diff( b.w[7], b.w[3] )) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } if (Diff( b.w[5], b.w[7] )) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } break; case 55: case 23: if (Diff( b.w[1], b.w[5] )) { PIXEL00_81 PIXEL01_31 PIXEL02_0 PIXEL03_0 PIXEL12_0 PIXEL13_0 } else { PIXEL00_12 PIXEL01_14 PIXEL02_83 PIXEL03_50 PIXEL12_70 PIXEL13_21 } PIXEL10_81 PIXEL11_31 PIXEL20_60 PIXEL21_70 PIXEL22_30 PIXEL23_10 PIXEL30_20 PIXEL31_60 PIXEL32_61 PIXEL33_80 break; case 182: case 150: PIXEL00_80 PIXEL01_10 if (Diff( b.w[1], b.w[5] )) { PIXEL02_0 PIXEL03_0 PIXEL12_0 PIXEL13_0 PIXEL23_32 PIXEL33_82 } else { PIXEL02_21 PIXEL03_50 PIXEL12_70 PIXEL13_83 PIXEL23_13 PIXEL33_11 } PIXEL10_61 PIXEL11_30 PIXEL20_60 PIXEL21_70 PIXEL22_32 PIXEL30_20 PIXEL31_60 PIXEL32_82 break; case 213: case 212: PIXEL00_20 PIXEL01_60 PIXEL02_81 if (Diff( b.w[5], b.w[7] )) { PIXEL03_81 PIXEL13_31 PIXEL22_0 PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL03_12 PIXEL13_14 PIXEL22_70 PIXEL23_83 PIXEL32_21 PIXEL33_50 } PIXEL10_60 PIXEL11_70 PIXEL12_31 PIXEL20_61 PIXEL21_30 PIXEL30_80 PIXEL31_10 break; case 241: case 240: PIXEL00_20 PIXEL01_60 PIXEL02_61 PIXEL03_80 PIXEL10_60 PIXEL11_70 PIXEL12_30 PIXEL13_10 PIXEL20_82 PIXEL21_32 if (Diff( b.w[5], b.w[7] )) { PIXEL22_0 PIXEL23_0 PIXEL30_82 PIXEL31_32 PIXEL32_0 PIXEL33_0 } else { PIXEL22_70 PIXEL23_21 PIXEL30_11 PIXEL31_13 PIXEL32_83 PIXEL33_50 } break; case 236: case 232: PIXEL00_80 PIXEL01_61 PIXEL02_60 PIXEL03_20 PIXEL10_10 PIXEL11_30 PIXEL12_70 PIXEL13_60 if (Diff( b.w[7], b.w[3] )) { PIXEL20_0 PIXEL21_0 PIXEL30_0 PIXEL31_0 PIXEL32_31 PIXEL33_81 } else { PIXEL20_21 PIXEL21_70 PIXEL30_50 PIXEL31_83 PIXEL32_14 PIXEL33_12 } PIXEL22_31 PIXEL23_81 break; case 109: case 105: if (Diff( b.w[7], b.w[3] )) { PIXEL00_82 PIXEL10_32 PIXEL20_0 PIXEL21_0 PIXEL30_0 PIXEL31_0 } else { PIXEL00_11 PIXEL10_13 PIXEL20_83 PIXEL21_70 PIXEL30_50 PIXEL31_21 } PIXEL01_82 PIXEL02_60 PIXEL03_20 PIXEL11_32 PIXEL12_70 PIXEL13_60 PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; case 171: case 43: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL01_0 PIXEL10_0 PIXEL11_0 PIXEL20_31 PIXEL30_81 } else { PIXEL00_50 PIXEL01_21 PIXEL10_83 PIXEL11_70 PIXEL20_14 PIXEL30_12 } PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_61 PIXEL21_31 PIXEL22_70 PIXEL23_60 PIXEL31_81 PIXEL32_60 PIXEL33_20 break; case 143: case 15: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL01_0 PIXEL02_32 PIXEL03_82 PIXEL10_0 PIXEL11_0 } else { PIXEL00_50 PIXEL01_83 PIXEL02_13 PIXEL03_11 PIXEL10_21 PIXEL11_70 } PIXEL12_32 PIXEL13_82 PIXEL20_10 PIXEL21_30 PIXEL22_70 PIXEL23_60 PIXEL30_80 PIXEL31_61 PIXEL32_60 PIXEL33_20 break; case 124: PIXEL00_80 PIXEL01_61 PIXEL02_81 PIXEL03_81 PIXEL10_10 PIXEL11_30 PIXEL12_31 PIXEL13_31 if (Diff( b.w[7], b.w[3] )) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 break; case 203: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_61 PIXEL20_10 PIXEL21_30 PIXEL22_31 PIXEL23_81 PIXEL30_80 PIXEL31_10 PIXEL32_31 PIXEL33_81 break; case 62: PIXEL00_80 PIXEL01_10 if (Diff( b.w[1], b.w[5] )) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_10 PIXEL11_30 PIXEL12_0 PIXEL20_31 PIXEL21_31 PIXEL22_30 PIXEL23_10 PIXEL30_81 PIXEL31_81 PIXEL32_61 PIXEL33_80 break; case 211: PIXEL00_81 PIXEL01_31 PIXEL02_10 PIXEL03_80 PIXEL10_81 PIXEL11_31 PIXEL12_30 PIXEL13_10 PIXEL20_61 PIXEL21_30 PIXEL22_0 if (Diff( b.w[5], b.w[7] )) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; case 118: PIXEL00_80 PIXEL01_10 if (Diff( b.w[1], b.w[5] )) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_61 PIXEL11_30 PIXEL12_0 PIXEL20_82 PIXEL21_32 PIXEL22_30 PIXEL23_10 PIXEL30_82 PIXEL31_32 PIXEL32_10 PIXEL33_80 break; case 217: PIXEL00_82 PIXEL01_82 PIXEL02_61 PIXEL03_80 PIXEL10_32 PIXEL11_32 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_0 if (Diff( b.w[5], b.w[7] )) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; case 110: PIXEL00_80 PIXEL01_10 PIXEL02_32 PIXEL03_82 PIXEL10_10 PIXEL11_30 PIXEL12_32 PIXEL13_82 if (Diff( b.w[7], b.w[3] )) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; case 155: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_32 PIXEL23_32 PIXEL30_80 PIXEL31_61 PIXEL32_82 PIXEL33_82 break; case 188: PIXEL00_80 PIXEL01_61 PIXEL02_81 PIXEL03_81 PIXEL10_10 PIXEL11_30 PIXEL12_31 PIXEL13_31 PIXEL20_31 PIXEL21_31 PIXEL22_32 PIXEL23_32 PIXEL30_81 PIXEL31_81 PIXEL32_82 PIXEL33_82 break; case 185: PIXEL00_82 PIXEL01_82 PIXEL02_61 PIXEL03_80 PIXEL10_32 PIXEL11_32 PIXEL12_30 PIXEL13_10 PIXEL20_31 PIXEL21_31 PIXEL22_32 PIXEL23_32 PIXEL30_81 PIXEL31_81 PIXEL32_82 PIXEL33_82 break; case 61: PIXEL00_82 PIXEL01_82 PIXEL02_81 PIXEL03_81 PIXEL10_32 PIXEL11_32 PIXEL12_31 PIXEL13_31 PIXEL20_31 PIXEL21_31 PIXEL22_30 PIXEL23_10 PIXEL30_81 PIXEL31_81 PIXEL32_61 PIXEL33_80 break; case 157: PIXEL00_82 PIXEL01_82 PIXEL02_81 PIXEL03_81 PIXEL10_32 PIXEL11_32 PIXEL12_31 PIXEL13_31 PIXEL20_10 PIXEL21_30 PIXEL22_32 PIXEL23_32 PIXEL30_80 PIXEL31_61 PIXEL32_82 PIXEL33_82 break; case 103: PIXEL00_81 PIXEL01_31 PIXEL02_32 PIXEL03_82 PIXEL10_81 PIXEL11_31 PIXEL12_32 PIXEL13_82 PIXEL20_82 PIXEL21_32 PIXEL22_30 PIXEL23_61 PIXEL30_82 PIXEL31_32 PIXEL32_10 PIXEL33_80 break; case 227: PIXEL00_81 PIXEL01_31 PIXEL02_10 PIXEL03_80 PIXEL10_81 PIXEL11_31 PIXEL12_30 PIXEL13_61 PIXEL20_82 PIXEL21_32 PIXEL22_31 PIXEL23_81 PIXEL30_82 PIXEL31_32 PIXEL32_31 PIXEL33_81 break; case 230: PIXEL00_80 PIXEL01_10 PIXEL02_32 PIXEL03_82 PIXEL10_61 PIXEL11_30 PIXEL12_32 PIXEL13_82 PIXEL20_82 PIXEL21_32 PIXEL22_31 PIXEL23_81 PIXEL30_82 PIXEL31_32 PIXEL32_31 PIXEL33_81 break; case 199: PIXEL00_81 PIXEL01_31 PIXEL02_32 PIXEL03_82 PIXEL10_81 PIXEL11_31 PIXEL12_32 PIXEL13_82 PIXEL20_61 PIXEL21_30 PIXEL22_31 PIXEL23_81 PIXEL30_80 PIXEL31_10 PIXEL32_31 PIXEL33_81 break; case 220: PIXEL00_80 PIXEL01_61 PIXEL02_81 PIXEL03_81 PIXEL10_10 PIXEL11_30 PIXEL12_31 PIXEL13_31 if (Diff( b.w[7], b.w[3] )) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } PIXEL22_0 if (Diff( b.w[5], b.w[7] )) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } break; case 158: if (Diff( b.w[3], b.w[1] )) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } if (Diff( b.w[1], b.w[5] )) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL12_0 PIXEL20_10 PIXEL21_30 PIXEL22_32 PIXEL23_32 PIXEL30_80 PIXEL31_61 PIXEL32_82 PIXEL33_82 break; case 234: if (Diff( b.w[3], b.w[1] )) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_61 if (Diff( b.w[7], b.w[3] )) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_31 PIXEL23_81 PIXEL32_31 PIXEL33_81 break; case 242: PIXEL00_80 PIXEL01_10 if (Diff( b.w[1], b.w[5] )) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL10_61 PIXEL11_30 PIXEL20_82 PIXEL21_32 PIXEL22_0 if (Diff( b.w[5], b.w[7] )) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_82 PIXEL31_32 break; case 59: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } if (Diff( b.w[1], b.w[5] )) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL11_0 PIXEL20_31 PIXEL21_31 PIXEL22_30 PIXEL23_10 PIXEL30_81 PIXEL31_81 PIXEL32_61 PIXEL33_80 break; case 121: PIXEL00_82 PIXEL01_82 PIXEL02_61 PIXEL03_80 PIXEL10_32 PIXEL11_32 PIXEL12_30 PIXEL13_10 if (Diff( b.w[7], b.w[3] )) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 if (Diff( b.w[5], b.w[7] )) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } break; case 87: PIXEL00_81 PIXEL01_31 if (Diff( b.w[1], b.w[5] )) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_81 PIXEL11_31 PIXEL12_0 PIXEL20_61 PIXEL21_30 if (Diff( b.w[5], b.w[7] )) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } PIXEL30_80 PIXEL31_10 break; case 79: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_32 PIXEL03_82 PIXEL11_0 PIXEL12_32 PIXEL13_82 if (Diff( b.w[7], b.w[3] )) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; case 122: if (Diff( b.w[3], b.w[1] )) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } if (Diff( b.w[1], b.w[5] )) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } if (Diff( b.w[7], b.w[3] )) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 if (Diff( b.w[5], b.w[7] )) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } break; case 94: if (Diff( b.w[3], b.w[1] )) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } if (Diff( b.w[1], b.w[5] )) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL12_0 if (Diff( b.w[7], b.w[3] )) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } if (Diff( b.w[5], b.w[7] )) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } break; case 218: if (Diff( b.w[3], b.w[1] )) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } if (Diff( b.w[1], b.w[5] )) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } if (Diff( b.w[7], b.w[3] )) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } PIXEL22_0 if (Diff( b.w[5], b.w[7] )) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } break; case 91: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } if (Diff( b.w[1], b.w[5] )) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL11_0 if (Diff( b.w[7], b.w[3] )) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } if (Diff( b.w[5], b.w[7] )) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } break; case 229: PIXEL00_20 PIXEL01_60 PIXEL02_60 PIXEL03_20 PIXEL10_60 PIXEL11_70 PIXEL12_70 PIXEL13_60 PIXEL20_82 PIXEL21_32 PIXEL22_31 PIXEL23_81 PIXEL30_82 PIXEL31_32 PIXEL32_31 PIXEL33_81 break; case 167: PIXEL00_81 PIXEL01_31 PIXEL02_32 PIXEL03_82 PIXEL10_81 PIXEL11_31 PIXEL12_32 PIXEL13_82 PIXEL20_60 PIXEL21_70 PIXEL22_70 PIXEL23_60 PIXEL30_20 PIXEL31_60 PIXEL32_60 PIXEL33_20 break; case 173: PIXEL00_82 PIXEL01_82 PIXEL02_60 PIXEL03_20 PIXEL10_32 PIXEL11_32 PIXEL12_70 PIXEL13_60 PIXEL20_31 PIXEL21_31 PIXEL22_70 PIXEL23_60 PIXEL30_81 PIXEL31_81 PIXEL32_60 PIXEL33_20 break; case 181: PIXEL00_20 PIXEL01_60 PIXEL02_81 PIXEL03_81 PIXEL10_60 PIXEL11_70 PIXEL12_31 PIXEL13_31 PIXEL20_60 PIXEL21_70 PIXEL22_32 PIXEL23_32 PIXEL30_20 PIXEL31_60 PIXEL32_82 PIXEL33_82 break; case 186: if (Diff( b.w[3], b.w[1] )) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } if (Diff( b.w[1], b.w[5] )) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL20_31 PIXEL21_31 PIXEL22_32 PIXEL23_32 PIXEL30_81 PIXEL31_81 PIXEL32_82 PIXEL33_82 break; case 115: PIXEL00_81 PIXEL01_31 if (Diff( b.w[1], b.w[5] )) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL10_81 PIXEL11_31 PIXEL20_82 PIXEL21_32 if (Diff( b.w[5], b.w[7] )) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } PIXEL30_82 PIXEL31_32 break; case 93: PIXEL00_82 PIXEL01_82 PIXEL02_81 PIXEL03_81 PIXEL10_32 PIXEL11_32 PIXEL12_31 PIXEL13_31 if (Diff( b.w[7], b.w[3] )) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } if (Diff( b.w[5], b.w[7] )) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } break; case 206: if (Diff( b.w[3], b.w[1] )) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } PIXEL02_32 PIXEL03_82 PIXEL12_32 PIXEL13_82 if (Diff( b.w[7], b.w[3] )) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } PIXEL22_31 PIXEL23_81 PIXEL32_31 PIXEL33_81 break; case 205: case 201: PIXEL00_82 PIXEL01_82 PIXEL02_60 PIXEL03_20 PIXEL10_32 PIXEL11_32 PIXEL12_70 PIXEL13_60 if (Diff( b.w[7], b.w[3] )) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } PIXEL22_31 PIXEL23_81 PIXEL32_31 PIXEL33_81 break; case 174: case 46: if (Diff( b.w[3], b.w[1] )) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } PIXEL02_32 PIXEL03_82 PIXEL12_32 PIXEL13_82 PIXEL20_31 PIXEL21_31 PIXEL22_70 PIXEL23_60 PIXEL30_81 PIXEL31_81 PIXEL32_60 PIXEL33_20 break; case 179: case 147: PIXEL00_81 PIXEL01_31 if (Diff( b.w[1], b.w[5] )) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL10_81 PIXEL11_31 PIXEL20_60 PIXEL21_70 PIXEL22_32 PIXEL23_32 PIXEL30_20 PIXEL31_60 PIXEL32_82 PIXEL33_82 break; case 117: case 116: PIXEL00_20 PIXEL01_60 PIXEL02_81 PIXEL03_81 PIXEL10_60 PIXEL11_70 PIXEL12_31 PIXEL13_31 PIXEL20_82 PIXEL21_32 if (Diff( b.w[5], b.w[7] )) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } PIXEL30_82 PIXEL31_32 break; case 189: PIXEL00_82 PIXEL01_82 PIXEL02_81 PIXEL03_81 PIXEL10_32 PIXEL11_32 PIXEL12_31 PIXEL13_31 PIXEL20_31 PIXEL21_31 PIXEL22_32 PIXEL23_32 PIXEL30_81 PIXEL31_81 PIXEL32_82 PIXEL33_82 break; case 231: PIXEL00_81 PIXEL01_31 PIXEL02_32 PIXEL03_82 PIXEL10_81 PIXEL11_31 PIXEL12_32 PIXEL13_82 PIXEL20_82 PIXEL21_32 PIXEL22_31 PIXEL23_81 PIXEL30_82 PIXEL31_32 PIXEL32_31 PIXEL33_81 break; case 126: PIXEL00_80 PIXEL01_10 if (Diff( b.w[1], b.w[5] )) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_10 PIXEL11_30 PIXEL12_0 if (Diff( b.w[7], b.w[3] )) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 break; case 219: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_0 if (Diff( b.w[5], b.w[7] )) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; case 125: if (Diff( b.w[7], b.w[3] )) { PIXEL00_82 PIXEL10_32 PIXEL20_0 PIXEL21_0 PIXEL30_0 PIXEL31_0 } else { PIXEL00_11 PIXEL10_13 PIXEL20_83 PIXEL21_70 PIXEL30_50 PIXEL31_21 } PIXEL01_82 PIXEL02_81 PIXEL03_81 PIXEL11_32 PIXEL12_31 PIXEL13_31 PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 break; case 221: PIXEL00_82 PIXEL01_82 PIXEL02_81 if (Diff( b.w[5], b.w[7] )) { PIXEL03_81 PIXEL13_31 PIXEL22_0 PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL03_12 PIXEL13_14 PIXEL22_70 PIXEL23_83 PIXEL32_21 PIXEL33_50 } PIXEL10_32 PIXEL11_32 PIXEL12_31 PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 break; case 207: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL01_0 PIXEL02_32 PIXEL03_82 PIXEL10_0 PIXEL11_0 } else { PIXEL00_50 PIXEL01_83 PIXEL02_13 PIXEL03_11 PIXEL10_21 PIXEL11_70 } PIXEL12_32 PIXEL13_82 PIXEL20_10 PIXEL21_30 PIXEL22_31 PIXEL23_81 PIXEL30_80 PIXEL31_10 PIXEL32_31 PIXEL33_81 break; case 238: PIXEL00_80 PIXEL01_10 PIXEL02_32 PIXEL03_82 PIXEL10_10 PIXEL11_30 PIXEL12_32 PIXEL13_82 if (Diff( b.w[7], b.w[3] )) { PIXEL20_0 PIXEL21_0 PIXEL30_0 PIXEL31_0 PIXEL32_31 PIXEL33_81 } else { PIXEL20_21 PIXEL21_70 PIXEL30_50 PIXEL31_83 PIXEL32_14 PIXEL33_12 } PIXEL22_31 PIXEL23_81 break; case 190: PIXEL00_80 PIXEL01_10 if (Diff( b.w[1], b.w[5] )) { PIXEL02_0 PIXEL03_0 PIXEL12_0 PIXEL13_0 PIXEL23_32 PIXEL33_82 } else { PIXEL02_21 PIXEL03_50 PIXEL12_70 PIXEL13_83 PIXEL23_13 PIXEL33_11 } PIXEL10_10 PIXEL11_30 PIXEL20_31 PIXEL21_31 PIXEL22_32 PIXEL30_81 PIXEL31_81 PIXEL32_82 break; case 187: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL01_0 PIXEL10_0 PIXEL11_0 PIXEL20_31 PIXEL30_81 } else { PIXEL00_50 PIXEL01_21 PIXEL10_83 PIXEL11_70 PIXEL20_14 PIXEL30_12 } PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 PIXEL21_31 PIXEL22_32 PIXEL23_32 PIXEL31_81 PIXEL32_82 PIXEL33_82 break; case 243: PIXEL00_81 PIXEL01_31 PIXEL02_10 PIXEL03_80 PIXEL10_81 PIXEL11_31 PIXEL12_30 PIXEL13_10 PIXEL20_82 PIXEL21_32 if (Diff( b.w[5], b.w[7] )) { PIXEL22_0 PIXEL23_0 PIXEL30_82 PIXEL31_32 PIXEL32_0 PIXEL33_0 } else { PIXEL22_70 PIXEL23_21 PIXEL30_11 PIXEL31_13 PIXEL32_83 PIXEL33_50 } break; case 119: if (Diff( b.w[1], b.w[5] )) { PIXEL00_81 PIXEL01_31 PIXEL02_0 PIXEL03_0 PIXEL12_0 PIXEL13_0 } else { PIXEL00_12 PIXEL01_14 PIXEL02_83 PIXEL03_50 PIXEL12_70 PIXEL13_21 } PIXEL10_81 PIXEL11_31 PIXEL20_82 PIXEL21_32 PIXEL22_30 PIXEL23_10 PIXEL30_82 PIXEL31_32 PIXEL32_10 PIXEL33_80 break; case 237: case 233: PIXEL00_82 PIXEL01_82 PIXEL02_60 PIXEL03_20 PIXEL10_32 PIXEL11_32 PIXEL12_70 PIXEL13_60 PIXEL20_0 PIXEL21_0 PIXEL22_31 PIXEL23_81 if (Diff( b.w[7], b.w[3] )) PIXEL30_0 else PIXEL30_20 PIXEL31_0 PIXEL32_31 PIXEL33_81 break; case 175: case 47: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_20 PIXEL01_0 PIXEL02_32 PIXEL03_82 PIXEL10_0 PIXEL11_0 PIXEL12_32 PIXEL13_82 PIXEL20_31 PIXEL21_31 PIXEL22_70 PIXEL23_60 PIXEL30_81 PIXEL31_81 PIXEL32_60 PIXEL33_20 break; case 183: case 151: PIXEL00_81 PIXEL01_31 PIXEL02_0 if (Diff( b.w[1], b.w[5] )) PIXEL03_0 else PIXEL03_20 PIXEL10_81 PIXEL11_31 PIXEL12_0 PIXEL13_0 PIXEL20_60 PIXEL21_70 PIXEL22_32 PIXEL23_32 PIXEL30_20 PIXEL31_60 PIXEL32_82 PIXEL33_82 break; case 245: case 244: PIXEL00_20 PIXEL01_60 PIXEL02_81 PIXEL03_81 PIXEL10_60 PIXEL11_70 PIXEL12_31 PIXEL13_31 PIXEL20_82 PIXEL21_32 PIXEL22_0 PIXEL23_0 PIXEL30_82 PIXEL31_32 PIXEL32_0 if (Diff( b.w[5], b.w[7] )) PIXEL33_0 else PIXEL33_20 break; case 250: PIXEL00_80 PIXEL01_10 PIXEL02_10 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_10 if (Diff( b.w[7], b.w[3] )) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_0 if (Diff( b.w[5], b.w[7] )) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } break; case 123: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_10 if (Diff( b.w[7], b.w[3] )) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 break; case 95: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } if (Diff( b.w[1], b.w[5] )) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL11_0 PIXEL12_0 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_10 PIXEL32_10 PIXEL33_80 break; case 222: PIXEL00_80 PIXEL01_10 if (Diff( b.w[1], b.w[5] )) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_10 PIXEL11_30 PIXEL12_0 PIXEL20_10 PIXEL21_30 PIXEL22_0 if (Diff( b.w[5], b.w[7] )) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; case 252: PIXEL00_80 PIXEL01_61 PIXEL02_81 PIXEL03_81 PIXEL10_10 PIXEL11_30 PIXEL12_31 PIXEL13_31 if (Diff( b.w[7], b.w[3] )) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_0 PIXEL23_0 PIXEL32_0 if (Diff( b.w[5], b.w[7] )) PIXEL33_0 else PIXEL33_20 break; case 249: PIXEL00_82 PIXEL01_82 PIXEL02_61 PIXEL03_80 PIXEL10_32 PIXEL11_32 PIXEL12_30 PIXEL13_10 PIXEL20_0 PIXEL21_0 PIXEL22_0 if (Diff( b.w[5], b.w[7] )) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } if (Diff( b.w[7], b.w[3] )) PIXEL30_0 else PIXEL30_20 PIXEL31_0 break; case 235: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_61 PIXEL20_0 PIXEL21_0 PIXEL22_31 PIXEL23_81 if (Diff( b.w[7], b.w[3] )) PIXEL30_0 else PIXEL30_20 PIXEL31_0 PIXEL32_31 PIXEL33_81 break; case 111: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_20 PIXEL01_0 PIXEL02_32 PIXEL03_82 PIXEL10_0 PIXEL11_0 PIXEL12_32 PIXEL13_82 if (Diff( b.w[7], b.w[3] )) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; case 63: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_20 PIXEL01_0 if (Diff( b.w[1], b.w[5] )) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_0 PIXEL11_0 PIXEL12_0 PIXEL20_31 PIXEL21_31 PIXEL22_30 PIXEL23_10 PIXEL30_81 PIXEL31_81 PIXEL32_61 PIXEL33_80 break; case 159: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_0 if (Diff( b.w[1], b.w[5] )) PIXEL03_0 else PIXEL03_20 PIXEL11_0 PIXEL12_0 PIXEL13_0 PIXEL20_10 PIXEL21_30 PIXEL22_32 PIXEL23_32 PIXEL30_80 PIXEL31_61 PIXEL32_82 PIXEL33_82 break; case 215: PIXEL00_81 PIXEL01_31 PIXEL02_0 if (Diff( b.w[1], b.w[5] )) PIXEL03_0 else PIXEL03_20 PIXEL10_81 PIXEL11_31 PIXEL12_0 PIXEL13_0 PIXEL20_61 PIXEL21_30 PIXEL22_0 if (Diff( b.w[5], b.w[7] )) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; case 246: PIXEL00_80 PIXEL01_10 if (Diff( b.w[1], b.w[5] )) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_61 PIXEL11_30 PIXEL12_0 PIXEL20_82 PIXEL21_32 PIXEL22_0 PIXEL23_0 PIXEL30_82 PIXEL31_32 PIXEL32_0 if (Diff( b.w[5], b.w[7] )) PIXEL33_0 else PIXEL33_20 break; case 254: PIXEL00_80 PIXEL01_10 if (Diff( b.w[1], b.w[5] )) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_10 PIXEL11_30 PIXEL12_0 if (Diff( b.w[7], b.w[3] )) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_0 PIXEL23_0 PIXEL32_0 if (Diff( b.w[5], b.w[7] )) PIXEL33_0 else PIXEL33_20 break; case 253: PIXEL00_82 PIXEL01_82 PIXEL02_81 PIXEL03_81 PIXEL10_32 PIXEL11_32 PIXEL12_31 PIXEL13_31 PIXEL20_0 PIXEL21_0 PIXEL22_0 PIXEL23_0 if (Diff( b.w[7], b.w[3] )) PIXEL30_0 else PIXEL30_20 PIXEL31_0 PIXEL32_0 if (Diff( b.w[5], b.w[7] )) PIXEL33_0 else PIXEL33_20 break; case 251: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_10 PIXEL20_0 PIXEL21_0 PIXEL22_0 if (Diff( b.w[5], b.w[7] )) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } if (Diff( b.w[7], b.w[3] )) PIXEL30_0 else PIXEL30_20 PIXEL31_0 break; case 239: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_20 PIXEL01_0 PIXEL02_32 PIXEL03_82 PIXEL10_0 PIXEL11_0 PIXEL12_32 PIXEL13_82 PIXEL20_0 PIXEL21_0 PIXEL22_31 PIXEL23_81 if (Diff( b.w[7], b.w[3] )) PIXEL30_0 else PIXEL30_20 PIXEL31_0 PIXEL32_31 PIXEL33_81 break; case 127: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_20 PIXEL01_0 if (Diff( b.w[1], b.w[5] )) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_0 PIXEL11_0 PIXEL12_0 if (Diff( b.w[7], b.w[3] )) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 break; case 191: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_20 PIXEL01_0 PIXEL02_0 if (Diff( b.w[1], b.w[5] )) PIXEL03_0 else PIXEL03_20 PIXEL10_0 PIXEL11_0 PIXEL12_0 PIXEL13_0 PIXEL20_31 PIXEL21_31 PIXEL22_32 PIXEL23_32 PIXEL30_81 PIXEL31_81 PIXEL32_82 PIXEL33_82 break; case 223: if (Diff( b.w[3], b.w[1] )) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_0 if (Diff( b.w[1], b.w[5] )) PIXEL03_0 else PIXEL03_20 PIXEL11_0 PIXEL12_0 PIXEL13_0 PIXEL20_10 PIXEL21_30 PIXEL22_0 if (Diff( b.w[5], b.w[7] )) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; case 247: PIXEL00_81 PIXEL01_31 PIXEL02_0 if (Diff( b.w[1], b.w[5] )) PIXEL03_0 else PIXEL03_20 PIXEL10_81 PIXEL11_31 PIXEL12_0 PIXEL13_0 PIXEL20_82 PIXEL21_32 PIXEL22_0 PIXEL23_0 PIXEL30_82 PIXEL31_32 PIXEL32_0 if (Diff( b.w[5], b.w[7] )) PIXEL33_0 else PIXEL33_20 break; case 255: if (Diff( b.w[3], b.w[1] )) PIXEL00_0 else PIXEL00_20 PIXEL01_0 PIXEL02_0 if (Diff( b.w[1], b.w[5] )) PIXEL03_0 else PIXEL03_20 PIXEL10_0 PIXEL11_0 PIXEL12_0 PIXEL13_0 PIXEL20_0 PIXEL21_0 PIXEL22_0 PIXEL23_0 if (Diff( b.w[7], b.w[3] )) PIXEL30_0 else PIXEL30_20 PIXEL31_0 PIXEL32_0 if (Diff( b.w[5], b.w[7] )) PIXEL33_0 else PIXEL33_20 break; default: NST_UNREACHABLE(); } #undef PIXEL00_0 #undef PIXEL00_11 #undef PIXEL00_12 #undef PIXEL00_20 #undef PIXEL00_50 #undef PIXEL00_80 #undef PIXEL00_81 #undef PIXEL00_82 #undef PIXEL01_0 #undef PIXEL01_10 #undef PIXEL01_12 #undef PIXEL01_14 #undef PIXEL01_21 #undef PIXEL01_31 #undef PIXEL01_50 #undef PIXEL01_60 #undef PIXEL01_61 #undef PIXEL01_82 #undef PIXEL01_83 #undef PIXEL02_0 #undef PIXEL02_10 #undef PIXEL02_11 #undef PIXEL02_13 #undef PIXEL02_21 #undef PIXEL02_32 #undef PIXEL02_50 #undef PIXEL02_60 #undef PIXEL02_61 #undef PIXEL02_81 #undef PIXEL02_83 #undef PIXEL03_0 #undef PIXEL03_11 #undef PIXEL03_12 #undef PIXEL03_20 #undef PIXEL03_50 #undef PIXEL03_80 #undef PIXEL03_81 #undef PIXEL03_82 #undef PIXEL10_0 #undef PIXEL10_10 #undef PIXEL10_11 #undef PIXEL10_13 #undef PIXEL10_21 #undef PIXEL10_32 #undef PIXEL10_50 #undef PIXEL10_60 #undef PIXEL10_61 #undef PIXEL10_81 #undef PIXEL10_83 #undef PIXEL11_0 #undef PIXEL11_30 #undef PIXEL11_31 #undef PIXEL11_32 #undef PIXEL11_70 #undef PIXEL12_0 #undef PIXEL12_30 #undef PIXEL12_31 #undef PIXEL12_32 #undef PIXEL12_70 #undef PIXEL13_0 #undef PIXEL13_10 #undef PIXEL13_12 #undef PIXEL13_14 #undef PIXEL13_21 #undef PIXEL13_31 #undef PIXEL13_50 #undef PIXEL13_60 #undef PIXEL13_61 #undef PIXEL13_82 #undef PIXEL13_83 #undef PIXEL20_0 #undef PIXEL20_10 #undef PIXEL20_12 #undef PIXEL20_14 #undef PIXEL20_21 #undef PIXEL20_31 #undef PIXEL20_50 #undef PIXEL20_60 #undef PIXEL20_61 #undef PIXEL20_82 #undef PIXEL20_83 #undef PIXEL21_0 #undef PIXEL21_30 #undef PIXEL21_31 #undef PIXEL21_32 #undef PIXEL21_70 #undef PIXEL22_0 #undef PIXEL22_30 #undef PIXEL22_31 #undef PIXEL22_32 #undef PIXEL22_70 #undef PIXEL23_0 #undef PIXEL23_10 #undef PIXEL23_11 #undef PIXEL23_13 #undef PIXEL23_21 #undef PIXEL23_32 #undef PIXEL23_50 #undef PIXEL23_60 #undef PIXEL23_61 #undef PIXEL23_81 #undef PIXEL23_83 #undef PIXEL30_0 #undef PIXEL30_11 #undef PIXEL30_12 #undef PIXEL30_20 #undef PIXEL30_50 #undef PIXEL30_80 #undef PIXEL30_81 #undef PIXEL30_82 #undef PIXEL31_0 #undef PIXEL31_10 #undef PIXEL31_11 #undef PIXEL31_13 #undef PIXEL31_21 #undef PIXEL31_32 #undef PIXEL31_50 #undef PIXEL31_60 #undef PIXEL31_61 #undef PIXEL31_81 #undef PIXEL31_83 #undef PIXEL32_0 #undef PIXEL32_10 #undef PIXEL32_12 #undef PIXEL32_14 #undef PIXEL32_21 #undef PIXEL32_31 #undef PIXEL32_50 #undef PIXEL32_60 #undef PIXEL32_61 #undef PIXEL32_82 #undef PIXEL32_83 #undef PIXEL33_0 #undef PIXEL33_11 #undef PIXEL33_12 #undef PIXEL33_20 #undef PIXEL33_50 #undef PIXEL33_80 #undef PIXEL33_81 #undef PIXEL33_82 nestopia-1.51.1/source/core/NstVideoFilterHqX.cpp000066400000000000000000000346731411157722000217140ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003 MaxSt ( maxst@hiend3d.com ) // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstCore.hpp" #ifndef NST_NO_HQ2X #include "NstAssert.hpp" #include "NstVideoRenderer.hpp" #include "NstVideoFilterHqX.hpp" namespace Nes { namespace Core { namespace Video { void Renderer::FilterHqX::Blit(const Input& input,const Output& output,uint) { (*this.*path)( input, output ); } template dword Renderer::FilterHqX::Interpolate1(dword c1,dword c2) { return ((((c1 & G)*3 + (c2 & G)) & (G << 2)) + (((c1 & (R|B))*3 + (c2 & (R|B))) & ((R|B) << 2))) >> 2; } template<> inline dword Renderer::FilterHqX::Interpolate1<0xFF0000,0x00FF00,0x0000FF>(dword c1,dword c2) { return (c1 * 3 + c2) >> 2; } template dword Renderer::FilterHqX::Interpolate2(dword c1,dword c2,dword c3) { return ((((c1 & G)*2 + (c2 & G) + (c3 & G)) & (G << 2)) + (((c1 & (R|B))*2 + (c2 & (R|B)) + (c3 & (R|B))) & ((R|B) << 2))) >> 2; } template<> inline dword Renderer::FilterHqX::Interpolate2<0xFF0000,0x00FF00,0x0000FF>(dword c1,dword c2,dword c3) { return (c1 * 2 + c2 + c3) >> 2; } template dword Renderer::FilterHqX::Interpolate3(dword c1,dword c2) { return ((((c1 & G)*7 + (c2 & G)) & (G << 3)) + (((c1 & (R|B))*7 + (c2 & (R|B))) & ((R|B) << 3))) >> 3; } template dword Renderer::FilterHqX::Interpolate4(dword c1,dword c2,dword c3) { return ((((c1 & G)*2 + ((c2 & G) + (c3 & G))*7) & (G << 4)) + (((c1 & (R|B))*2 + ((c2 & (R|B)) + (c3 & (R|B)))*7) & ((R|B) << 4))) >> 4; } template dword Renderer::FilterHqX::Interpolate5(dword c1,dword c2) { return (((c1 & G) + (c2 & G) & (G << 1)) + ((c1 & (R|B)) + (c2 & (R|B)) & ((R|B) << 1))) >> 1; } template<> inline dword Renderer::FilterHqX::Interpolate5<0xFF0000,0x00FF00,0x0000FF>(dword c1,dword c2) { return (c1 + c2) >> 1; } template dword Renderer::FilterHqX::Interpolate6(dword c1,dword c2,dword c3) { return ((((c1 & G)*5 + (c2 & G)*2 + (c3 & G)) & (G << 3)) + (((c1 & (R|B))*5 + (c2 & (R|B))*2 + (c3 & (R|B))) & ((R|B) << 3))) >> 3; } template dword Renderer::FilterHqX::Interpolate7(dword c1,dword c2,dword c3) { return ((((c1 & G)*6 + (c2 & G) + (c3 & G)) & (G << 3)) + (((c1 & (R|B))*6 + (c2 & (R|B)) + (c3 & (R|B))) & ((R|B) << 3))) >> 3; } template dword Renderer::FilterHqX::Interpolate8(dword c1,dword c2) { return ((((c1 & G)*5 + (c2 & G)*3) & (G << 3)) + (((c1 & (R|B))*5 + (c2 & (R|B))*3) & ((R|B) << 3))) >> 3; } template dword Renderer::FilterHqX::Interpolate9(dword c1,dword c2,dword c3) { return ((((c1 & G)*2 + ((c2 & G) + (c3 & G))*3 ) & (G << 3)) + (((c1 & (R|B))*2 + ((c2 & (R|B)) + (c3 & (R|B)))*3 ) & ((R|B) << 3))) >> 3; } template dword Renderer::FilterHqX::Interpolate10(dword c1,dword c2,dword c3) { return ((((c1 & G)*14 + (c2 & G) + (c3 & G)) & (G << 4)) + (((c1 & (R|B))*14 + (c2 & (R|B)) + (c3 & (R|B))) & ((R|B) << 4))) >> 4; } inline dword Renderer::FilterHqX::Diff(uint w1,uint w2) const { return (lut.yuv[w1] - lut.yuv[w2] + Lut::YUV_OFFSET) & Lut::YUV_MASK; } template struct Renderer::FilterHqX::Buffer { uint w[10]; dword c[10]; NST_FORCE_INLINE void Convert(const Lut& lut) { for (uint k=0; k < 9; ++k) c[k] = lut.rgb[w[k]]; } }; template<> struct Renderer::FilterHqX::Buffer { union { uint w[10]; dword c[10]; }; void Convert(const Lut&) { } }; template void Renderer::FilterHqX::Blit2x(const Input& input,const Output& output) const { const byte* NST_RESTRICT src = reinterpret_cast(input.pixels); const long pitch = output.pitch + output.pitch - (WIDTH*2 * sizeof(T)); T* NST_RESTRICT dst[2] = { static_cast(output.pixels) - 2, reinterpret_cast(static_cast(output.pixels) + output.pitch) - 2 }; for (uint y=HEIGHT; y; --y) { const uint lines[2] = { y < HEIGHT ? WIDTH * sizeof(Input::Pixel) : 0, y > 1 ? WIDTH * sizeof(Input::Pixel) : 0 }; Buffer b; b.w[2] = (b.w[1] = input.palette[*reinterpret_cast(src - lines[0])]); b.w[5] = (b.w[4] = input.palette[*reinterpret_cast(src)]); b.w[8] = (b.w[7] = input.palette[*reinterpret_cast(src + lines[1])]); for (uint x=WIDTH; x; ) { src += sizeof(Input::Pixel); dst[0] += 2; dst[1] += 2; b.w[0] = b.w[1]; b.w[1] = b.w[2]; b.w[3] = b.w[4]; b.w[4] = b.w[5]; b.w[6] = b.w[7]; b.w[7] = b.w[8]; if (--x) { b.w[2] = input.palette[*reinterpret_cast(src - lines[0])]; b.w[5] = input.palette[*reinterpret_cast(src)]; b.w[8] = input.palette[*reinterpret_cast(src + lines[1])]; } b.Convert( lut ); const uint yuv5 = lut.yuv[b.w[4]]; #include "NstVideoFilterHq2x.inl" } dst[0] = reinterpret_cast(reinterpret_cast(dst[0]) + pitch); dst[1] = reinterpret_cast(reinterpret_cast(dst[1]) + pitch); } } template void Renderer::FilterHqX::Blit3x(const Input& input,const Output& output) const { const byte* NST_RESTRICT src = reinterpret_cast(input.pixels); const long pitch = (output.pitch * 2) + output.pitch - (WIDTH*3 * sizeof(T)); T* NST_RESTRICT dst[3] = { static_cast(output.pixels) - 3, reinterpret_cast(static_cast(output.pixels) + output.pitch) - 3, reinterpret_cast(static_cast(output.pixels) + output.pitch * 2) - 3 }; for (uint y=HEIGHT; y; --y) { const uint lines[2] = { y < HEIGHT ? WIDTH * sizeof(Input::Pixel) : 0, y > 1 ? WIDTH * sizeof(Input::Pixel) : 0 }; Buffer b; b.w[2] = (b.w[1] = input.palette[*reinterpret_cast(src - lines[0])]); b.w[5] = (b.w[4] = input.palette[*reinterpret_cast(src)]); b.w[8] = (b.w[7] = input.palette[*reinterpret_cast(src + lines[1])]); for (uint x=WIDTH; x; ) { src += sizeof(Input::Pixel); dst[0] += 3; dst[1] += 3; dst[2] += 3; b.w[0] = b.w[1]; b.w[1] = b.w[2]; b.w[3] = b.w[4]; b.w[4] = b.w[5]; b.w[6] = b.w[7]; b.w[7] = b.w[8]; if (--x) { b.w[2] = input.palette[*reinterpret_cast(src - lines[0])]; b.w[5] = input.palette[*reinterpret_cast(src)]; b.w[8] = input.palette[*reinterpret_cast(src + lines[1])]; } b.Convert( lut ); const uint yuv5 = lut.yuv[b.w[4]]; #include "NstVideoFilterHq3x.inl" } dst[0] = reinterpret_cast(reinterpret_cast(dst[0]) + pitch); dst[1] = reinterpret_cast(reinterpret_cast(dst[1]) + pitch); dst[2] = reinterpret_cast(reinterpret_cast(dst[2]) + pitch); } } template void Renderer::FilterHqX::Blit4x(const Input& input,const Output& output) const { const byte* NST_RESTRICT src = reinterpret_cast(input.pixels); const long pitch = (output.pitch * 3) + output.pitch - (WIDTH*4 * sizeof(T)); T* NST_RESTRICT dst[4] = { static_cast(output.pixels) - 4, reinterpret_cast(static_cast(output.pixels) + output.pitch) - 4, reinterpret_cast(static_cast(output.pixels) + output.pitch * 2) - 4, reinterpret_cast(static_cast(output.pixels) + output.pitch * 3) - 4 }; for (uint y=HEIGHT; y; --y) { const uint lines[2] = { y < HEIGHT ? WIDTH * sizeof(Input::Pixel) : 0, y > 1 ? WIDTH * sizeof(Input::Pixel) : 0 }; Buffer b; b.w[2] = (b.w[1] = input.palette[*reinterpret_cast(src - lines[0])]); b.w[5] = (b.w[4] = input.palette[*reinterpret_cast(src)]); b.w[8] = (b.w[7] = input.palette[*reinterpret_cast(src + lines[1])]); for (uint x=WIDTH; x; ) { src += sizeof(Input::Pixel); dst[0] += 4; dst[1] += 4; dst[2] += 4; dst[3] += 4; b.w[0] = b.w[1]; b.w[1] = b.w[2]; b.w[3] = b.w[4]; b.w[4] = b.w[5]; b.w[6] = b.w[7]; b.w[7] = b.w[8]; if (--x) { b.w[2] = input.palette[*reinterpret_cast(src - lines[0])]; b.w[5] = input.palette[*reinterpret_cast(src)]; b.w[8] = input.palette[*reinterpret_cast(src + lines[1])]; } b.Convert( lut ); const uint yuv5 = lut.yuv[b.w[4]]; #include "NstVideoFilterHq4x.inl" } dst[0] = reinterpret_cast(reinterpret_cast(dst[0]) + pitch); dst[1] = reinterpret_cast(reinterpret_cast(dst[1]) + pitch); dst[2] = reinterpret_cast(reinterpret_cast(dst[2]) + pitch); dst[3] = reinterpret_cast(reinterpret_cast(dst[3]) + pitch); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Renderer::FilterHqX::Lut::Lut(const bool bpp32,const byte (&formatShifts)[3],dword* tmp) : rgb(tmp = (bpp32 ? new dword [0x10000] : NULL)) { const uint shifts[3] = { bpp32 ? 11 : formatShifts[0], bpp32 ? 5 : formatShifts[1], bpp32 ? 0 : formatShifts[2] }; for (uint i=0; i < 32; ++i) { for (uint j=0; j < 64; ++j) { for (uint k=0; k < 32; ++k) { uint r = i << 3; uint g = j << 2; uint b = k << 3; dword y = ((r + g + b) >> 2) & 0xFF; dword u = (128 + ((r - b) >> 2)) & 0xFF; dword v = (128 + ((2*g - r - b) >> 3)) & 0xFF; yuv[(i << shifts[0]) | (j << shifts[1]) | (k << shifts[2])] = (y << 16) | (u << 8) | (v << 0); } } } if (bpp32) { for (dword i=0; i < 0x10000; ++i) tmp[i] = ((i & 0xF800) << 8) | ((i & 0x07E0) << 5) | ((i & 0x001F) << 3); } } Renderer::FilterHqX::Lut::~Lut() { delete [] rgb; } Renderer::FilterHqX::Path Renderer::FilterHqX::GetPath(const RenderState& state) { if (state.filter == RenderState::FILTER_HQ2X) { if (state.bits.count == 32) { return &FilterHqX::Blit2x; } else if (state.bits.mask.g == 0x07E0) { return &FilterHqX::Blit2x; } else { return &FilterHqX::Blit2x; } } else if (state.filter == RenderState::FILTER_HQ3X) { if (state.bits.count == 32) { return &FilterHqX::Blit3x; } else if (state.bits.mask.g == 0x07E0) { return &FilterHqX::Blit3x; } else { return &FilterHqX::Blit3x; } } else { if (state.bits.count == 32) { return &FilterHqX::Blit4x; } else if (state.bits.mask.g == 0x07E0) { return &FilterHqX::Blit4x; } else { return &FilterHqX::Blit4x; } } } Renderer::FilterHqX::FilterHqX(const RenderState& state) : Filter (state), path (GetPath(state)), lut (state.bits.count == 32,format.shifts) { } bool Renderer::FilterHqX::Check(const RenderState& state) { return ( (state.bits.count == 16 && state.bits.mask.b == 0x001F && ((state.bits.mask.g == 0x07E0 && state.bits.mask.r == 0xF800) || (state.bits.mask.g == 0x03E0 && state.bits.mask.r == 0x7C00))) || (state.bits.count == 32 && state.bits.mask.r == 0xFF0000 && state.bits.mask.g == 0x00FF00 && state.bits.mask.b == 0x0000FF) ) && ( (state.filter == RenderState::FILTER_HQ2X && state.width == WIDTH*2 && state.height == HEIGHT*2) || (state.filter == RenderState::FILTER_HQ3X && state.width == WIDTH*3 && state.height == HEIGHT*3) || (state.filter == RenderState::FILTER_HQ4X && state.width == WIDTH*4 && state.height == HEIGHT*4) ); } void Renderer::FilterHqX::Transform(const byte (&src)[PALETTE][3],Input::Palette& dst) const { if (format.bpp == 32) { for (uint i=0; i < PALETTE; ++i) { dst[i] = ( ((src[i][0] * 0x1FU + 0x7F) / 0xFF) << 11 | ((src[i][1] * 0x3FU + 0x7F) / 0xFF) << 5 | ((src[i][2] * 0x1FU + 0x7F) / 0xFF) << 0 ); } } else { Filter::Transform( src, dst ); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } } #endif nestopia-1.51.1/source/core/NstVideoFilterHqX.hpp000066400000000000000000000064231411157722000217110ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003 MaxSt ( maxst@hiend3d.com ) // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_VIDEO_FILTER_HQX_H #define NST_VIDEO_FILTER_HQX_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Video { class Renderer::FilterHqX : public Renderer::Filter { public: explicit FilterHqX(const RenderState&); static bool Check(const RenderState&); private: ~FilterHqX() {} typedef void (FilterHqX::*Path)(const Input&,const Output&) const; static Path GetPath(const RenderState&); void Blit(const Input&,const Output&,uint); void Transform(const byte (&)[PALETTE][3],Input::Palette&) const; template static dword Interpolate1(dword,dword); template static dword Interpolate2(dword,dword,dword); template static dword Interpolate3(dword,dword); template static dword Interpolate4(dword,dword,dword); template static dword Interpolate5(dword,dword); template static dword Interpolate6(dword,dword,dword); template static dword Interpolate7(dword,dword,dword); template static dword Interpolate8(dword,dword); template static dword Interpolate9(dword,dword,dword); template static dword Interpolate10(dword,dword,dword); inline dword Diff(uint,uint) const; template void Blit2x(const Input&,const Output&) const; template void Blit3x(const Input&,const Output&) const; template void Blit4x(const Input&,const Output&) const; template struct Buffer; struct Lut { Lut(bool,const byte (&)[3],dword* = NULL); ~Lut(); enum { YUV_OFFSET = (0x440UL << 21) + (0x207UL << 11) + 0x407, YUV_MASK = (0x380UL << 21) + (0x1F0UL << 11) + 0x3F0 }; dword yuv[0x10000]; const dword* const NST_RESTRICT rgb; }; const Path path; const Lut lut; }; } } } #endif nestopia-1.51.1/source/core/NstVideoFilterNone.cpp000066400000000000000000000061621411157722000221030ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstCore.hpp" #include "NstVideoRenderer.hpp" #include "NstVideoFilterNone.hpp" namespace Nes { namespace Core { namespace Video { template void Renderer::FilterNone::BlitAligned(const Input& input,const Output& output) { const Input::Pixel* NST_RESTRICT src = input.pixels; T* NST_RESTRICT dst = static_cast(output.pixels); for (uint prefetched=*src++, i=PIXELS; i; --i) { const dword reg = input.palette[prefetched]; prefetched = *src++; *dst++ = reg; } } template void Renderer::FilterNone::BlitUnaligned(const Input& input,const Output& output) { const Input::Pixel* NST_RESTRICT src = input.pixels; T* NST_RESTRICT dst = static_cast(output.pixels); const long pad = output.pitch - WIDTH * sizeof(T); for (uint prefetched=*src++, y=HEIGHT; y; --y) { for (uint x=WIDTH; x; --x) { const dword reg = input.palette[prefetched]; prefetched = *src++; *dst++ = reg; } dst = reinterpret_cast(reinterpret_cast(dst) + pad); } } void Renderer::FilterNone::Blit(const Input& input,const Output& output,uint) { if (format.bpp == 32) { if (output.pitch == WIDTH * sizeof(dword)) BlitAligned( input, output ); else BlitUnaligned( input, output ); } else { if (output.pitch == WIDTH * sizeof(word)) BlitAligned( input, output ); else BlitUnaligned( input, output ); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Renderer::FilterNone::FilterNone(const RenderState& state) : Filter(state) { NST_COMPILE_ASSERT( Video::Screen::PIXELS_PADDING >= 1 ); } bool Renderer::FilterNone::Check(const RenderState& state) { return ( (state.bits.count == 16 || state.bits.count == 32) && (state.width == WIDTH && state.height == HEIGHT) ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } } nestopia-1.51.1/source/core/NstVideoFilterNone.hpp000066400000000000000000000032241411157722000221040ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_VIDEO_FILTER_NONE_H #define NST_VIDEO_FILTER_NONE_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Video { class Renderer::FilterNone : public Renderer::Filter { public: explicit FilterNone(const RenderState&); static bool Check(const RenderState&); private: ~FilterNone() {} void Blit(const Input&,const Output&,uint); template static void BlitAligned(const Input&,const Output&); template static void BlitUnaligned(const Input&,const Output&); }; } } } #endif nestopia-1.51.1/source/core/NstVideoFilterNtsc.cpp000066400000000000000000000132101411157722000221030ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstAssert.hpp" #include "NstVideoRenderer.hpp" #include "NstVideoFilterNtsc.hpp" #include "NstFpuPrecision.hpp" namespace Nes { namespace Core { namespace Video { void Renderer::FilterNtsc::Blit(const Input& input,const Output& output,uint phase) { (*this.*path)( input, output, phase ); } template void Renderer::FilterNtsc::BlitType(const Input& input,const Output& output,uint phase) const { NST_ASSERT( phase < 3 ); const uint bgcolor = this->bgColor; const Input::Pixel* NST_RESTRICT src = input.pixels; Pixel* NST_RESTRICT dst = static_cast(output.pixels); const long pad = output.pitch - (NTSC_WIDTH-7) * sizeof(Pixel); phase &= lut.noFieldMerging; for (uint y=HEIGHT; y; --y) { NES_NTSC_BEGIN_ROW( &lut, phase, bgcolor, bgcolor, *src++ ); for (const Input::Pixel* const end=src+(NTSC_WIDTH/7*3-3); src != end; src += 3, dst += 7) { NES_NTSC_COLOR_IN( 0, src[0] ); NES_NTSC_RGB_OUT( 0, dst[0], BITS ); NES_NTSC_RGB_OUT( 1, dst[1], BITS ); NES_NTSC_COLOR_IN( 1, src[1] ); NES_NTSC_RGB_OUT( 2, dst[2], BITS ); NES_NTSC_RGB_OUT( 3, dst[3], BITS ); NES_NTSC_COLOR_IN( 2, src[2] ); NES_NTSC_RGB_OUT( 4, dst[4], BITS ); NES_NTSC_RGB_OUT( 5, dst[5], BITS ); NES_NTSC_RGB_OUT( 6, dst[6], BITS ); } NES_NTSC_COLOR_IN( 0, bgcolor ); NES_NTSC_RGB_OUT( 0, dst[0], BITS ); NES_NTSC_RGB_OUT( 1, dst[1], BITS ); NES_NTSC_COLOR_IN( 1, bgcolor ); NES_NTSC_RGB_OUT( 2, dst[2], BITS ); NES_NTSC_RGB_OUT( 3, dst[3], BITS ); NES_NTSC_COLOR_IN( 2, bgcolor ); NES_NTSC_RGB_OUT( 4, dst[4], BITS ); NES_NTSC_RGB_OUT( 5, dst[5], BITS ); NES_NTSC_RGB_OUT( 6, dst[6], BITS ); dst = reinterpret_cast(reinterpret_cast(dst) + pad); phase = (phase + 1) % 3; } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif bool Renderer::FilterNtsc::Check(const RenderState& state) { return (state.width == NTSC_WIDTH && state.height == HEIGHT) && ( (state.bits.count == 16 && state.bits.mask.b == 0x001F && ((state.bits.mask.g == 0x07E0 && state.bits.mask.r == 0xF800) || (state.bits.mask.g == 0x03E0 && state.bits.mask.r == 0x7C00))) || (state.bits.count == 32 && state.bits.mask.r == 0xFF0000 && state.bits.mask.g == 0x00FF00 && state.bits.mask.b == 0x0000FF) ); } Renderer::FilterNtsc::Path Renderer::FilterNtsc::GetPath(const RenderState& state,const Lut& lut) { if (state.bits.count == 32) { return &FilterNtsc::BlitType; } else if (state.bits.mask.g == 0x07E0) { return &FilterNtsc::BlitType; } else { return &FilterNtsc::BlitType; } } inline uint Renderer::FilterNtsc::Lut::GetBlack(const byte (&p)[PALETTE][3]) { uint index = DEF_BLACK; for (uint i=0, intensity = 0xFF * 100; i < 64; ++i) { const uint v = p[i][0] * 30 + p[i][1] * 59 + p[i][2] * 11; if (intensity > v) { intensity = v; index = i; } } return index; } Renderer::FilterNtsc::Lut::Lut ( const byte (&palette)[PALETTE][3], const schar sharpness, const schar resolution, const schar bleed, const schar artifacts, const schar fringing, const bool fieldMerging ) : noFieldMerging (fieldMerging ? 0U : ~0U), black (GetBlack(palette)) { FpuPrecision precision; nes_ntsc_setup_t setup; setup.hue = 0; setup.saturation = 0; setup.contrast = 0; setup.brightness = 0; setup.sharpness = sharpness / 100.0; setup.gamma = 0; setup.resolution = resolution / 100.0; setup.artifacts = artifacts / 100.0; setup.fringing = fringing / 100.0; setup.bleed = bleed / 100.0; setup.merge_fields = fieldMerging; setup.decoder_matrix = NULL; setup.palette_out = NULL; setup.palette = *palette; setup.base_palette = NULL; ::nes_ntsc_init( this, &setup ); } Renderer::FilterNtsc::FilterNtsc ( const RenderState& state, const byte (&palette)[PALETTE][3], schar sharpness, schar resolution, schar bleed, schar artifacts, schar fringing, bool fieldMerging ) : Filter (state), path (GetPath(state,lut)), lut (palette,sharpness,resolution,bleed,artifacts,fringing,fieldMerging) { } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } } nestopia-1.51.1/source/core/NstVideoFilterNtsc.hpp000066400000000000000000000043071411157722000221170ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_VIDEO_FILTER_NTSC_H #define NST_VIDEO_FILTER_NTSC_H #include "../nes_ntsc/nes_ntsc.h" #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Video { class Renderer::FilterNtsc : public Renderer::Filter { public: FilterNtsc(const RenderState&,const byte (&)[PALETTE][3],schar,schar,schar,schar,schar,bool); static bool Check(const RenderState&); private: ~FilterNtsc() {} enum { NTSC_WIDTH = 602 }; typedef void (FilterNtsc::*Path)(const Input&,const Output&,uint) const; void Blit(const Input&,const Output&,uint); template void BlitType(const Input&,const Output&,uint) const; class Lut : public nes_ntsc_t { enum { DEF_BLACK = 15 }; static inline uint GetBlack(const byte (&)[PALETTE][3]); public: Lut(const byte (&)[PALETTE][3],schar,schar,schar,schar,schar,bool); const uint noFieldMerging; const uint black; }; static Path GetPath(const RenderState&,const Lut&); const Path path; const Lut lut; }; } } } #endif nestopia-1.51.1/source/core/NstVideoFilterNtscCfg.cpp000066400000000000000000000024671411157722000225370ustar00rootroot00000000000000/* //////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// */ #ifdef __INTEL_COMPILER #pragma warning( disable : 981 1572 1599 ) #endif #ifdef _MSC_VER #pragma warning( push ) #pragma warning( disable : 4127 ) #endif #define NES_NTSC_NO_BLITTERS #include "../nes_ntsc/nes_ntsc.inl" #ifdef _MSC_VER #pragma warning( pop ) #endif nestopia-1.51.1/source/core/NstVideoFilterScaleX.cpp000066400000000000000000000164611411157722000223660ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2001, 2002, 2003, 2004 Andrea Mazzoleni // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstCore.hpp" #ifndef NST_NO_SCALEX #include "NstVideoRenderer.hpp" #include "NstVideoFilterScaleX.hpp" namespace Nes { namespace Core { namespace Video { void Renderer::FilterScaleX::Blit(const Input& input,const Output& output,uint) { path( input, output ); } template NST_FORCE_INLINE T* Renderer::FilterScaleX::Blit2xBorder(T* NST_RESTRICT dst,const Input::Pixel* NST_RESTRICT src,const Input::Palette& palette) { { dword p[4] = { palette[src[ PREV ]], palette[src[ 0 ]], palette[src[ 1 ]], palette[src[ NEXT ]] }; if (p[0] != p[3] && p[2] != p[1] && p[2] == p[0]) p[1] = p[0]; dst[0] = p[1]; dst[1] = p[1]; } src += 1; dst += 2; for (uint x=WIDTH-2; x; --x) { const dword p[4] = { palette[src[ PREV ]], palette[src[ -1 ]], palette[src[ 0 ]], palette[src[ 1 ]] }; if (p[0] != p[1] && p[1] != p[3]) { dst[0] = p[1] == p[0] ? p[0] : p[2]; dst[1] = p[3] == p[0] ? p[0] : p[2]; } else { dst[0] = p[2]; dst[1] = p[2]; } src += 1; dst += 2; } const dword p[4] = { palette[src[ PREV ]], palette[src[ -1 ]], palette[src[ 0 ]], palette[src[ NEXT ]] }; if (p[0] != p[3] && p[1] != p[2]) { dst[0] = p[1] == p[0] ? p[0] : p[2]; dst[1] = p[2] == p[0] ? p[0] : p[2]; } else { dst[0] = p[2]; dst[1] = p[2]; } return dst + 2; } template NST_FORCE_INLINE T* Renderer::FilterScaleX::Blit3xBorder(T* NST_RESTRICT dst,const Input::Pixel* NST_RESTRICT src,const Input::Palette& palette) { { const dword p = palette[src[0]]; dst[0] = p; dst[1] = p; const dword q = palette[src[PREV]]; dst[2] = (q != palette[src[1]] && q != palette[src[NEXT]]) ? q : p; } src += 1; dst += 3; for (uint x=WIDTH-2; x; --x) { const dword p[5] = { palette[src[ PREV ]], palette[src[ -1 ]], palette[src[ 0 ]], palette[src[ 1 ]], palette[src[ NEXT ]] }; dst[0] = (p[1] == p[0] && p[4] != p[0] && p[3] != p[0]) ? p[0] : p[2]; dst[1] = p[2]; dst[2] = (p[3] == p[0] && p[4] != p[0] && p[1] != p[0]) ? p[0] : p[2]; src += 1; dst += 3; } const dword p[2] = { palette[src[ PREV ]], palette[src[ 0 ]] }; dst[0] = p[p[0] != palette[src[-1]] || p[0] == palette[src[NEXT]]]; dst[1] = p[1]; dst[2] = p[1]; return dst + 3; } template NST_FORCE_INLINE T* Renderer::FilterScaleX::Blit3xCenter(T* NST_RESTRICT dst,const Input::Pixel* NST_RESTRICT src,const Input::Palette& palette) { for (uint x=WIDTH; x; --x) { const dword p = palette[*src++]; dst[0] = p; dst[1] = p; dst[2] = p; dst += 3; } return dst; } template NST_FORCE_INLINE T* Renderer::FilterScaleX::Blit2xLine(T* dst,const Input::Pixel* const src,const Input::Palette& palette,const long pad) { dst = reinterpret_cast(reinterpret_cast(Blit2xBorder( dst, src, palette )) + pad); dst = reinterpret_cast(reinterpret_cast(Blit2xBorder( dst, src, palette )) + pad); return dst; } template NST_FORCE_INLINE T* Renderer::FilterScaleX::Blit3xLine(T* dst,const Input::Pixel* const src,const Input::Palette& palette,const long pad) { dst = reinterpret_cast(reinterpret_cast(Blit3xBorder( dst, src, palette )) + pad); dst = reinterpret_cast(reinterpret_cast(Blit3xCenter( dst, src, palette )) + pad); dst = reinterpret_cast(reinterpret_cast(Blit3xBorder( dst, src, palette )) + pad); return dst; } template void Renderer::FilterScaleX::Blit2x(const Input& input,const Output& output) { const Input::Pixel* src = input.pixels; T* dst = static_cast(output.pixels); const long pad = output.pitch - long(sizeof(T) * WIDTH*2); dst = Blit2xLine( dst, src, input.palette, pad ); for (uint y=HEIGHT-2; y; --y) dst = Blit2xLine( dst, src += WIDTH, input.palette, pad ); Blit2xLine( dst, src + WIDTH, input.palette, pad ); } template void Renderer::FilterScaleX::Blit3x(const Input& input,const Output& output) { const Input::Pixel* src = input.pixels; T* dst = static_cast(output.pixels); const long pad = output.pitch - long(sizeof(T) * WIDTH*3); dst = Blit3xLine( dst, src, input.palette, pad ); for (uint y=HEIGHT-2; y; --y) dst = Blit3xLine( dst, src += WIDTH, input.palette, pad ); Blit3xLine( dst, src + WIDTH, input.palette, pad ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Renderer::FilterScaleX::Path Renderer::FilterScaleX::GetPath(const RenderState& state) { if (state.filter == RenderState::FILTER_SCALE2X) { if (state.bits.count == 32) return &FilterScaleX::Blit2x; else return &FilterScaleX::Blit2x; } else { if (state.bits.count == 32) return &FilterScaleX::Blit3x; else return &FilterScaleX::Blit3x; } } Renderer::FilterScaleX::FilterScaleX(const RenderState& state) : Filter (state), path (GetPath(state)) { } bool Renderer::FilterScaleX::Check(const RenderState& state) { return (state.bits.count == 16 || state.bits.count == 32) && ( (state.filter == RenderState::FILTER_SCALE2X && state.width == WIDTH*2 && state.height == HEIGHT*2) || (state.filter == RenderState::FILTER_SCALE3X && state.width == WIDTH*3 && state.height == HEIGHT*3) ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } } #endif nestopia-1.51.1/source/core/NstVideoFilterScaleX.hpp000066400000000000000000000051011411157722000223600ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2001, 2002, 2003, 2004 Andrea Mazzoleni // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_VIDEO_FILTER_SCALEX_H #define NST_VIDEO_FILTER_SCALEX_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Video { class Renderer::FilterScaleX : public Renderer::Filter { public: explicit FilterScaleX(const RenderState&); static bool Check(const RenderState&); private: ~FilterScaleX() {} typedef void (*Path)(const Input&,const Output&); static Path GetPath(const RenderState&); void Blit(const Input&,const Output&,uint); template static NST_FORCE_INLINE T* Blit2xBorder(T* NST_RESTRICT,const Input::Pixel* NST_RESTRICT,const Input::Palette&); template static NST_FORCE_INLINE T* Blit3xBorder(T* NST_RESTRICT,const Input::Pixel* NST_RESTRICT,const Input::Palette&); template static NST_FORCE_INLINE T* Blit3xCenter(T* NST_RESTRICT,const Input::Pixel* NST_RESTRICT,const Input::Palette&); template static NST_FORCE_INLINE T* Blit2xLine(T*,const Input::Pixel*,const Input::Palette&,long); template static NST_FORCE_INLINE T* Blit3xLine(T*,const Input::Pixel*,const Input::Palette&,long); template static void Blit2x(const Input&,const Output&); template static void Blit3x(const Input&,const Output&); const Path path; }; } } } #endif nestopia-1.51.1/source/core/NstVideoFilterxBR.cpp000066400000000000000000001316151411157722000217010ustar00rootroot00000000000000/* Hyllian's 3xBR v3.3a-b-c Copyright (C) 2011, 2012 Hyllian/Jararaca - sergiogdb@gmail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "NstAssert.hpp" #include "NstVideoRenderer.hpp" #include "NstVideoFilterxBR.hpp" namespace Nes { namespace Core { namespace Video { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif /** * Constructor */ Renderer::FilterxBR::FilterxBR(const RenderState& state, const bool blend, const schar corner_rounding) : _blend(blend), Filter (state), path (GetPath(state, blend, corner_rounding)) { _index = new YUVPixel*[32768]; //Todo: When a setting is changed before starting a game, "transform" will //not be called for some reason. (This is a quick workaround) initCache(); } /** * Creates a RGB to YUV lookup table */ void Renderer::FilterxBR::initCache() const { for(int c=0; c < 32768; c++) { //Hmm, 32000+ should be enough YUVPixel *yuv_pt = new YUVPixel; *yuv_pt = YUVPixel::FromWord(c, format.bpp); _index[c] = yuv_pt; } } Renderer::FilterxBR::~FilterxBR() { freeCache(); free(_index); } void Renderer::FilterxBR::freeCache() const { //Frees cached colors (note that null pointes can be freed safely). for(int c=0; c < 32768; c++) free(_index[c]); } Renderer::FilterxBR::Path Renderer::FilterxBR::GetPath(const RenderState& state, const bool blend, const schar corner_rounding) { if (state.bits.count == 32) { //Color mode 888 if (state.filter == RenderState::FILTER_2XBR) { if (blend) { if (corner_rounding == 0) return &FilterxBR::Xbr2X; if (corner_rounding == 1) return &FilterxBR::Xbr2X; return &FilterxBR::Xbr2X; } if (corner_rounding == 0) return &FilterxBR::Xbr2X; if (corner_rounding == 1) return &FilterxBR::Xbr2X; return &FilterxBR::Xbr2X; } else if (state.filter == RenderState::FILTER_3XBR) { if (blend) { if (corner_rounding == 0) return &FilterxBR::Xbr3X; if (corner_rounding == 1) return &FilterxBR::Xbr3X; return &FilterxBR::Xbr3X; } if (corner_rounding == 0) return &FilterxBR::Xbr3X; if (corner_rounding == 1) return &FilterxBR::Xbr3X; return &FilterxBR::Xbr3X; } if (blend) { if (corner_rounding == 0) return &FilterxBR::Xbr4X; if (corner_rounding == 1) return &FilterxBR::Xbr4X; return &FilterxBR::Xbr4X; } if (corner_rounding == 0) return &FilterxBR::Xbr4X; if (corner_rounding == 1) return &FilterxBR::Xbr4X; return &FilterxBR::Xbr4X; } else if (state.bits.mask.g == 0x07E0) { //Color mode 565 if (state.filter == RenderState::FILTER_2XBR) { if (blend) { if (corner_rounding == 0) return &FilterxBR::Xbr2X; if (corner_rounding == 1) return &FilterxBR::Xbr2X; return &FilterxBR::Xbr2X; } if (corner_rounding == 0) return &FilterxBR::Xbr2X; if (corner_rounding == 1) return &FilterxBR::Xbr2X; return &FilterxBR::Xbr2X; } else if (state.filter == RenderState::FILTER_3XBR) { if (blend) { if (corner_rounding == 0) return &FilterxBR::Xbr3X; if (corner_rounding == 1) return &FilterxBR::Xbr3X; return &FilterxBR::Xbr3X; } if (corner_rounding == 0) return &FilterxBR::Xbr3X; if (corner_rounding == 1) return &FilterxBR::Xbr3X; return &FilterxBR::Xbr3X; } if (blend) { if (corner_rounding == 0) return &FilterxBR::Xbr4X; if (corner_rounding == 1) return &FilterxBR::Xbr4X; return &FilterxBR::Xbr4X; } if (corner_rounding == 0) return &FilterxBR::Xbr4X; if (corner_rounding == 1) return &FilterxBR::Xbr4X; return &FilterxBR::Xbr4X; } else { //Color mode 555 if (state.filter == RenderState::FILTER_2XBR) { if (blend) { if (corner_rounding == 0) return &FilterxBR::Xbr2X; if (corner_rounding == 1) return &FilterxBR::Xbr2X; return &FilterxBR::Xbr2X; } if (corner_rounding == 0) return &FilterxBR::Xbr2X; if (corner_rounding == 1) return &FilterxBR::Xbr2X; return &FilterxBR::Xbr2X; } else if (state.filter == RenderState::FILTER_3XBR) { if (blend) { if (corner_rounding == 0) return &FilterxBR::Xbr3X; if (corner_rounding == 1) return &FilterxBR::Xbr3X; return &FilterxBR::Xbr3X; } if (corner_rounding == 0) return &FilterxBR::Xbr3X; if (corner_rounding == 1) return &FilterxBR::Xbr3X; return &FilterxBR::Xbr3X; } if (blend) { if (corner_rounding == 0) return &FilterxBR::Xbr4X; if (corner_rounding == 1) return &FilterxBR::Xbr4X; return &FilterxBR::Xbr4X; } if (corner_rounding == 0) return &FilterxBR::Xbr4X; if (corner_rounding == 1) return &FilterxBR::Xbr4X; return &FilterxBR::Xbr4X; } //return NULL; } /** * Checks if this filter can be used with the render state * * Currently only supports 888, 565 and 555 output. */ bool Renderer::FilterxBR::Check(const RenderState& state) { return ( (state.filter == RenderState::FILTER_2XBR || state.filter == RenderState::FILTER_3XBR || state.filter == RenderState::FILTER_4XBR )&& ( (state.bits.count == 16 && state.bits.mask.b == 0x001F && ((state.bits.mask.g == 0x07E0 && state.bits.mask.r == 0xF800) || (state.bits.mask.g == 0x03E0 && state.bits.mask.r == 0x7C00))) ||//*/ (state.bits.count == 32 && state.bits.mask.r == 0xFF0000 && state.bits.mask.g == 0x00FF00 && state.bits.mask.b == 0x0000FF) ) ); } /** * 4x filtering, with blend support */ template void Renderer::FilterxBR::Xbr4X(const Input& input,const Output& output) { #pragma region Sets up pointers to source pixels //Gets the pixels to filter. NST_RESTRICT tells the compiler to not alias //the pointer. const word* NST_RESTRICT src = input.pixels; //Size of a raster line in output const long pitch = (output.pitch * 3) + output.pitch - (WIDTH*4 * sizeof(T)); //Creates a non-aliased array with four enteries. First is the destination pixels //cast into the type of pointer this function has been templated to use, the others //points at the start of the next three lines. T* NST_RESTRICT dst[4] = { static_cast(output.pixels), reinterpret_cast(static_cast(output.pixels) + output.pitch), reinterpret_cast(static_cast(output.pixels) + output.pitch * 2), reinterpret_cast(static_cast(output.pixels) + output.pitch * 3) }; //const long pad = output.pitch - long(sizeof(dword) * WIDTH); const uint MAX_PIXELS = WIDTH * HEIGHT; #pragma endregion for (int y=0; y < MAX_PIXELS; y += WIDTH) { #pragma region Clamps y coords int ym1 = y - WIDTH, ym2 = y - 2*WIDTH; if (ym1 < 0) ym1 = y; if (ym2 < 0) ym2 = y; int y1 = y + WIDTH, y2 = y + 2*WIDTH; if (y1 >= MAX_PIXELS) y1 = y; if (y2 >= MAX_PIXELS) y2 = y; #pragma endregion for (int x=0; x < WIDTH; ++x, dst[0] += 4, dst[1] += 4, dst[2] += 4, dst[3] += 4) { #pragma region Clamps x coords int xm1 = x - 1, xm2 = x - 2; if (xm1 < 0) xm1 = 0; if (xm2 < 0) xm1 = 0; int x1 = x + 1, x2 = x + 2; if (x1 >= WIDTH) x1 = WIDTH - 1; if (x2 >= WIDTH) x2 = WIDTH - 1; #pragma endregion #pragma region Fetches pixels and converts to YUV //Result pixels YUVPixel e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, ea, eb, ec, ed, ee, ef; //Fetches pixels and converts to YUV YUVPixel pa, pb, pc, pd, pe, pf, pg, ph, pi, a1, b1, c1, a0, d0, g0, c4, f4, i4, g5, h5, i5; pa = getPixel(input.palette[src[xm1 + ym1]]); pb = getPixel(input.palette[src[x + ym1]]); pc = getPixel(input.palette[src[x1 + ym1]]); pd = getPixel(input.palette[src[xm1 + y]]); pe = e0 = e1 = e2 = e3 = e4 = e5 = e6 = e7= e8 = e9 = ea = eb = ec = ed = ee = ef = getPixel(input.palette[src[x + y]]);; pf = getPixel(input.palette[src[x1 + y]]); pg = getPixel(input.palette[src[xm1 + y1]]); ph = getPixel(input.palette[src[x + y1]]); pi = getPixel(input.palette[src[x1 + y1]]); a1 = getPixel(input.palette[src[xm1 + ym2]]); b1 = getPixel(input.palette[src[x + ym2]]); c1 = getPixel(input.palette[src[x1 + ym2]]); a0 = getPixel(input.palette[src[xm2 + ym1]]); d0 = getPixel(input.palette[src[xm2 + y]]); g0 = getPixel(input.palette[src[xm2 + y1]]); c4 = getPixel(input.palette[src[x2 + ym1]]); f4 = getPixel(input.palette[src[x2 + y]]); i4 = getPixel(input.palette[src[x2 + y1]]); g5 = getPixel(input.palette[src[xm1 + y2]]); h5 = getPixel(input.palette[src[x + y2]]); i5 = getPixel(input.palette[src[x1 + y2]]); #pragma endregion #pragma region Filters pixel Kernel4X(pe, pi, ph, pf, pg, pc, pd, pb, f4, i4, h5, i5, ef, ee, eb, e3, e7, ea, ed, ec); Kernel4X(pe, pc, pf, pb, pi, pa, ph, pd, b1, c1, f4, c4, e3, e7, e2, e0, e1, e6, eb, ef); Kernel4X(pe, pa, pb, pd, pc, pg, pf, ph, d0, a0, b1, a1, e0, e1, e4, ec, e8, e5, e2, e3); Kernel4X(pe, pg, pd, ph, pa, pi, pb, pf, h5, g5, d0, g0, ec, e8, ed, ef, ee, e9, e4, e0); #pragma endregion #pragma region Writes out result //The result is 16 pixels (as the image is expanded by 4x) dst[0][0] = (T) e0.rgb; dst[0][1] = (T) e1.rgb; dst[0][2] = (T) e2.rgb; dst[0][3] = (T) e3.rgb; dst[1][0] = (T) e4.rgb; dst[1][1] = (T) e5.rgb; dst[1][2] = (T) e6.rgb; dst[1][3] = (T) e7.rgb; dst[2][0] = (T) e8.rgb; dst[2][1] = (T) e9.rgb; dst[2][2] = (T) ea.rgb; dst[2][3] = (T) eb.rgb; dst[3][0] = (T) ec.rgb; dst[3][1] = (T) ed.rgb; dst[3][2] = (T) ee.rgb; dst[3][3] = (T) ef.rgb; #pragma endregion } #pragma region Moves dest to the next next line. dst[0] = reinterpret_cast(reinterpret_cast(dst[0]) + pitch); dst[1] = reinterpret_cast(reinterpret_cast(dst[1]) + pitch); dst[2] = reinterpret_cast(reinterpret_cast(dst[2]) + pitch); dst[3] = reinterpret_cast(reinterpret_cast(dst[3]) + pitch); #pragma endregion } } /** * 3x filtering, with blend support */ template void Renderer::FilterxBR::Xbr3X(const Input& input,const Output& output) { #pragma region Sets up pointers to source pixels //Gets the pixels to filter. NST_RESTRICT tells the compiler to not alias //the pointer. const word* NST_RESTRICT src = input.pixels; //Size of a raster line in output const long pitch = (output.pitch * 2) + output.pitch - (WIDTH*3 * sizeof(T)); //Creates a non-aliased array with three enteries. First is the destination pixels //cast into the type of pointer this function has been templated to use, the others //points at the start of the next two lines. T* NST_RESTRICT dst[3] = { static_cast(output.pixels), reinterpret_cast(static_cast(output.pixels) + output.pitch), reinterpret_cast(static_cast(output.pixels) + output.pitch * 2) }; //const long pad = output.pitch - long(sizeof(dword) * WIDTH); const uint MAX_PIXELS = WIDTH * HEIGHT; #pragma endregion for (int y=0; y < MAX_PIXELS; y += WIDTH) { #pragma region Clamps y coords int ym1 = y - WIDTH, ym2 = y - 2*WIDTH; if (ym1 < 0) ym1 = y; if (ym2 < 0) ym2 = y; int y1 = y + WIDTH, y2 = y + 2*WIDTH; if (y1 >= MAX_PIXELS) y1 = y; if (y2 >= MAX_PIXELS) y2 = y; #pragma endregion for (int x=0; x < WIDTH; ++x, dst[0] += 3, dst[1] += 3, dst[2] += 3) { #pragma region Clamps x coords int xm1 = x - 1, xm2 = x - 2; if (xm1 < 0) xm1 = 0; if (xm2 < 0) xm1 = 0; int x1 = x + 1, x2 = x + 2; if (x1 >= WIDTH) x1 = WIDTH - 1; if (x2 >= WIDTH) x2 = WIDTH - 1; #pragma endregion #pragma region Fetches pixels and converts to YUV //Result pixels YUVPixel e0, e1, e2, e3, e4, e5, e6, e7, e8; //Fetches pixels and converts to YUV YUVPixel pa, pb, pc, pd, pe, pf, pg, ph, pi, a1, b1, c1, a0, d0, g0, c4, f4, i4, g5, h5, i5; pa = getPixel(input.palette[src[xm1 + ym1]]); pb = getPixel(input.palette[src[x + ym1]]); pc = getPixel(input.palette[src[x1 + ym1]]); pd = getPixel(input.palette[src[xm1 + y]]); pe = e0 = e1 = e2 = e3 = e4 = e5 = e6 = e7= e8 = getPixel(input.palette[src[x + y]]);; pf = getPixel(input.palette[src[x1 + y]]); pg = getPixel(input.palette[src[xm1 + y1]]); ph = getPixel(input.palette[src[x + y1]]); pi = getPixel(input.palette[src[x1 + y1]]); a1 = getPixel(input.palette[src[xm1 + ym2]]); b1 = getPixel(input.palette[src[x + ym2]]); c1 = getPixel(input.palette[src[x1 + ym2]]); a0 = getPixel(input.palette[src[xm2 + ym1]]); d0 = getPixel(input.palette[src[xm2 + y]]); g0 = getPixel(input.palette[src[xm2 + y1]]); c4 = getPixel(input.palette[src[x2 + ym1]]); f4 = getPixel(input.palette[src[x2 + y]]); i4 = getPixel(input.palette[src[x2 + y1]]); g5 = getPixel(input.palette[src[xm1 + y2]]); h5 = getPixel(input.palette[src[x + y2]]); i5 = getPixel(input.palette[src[x1 + y2]]); #pragma endregion #pragma region Filters pixel Kernel3X(pe, pi, ph, pf, pg, pc, pd, pb, f4, i4, h5, i5, e2, e5, e6, e7, e8); Kernel3X(pe, pc, pf, pb, pi, pa, ph, pd, b1, c1, f4, c4, e0, e1, e8, e5, e2); Kernel3X(pe, pa, pb, pd, pc, pg, pf, ph, d0, a0, b1, a1, e6, e3, e2, e1, e0); Kernel3X(pe, pg, pd, ph, pa, pi, pb, pf, h5, g5, d0, g0, e8, e7, e0, e3, e6); #pragma endregion #pragma region Writes out result //The result is nine pixels (as the image is expanded) dst[0][0] = (T) e0.rgb; dst[0][1] = (T) e1.rgb; dst[0][2] = (T) e2.rgb; dst[1][0] = (T) e3.rgb; dst[1][1] = (T) e4.rgb; dst[1][2] = (T) e5.rgb; dst[2][0] = (T) e6.rgb; dst[2][1] = (T) e7.rgb; dst[2][2] = (T) e8.rgb; #pragma endregion } #pragma region Moves dest to the next next line. dst[0] = reinterpret_cast(reinterpret_cast(dst[0]) + pitch); dst[1] = reinterpret_cast(reinterpret_cast(dst[1]) + pitch); dst[2] = reinterpret_cast(reinterpret_cast(dst[2]) + pitch); #pragma endregion } } /** * This function does the actual filtering. Input is "NES CLUT" stuff, output is plain * 16-bit per color (RGB 565 or 555) or 32-bit per color (ARGB 0888) AFAICT * * Implements 2xBR */ template void Renderer::FilterxBR::Xbr2X(const Input& input,const Output& output) { #pragma region Sets up pointers to source pixels //Gets the pixels to filter. NST_RESTRICT tells the compiler to not alias //the pointer. const word* NST_RESTRICT src = input.pixels; //Size of a raster line in output const long pitch = output.pitch; //Creates a non-aliased array with two enteries. First is the destination pixels //cast into the type of pointer this function has been templated to use, the other //points at the start of the next line. T* NST_RESTRICT dst[2] = { static_cast(output.pixels), reinterpret_cast(static_cast(output.pixels) + pitch) }; //const long pad = output.pitch - long(sizeof(dword) * WIDTH); const uint MAX_PIXELS = WIDTH * HEIGHT; #pragma endregion for (int y=0; y < MAX_PIXELS; y += WIDTH) { #pragma region Clamps y coords //Clamps y coords int ym1 = y - WIDTH, ym2 = y - 2*WIDTH; if (ym1 < 0) ym1 = y; if (ym2 < 0) ym2 = y; int y1 = y + WIDTH, y2 = y + 2*WIDTH; if (y1 >= MAX_PIXELS) y1 = y; if (y2 >= MAX_PIXELS) y2 = y; #pragma endregion for (int x=0; x < WIDTH; ++x, dst[0] += 2, dst[1] += 2) { #pragma region Clamps x coords //Clamps x coords int xm1 = x - 1, xm2 = x - 2; if (xm1 < 0) xm1 = 0; if (xm2 < 0) xm1 = 0; int x1 = x + 1, x2 = x + 2; if (x1 >= WIDTH) x1 = WIDTH - 1; if (x2 >= WIDTH) x2 = WIDTH - 1; #pragma endregion #pragma region Fetches pixels and converts to YUV //Result pixels YUVPixel e0, e1, e2, e3; //Fetches pixels and converts to YUV YUVPixel pa, pb, pc, pd, pe, pf, pg, ph, pi, a1, b1, c1, a0, d0, g0, c4, f4, i4, g5, h5, i5; pa = getPixel(input.palette[src[xm1 + ym1]]); pb = getPixel(input.palette[src[x + ym1]]); pc = getPixel(input.palette[src[x1 + ym1]]); pd = getPixel(input.palette[src[xm1 + y]]); pe = e0 = e1 = e2 = e3 = getPixel(input.palette[src[x + y]]);; pf = getPixel(input.palette[src[x1 + y]]); pg = getPixel(input.palette[src[xm1 + y1]]); ph = getPixel(input.palette[src[x + y1]]); pi = getPixel(input.palette[src[x1 + y1]]); a1 = getPixel(input.palette[src[xm1 + ym2]]); b1 = getPixel(input.palette[src[x + ym2]]); c1 = getPixel(input.palette[src[x1 + ym2]]); a0 = getPixel(input.palette[src[xm2 + ym1]]); d0 = getPixel(input.palette[src[xm2 + y]]); g0 = getPixel(input.palette[src[xm2 + y1]]); c4 = getPixel(input.palette[src[x2 + ym1]]); f4 = getPixel(input.palette[src[x2 + y]]); i4 = getPixel(input.palette[src[x2 + y1]]); g5 = getPixel(input.palette[src[xm1 + y2]]); h5 = getPixel(input.palette[src[x + y2]]); i5 = getPixel(input.palette[src[x1 + y2]]); #pragma endregion #pragma region Filters pixel Kernel2X(pe, pi, ph, pf, pg, pc, pd, pb, f4, i4, h5, i5, e1, e2, e3); Kernel2X(pe, pc, pf, pb, pi, pa, ph, pd, b1, c1, f4, c4, e0, e3, e1); Kernel2X(pe, pa, pb, pd, pc, pg, pf, ph, d0, a0, b1, a1, e2, e1, e0); Kernel2X(pe, pg, pd, ph, pa, pi, pb, pf, h5, g5, d0, g0, e3, e0, e2); #pragma endregion #pragma region Writes out result dst[0][0] = (T) e0.rgb; dst[0][1] = (T) e1.rgb; dst[1][0] = (T) e2.rgb; dst[1][1] = (T) e3.rgb; #pragma endregion } #pragma region Moves dest to the next next line. dst[0] = reinterpret_cast(reinterpret_cast(dst[1]) + (pitch - long(sizeof(T) * WIDTH*2))); dst[1] = reinterpret_cast(reinterpret_cast(dst[0]) + pitch); #pragma endregion } } void Renderer::FilterxBR::Blit(const Input& input,const Output& output,uint) { (*this.*path)( input, output ); } #pragma region Kernels template void Renderer::FilterxBR::Kernel2X(YUVPixel pe, YUVPixel pi, YUVPixel ph, YUVPixel pf, YUVPixel pg, YUVPixel pc, YUVPixel pd, YUVPixel pb, YUVPixel f4, YUVPixel i4, YUVPixel h5, YUVPixel i5, YUVPixel &n1, YUVPixel &n2, YUVPixel &n3) { if (!(pe != ph && pe != pf)) return; uint e = (pe.YuvDifference(pc) + pe.YuvDifference(pg) + pi.YuvDifference(h5) + pi.YuvDifference(f4)) + (ph.YuvDifference(pf) << 2); uint i = (ph.YuvDifference(pd) + ph.YuvDifference(i5) + pf.YuvDifference(i4) + pf.YuvDifference(pb)) + (pe.YuvDifference(pi) << 2); YUVPixel px = (pe.YuvDifference(pf) <= pe.YuvDifference(ph)) ? pf : ph; //A if (NONE && ((e < i) && (!pf.isLike(pb) && !pf.isLike(pc) || !ph.isLike(pd) && !ph.isLike(pg) || pe.isLike(pi) && (!pf.isLike(f4) && !pf.isLike(i4) || !ph.isLike(h5) && !ph.isLike(i5)) || pe.isLike(pg) || pe.isLike(pc))) //B || SOME && ((e < i) && (!pf.isLike(pb) && !ph.isLike(pd) || pe.isLike(pi) && (!pf.isLike(i4) && !ph.isLike(i5)) || pe.isLike(pg) || pe.isLike(pc))) //C || ALL && (e < i)) { uint ke = pf.YuvDifference(pg); uint ki = ph.YuvDifference(pc); bool ex2 = (pe != pc && pb != pc); bool ex3 = (pe != pg && pd != pg); if (((ke << 1) <= ki) && ex3 || (ke >= (ki << 1)) && ex2) { if (BLEND) { if (((ke << 1) <= ki) && ex3) Left2_2X(n3, n2, px); if ((ke >= (ki << 1)) && ex2) Up2_2X(n3, n1, px); }else { n3 = px; } } else if (BLEND) Dia_2X(n3, px); } else if (BLEND && e <= i) { AlphaBlend64W(n3, px); } } template void Renderer::FilterxBR::Kernel3X(const YUVPixel pe, const YUVPixel pi, const YUVPixel ph, const YUVPixel pf, const YUVPixel pg, const YUVPixel pc, const YUVPixel pd, const YUVPixel pb, const YUVPixel f4, const YUVPixel i4, const YUVPixel h5, const YUVPixel i5, YUVPixel &n2, YUVPixel &n5, YUVPixel &n6, YUVPixel &n7, YUVPixel &n8) const { if (!(pe != ph && pe != pf)) return; uint e = (pe.YuvDifference(pc) + pe.YuvDifference(pg) + pi.YuvDifference(h5) + pi.YuvDifference(f4)) + (ph.YuvDifference(pf) << 2); uint i = (ph.YuvDifference(pd) + ph.YuvDifference(i5) + pf.YuvDifference(i4) + pf.YuvDifference(pb)) + (pe.YuvDifference(pi) << 2); //A if (NONE && ((e < i) && (!pf.isLike(pb) && !pf.isLike(pc) || !ph.isLike(pd) && !ph.isLike(pg) || pe.isLike(pi) && (!pf.isLike(f4) && !pf.isLike(i4) || !ph.isLike(h5) && !ph.isLike(i5)) || pe.isLike(pg) || pe.isLike(pc))) //B || SOME && ((e < i) && (!pf.isLike(pb) && !ph.isLike(pd) || pe.isLike(pi) && (!pf.isLike(i4) && !ph.isLike(i5)) || pe.isLike(pg) || pe.isLike(pc))) //C || ALL && (e < i)) { uint ke = pf.YuvDifference(pg); uint ki = ph.YuvDifference(pc); bool ex2 = (pe != pc && pb != pc); bool ex3 = (pe != pg && pd != pg); YUVPixel px = (pe.YuvDifference(pf) <= pe.YuvDifference(ph)) ? pf : ph; if (((ke << 1) <= ki) && ex3 && (ke >= (ki << 1)) && ex2) { LeftUp2_3X(n7, n5, n6, n2, n8, px); } else if (((ke << 1) <= ki) && ex3) { Left2_3X(n7, n5, n6, n8, px); } else if ((ke >= (ki << 1)) && ex2) { Up2_3X(n5, n7, n2, n8, px); } else { Dia_3X(n8, n5, n7, px); } } else if (BLEND && e <= i) { AlphaBlend128W(n8, (pe.YuvDifference(pf) <= pe.YuvDifference(ph)) ? pf : ph); } } template void Renderer::FilterxBR::Kernel4X(const YUVPixel pe, const YUVPixel pi, const YUVPixel ph, const YUVPixel pf, const YUVPixel pg, const YUVPixel pc, const YUVPixel pd, const YUVPixel pb, const YUVPixel f4, const YUVPixel i4, const YUVPixel h5, const YUVPixel i5, YUVPixel &n15, YUVPixel &n14, YUVPixel &n11, YUVPixel &n3, YUVPixel &n7, YUVPixel &n10, YUVPixel &n13, YUVPixel &n12) const { if (!(pe != ph && pe != pf)) return; uint e = (pe.YuvDifference(pc) + pe.YuvDifference(pg) + pi.YuvDifference(h5) + pi.YuvDifference(f4)) + (ph.YuvDifference(pf) << 2); uint i = (ph.YuvDifference(pd) + ph.YuvDifference(i5) + pf.YuvDifference(i4) + pf.YuvDifference(pb)) + (pe.YuvDifference(pi) << 2); YUVPixel px = (pe.YuvDifference(pf) <= pe.YuvDifference(ph)) ? pf : ph; //A if (NONE && ((e < i) && (!pf.isLike(pb) && !pf.isLike(pc) || !ph.isLike(pd) && !ph.isLike(pg) || pe.isLike(pi) && (!pf.isLike(f4) && !pf.isLike(i4) || !ph.isLike(h5) && !ph.isLike(i5)) || pe.isLike(pg) || pe.isLike(pc))) //B || SOME && ((e < i) && (!pf.isLike(pb) && !ph.isLike(pd) || pe.isLike(pi) && (!pf.isLike(i4) && !ph.isLike(i5)) || pe.isLike(pg) || pe.isLike(pc))) //C || ALL && (e < i)) { uint ke = pf.YuvDifference(pg); uint ki = ph.YuvDifference(pc); bool ex2 = (pe != pc && pb != pc); bool ex3 = (pe != pg && pd != pg); if (((ke << 1) <= ki) && ex3 || (ke >= (ki << 1)) && ex2) { if (((ke << 1) <= ki) && ex3) Left2_4X(n15, n14, n11, n13, n12, n10, px); if ((ke >= (ki << 1)) && ex2) Up2_4X(n15, n14, n11, n3, n7, n10, px); } else Dia_4X(n15, n14, n11, px); } else if (BLEND && e <= i) { AlphaBlend128W(n15, px); } } #pragma endregion void Renderer::FilterxBR::Transform(const byte (&src)[PALETTE][3],Input::Palette& dst) const { freeCache(); initCache(); //Truncates colors to 15-bit //Idea: Insert the true colors into the YUV cache. There's no real harm and will //give colors almost as good as the true 32-bit solution. if (format.bpp == 32) { for(int i=0, ncol=0; i < PALETTE; i++, ncol++) { //Converts to 1555 dst[i] = ( (src[i][0] & 0xF8) << 7 | (src[i][1] & 0xF8) << 2 | (src[i][2] & 0xF8) >> 3 ); dword col = src[i][0] << 16 | src[i][1] << 8 | src[i][2]; *_index[dst[i]] = YUVPixel::FromDWord(col); } } else if (format.bpp == 16) { //Removes the extra 1 bit of precision for(int i=0, ncol=0; i < PALETTE; i++, ncol++) { //Converts to 1555 dst[i] = ( (src[i][0] & 0xF8) << 7 | (src[i][1] & 0xF8) << 2 | (src[i][2] & 0xF8) >> 3 ); *_index[dst[i]] = YUVPixel::FromWord(dst[i], format.bpp); } } else //Assumes "Filter::Transform" spits out '1'-5-5-5 Filter::Transform( src, dst ); } template void Renderer::FilterxBR::Left2_2X(YUVPixel &n3, YUVPixel &n2, YUVPixel pixel) { AlphaBlend192W(n3, pixel); AlphaBlend64W(n2, pixel); } template void Renderer::FilterxBR::Up2_2X(YUVPixel &n3, YUVPixel &n1, YUVPixel pixel) { AlphaBlend192W(n3, pixel); AlphaBlend64W(n1, pixel); } template void Renderer::FilterxBR::Dia_2X(YUVPixel &n3, YUVPixel pixel) { AlphaBlend128W(n3, pixel); } template void Renderer::FilterxBR::LeftUp2_3X(YUVPixel &n7, YUVPixel &n5, YUVPixel &n6, YUVPixel &n2, YUVPixel &n8, const YUVPixel pixel) const { if (BLEND) { AlphaBlend192W(n7, pixel); AlphaBlend64W(n6, pixel); } else { n7 = pixel; } n5 = n7; n2 = n6; n8 = pixel; } template void Renderer::FilterxBR::LeftUp2_4X(YUVPixel &n15, YUVPixel &n14, YUVPixel &n11, YUVPixel &n13, YUVPixel &n12, YUVPixel &n10, YUVPixel &n7, YUVPixel &n3, const YUVPixel pixel) const { if (BLEND) { AlphaBlend192W(n13, pixel); AlphaBlend64W(n12, pixel); } else { n13 = pixel; } n15 = n14 = n11 = pixel; n10 = n3 = n12; n7 = n13; } template void Renderer::FilterxBR::Left2_3X(YUVPixel &n7, YUVPixel &n5, YUVPixel &n6, YUVPixel &n8, const YUVPixel pixel) const { if (BLEND) { AlphaBlend192W(n7, pixel); AlphaBlend64W(n5, pixel); AlphaBlend64W(n6, pixel); } else { n7 = pixel; } n8 = pixel; } template void Renderer::FilterxBR::Left2_4X(YUVPixel &n15, YUVPixel &n14, YUVPixel &n11, YUVPixel &n13, YUVPixel &n12, YUVPixel &n10, const YUVPixel pixel) const { if (BLEND) { AlphaBlend192W(n11, pixel); AlphaBlend192W(n13, pixel); AlphaBlend64W(n10, pixel); AlphaBlend64W(n12, pixel); } else { n11 = pixel; n13 = pixel; } n14 = pixel; n15 = pixel; } template void Renderer::FilterxBR::Up2_3X(YUVPixel &n5, YUVPixel &n7, YUVPixel &n2, YUVPixel &n8, const YUVPixel pixel) const { if (BLEND) { AlphaBlend192W(n5, pixel); AlphaBlend64W(n7, pixel); AlphaBlend64W(n2, pixel); } else { n5 = pixel; } n8 = pixel; } template void Renderer::FilterxBR::Up2_4X(YUVPixel &n15, YUVPixel &n14, YUVPixel &n11, YUVPixel &n3, YUVPixel &n7, YUVPixel &n10, const YUVPixel pixel) const { if (BLEND) { AlphaBlend192W(n14, pixel); AlphaBlend192W(n7, pixel); AlphaBlend64W(n10, pixel); AlphaBlend64W(n3, pixel); } else { n14 = pixel; n7 = pixel; } n11 = pixel; n15 = pixel; } template void Renderer::FilterxBR::Dia_3X(YUVPixel &n8, YUVPixel &n5, YUVPixel &n7, const YUVPixel pixel) const { if (BLEND) { AlphaBlend224W(n8, pixel); AlphaBlend32W(n5, pixel); AlphaBlend32W(n7, pixel); } else { n8 = pixel; } } template void Renderer::FilterxBR::Dia_4X(YUVPixel &n15, YUVPixel &n14, YUVPixel &n11, const YUVPixel pixel) const { if (BLEND) { AlphaBlend128W(n11, pixel); AlphaBlend128W(n14, pixel); } n15 = pixel; } //=========================== // Alpha blending // This impl. crunches down the interpolation to 15-bit, needlessly. // Currently these functions works something like this: // 1. Two YUV pixels are fed in. // 2. The pixels are converted to 15-Bit RGB // 3. The pixels are blended // 4. The pixels are converted back to YUV by the getPixel function // // New way should be something like this (Todo) // 1. Add together the 32-bit RGB pixels // 2. Return the result as a YUVPixel with the blended RGB data, and // no YUV data. // // i.e. col = ... with "& 0xFF" for 32bit and "& 0xF8" for 16/15 bit and 7/2/3 changed to R_SHIFT/G_SHIFT/B_SHIFT // dst = new YUVPixel // dst.rgb = col // // One could then take things a little further but having it return the result directly instead of packing it into // a YUV struct. Would make the code easier to read too. //=========================== template void Renderer::FilterxBR::AlphaBlend32W(YUVPixel &dst, const YUVPixel src) const { dword col = (((dst.getRed() * 7 + src.getRed()) / 8) & 0xF8) << 7 | (((dst.getGreen() * 7 + src.getGreen()) / 8) & 0xF8) << 2 | (((dst.getBlue() * 7 + src.getBlue()) / 8) & 0xF8) >> 3; dst = getPixel(col); } template void Renderer::FilterxBR::AlphaBlend64W(YUVPixel &dst, const YUVPixel src) const { dword col = (((dst.getRed() * 3 + src.getRed()) / 4) & 0xF8) << 7 | (((dst.getGreen() * 3 + src.getGreen()) / 4) & 0xF8) << 2 | (((dst.getBlue() * 3 + src.getBlue()) / 4) & 0xF8) >> 3; dst = getPixel(col); } template void Renderer::FilterxBR::AlphaBlend128W(YUVPixel &dst, const YUVPixel src) const { dword col = (((dst.getRed() + src.getRed()) / 2) & 0xF8) << 7 | (((dst.getGreen() + src.getGreen()) / 2) & 0xF8) << 2 | (((dst.getBlue() + src.getBlue()) / 2) & 0xF8) >> 3; dst = getPixel(col); } template void Renderer::FilterxBR::AlphaBlend192W(YUVPixel &dst, const YUVPixel src) const { dword col = (((dst.getRed() + src.getRed() *3) / 4) & 0xF8) << 7 | (((dst.getGreen() + src.getGreen() *3) / 4) & 0xF8) << 2 | (((dst.getBlue() + src.getBlue() *3) / 4) & 0xF8) >> 3; dst = getPixel(col); } template void Renderer::FilterxBR::AlphaBlend224W(YUVPixel &dst, const YUVPixel src) const { dword col = (((dst.getRed() + src.getRed() * 7) / 8) & 0xF8) << 7 | (((dst.getGreen() + src.getGreen() * 7) / 8) & 0xF8) << 2 | (((dst.getBlue() + src.getBlue() * 7) / 8) & 0xF8) >> 3; dst = getPixel(col); } #pragma region Pixel functions //=========================== // Pixel functions //=========================== YUVPixel& Renderer::FilterxBR::getPixel(dword col) const { //Using a 32KB lookup cache return *_index[col & 0x7FFF]; } /** * Creates a YUV pixel from a 15-bit RGB color. */ YUVPixel YUVPixel::FromWord(const dword num, int bpp) { int r = (num & 0x7C00) >> 7; int g = (num & 0x3E0) >> 2; int b = (num & 0x1F) << 3; //Note, using the same formula as ImageResizer. Note that ImageResizer //caches the YUV calculations, that might be a good idea to do here too. YUVPixel px; dword Luminance = r * 0.299f + g * 0.587f + b * 0.114f; //Alt: (0.257 * R) + (0.504 * G) + (0.098 * B) + 16 dword ChrominanceU = 127.5f + r * 0.5f - g * 0.418688f - b * 0.081312f; //Alt: -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128 dword ChrominanceV = 127.5f - r * 0.168736f - g * 0.331264f + b * 0.5f; //Alt: (0.439 * R) - (0.368 * G) - (0.071 * B) + 128 px.yuv = Luminance << 16 | ChrominanceU << 8 | ChrominanceV; if (bpp == 32) { //Rounds colors towards dark/light if (r > 127) r |= 7; if (g > 127) g |= 7; if (b > 127) b |= 7; px.rgb = r << 16 | g << 8 | b << 0; } else if (bpp == 16) { if (g > 127) g |= 4; px.rgb = r << 8 | g << 3 | b >> 3; } else { //Todo: is RGB555 1-5-5-5? That's what this assumes px.rgb = r << 7 | g << 2 | b >> 3; } return px; } /** * Creates a YUV pixel from a 32-bit RGB color. */ YUVPixel YUVPixel::FromDWord(const dword num) { int r = (num & 0xFF0000) >> 16; int g = (num & 0xFF00) >> 8; int b = (num & 0xFF) >> 0; YUVPixel px; dword Luminance = r * 0.299f + g * 0.587f + b * 0.114f; //Alt: (0.257 * R) + (0.504 * G) + (0.098 * B) + 16 dword ChrominanceU = 127.5f + r * 0.5f - g * 0.418688f - b * 0.081312f; //Alt: -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128 dword ChrominanceV = 127.5f - r * 0.168736f - g * 0.331264f + b * 0.5f; //Alt: (0.439 * R) - (0.368 * G) - (0.071 * B) + 128 px.yuv = Luminance << 16 | ChrominanceU << 8 | ChrominanceV; //Composes final output pixel px.rgb = r << 16 | g << 8 | b << 0; return px; } uint YUVPixel::YuvDifference(YUVPixel px) const { return (uint)( 48 * abs(getY() - px.getY()) + 6 * abs(getV() - px.getV()) + 7 * abs(getU() - px.getU()) ); //return abs((int)(yuv - px.yuv)); } /** * Tests if the pixels are similar looking */ bool YUVPixel::isLike(YUVPixel px) const { return rgb == px.rgb; //return abs((int)(yuv - px.yuv)) < 155; } template byte YUVPixel::getRed() const { return (rgb & R_MASK) >> R_SHIFT; } template byte YUVPixel::getGreen() const { return (rgb & G_MASK) >> G_SHIFT; } template byte YUVPixel::getBlue() const { return (rgb & B_MASK) << B_SHIFT; } byte YUVPixel::getY() const { return (yuv & 0xFF0000) >> 16; } byte YUVPixel::getU() const { return (yuv & 0xFF00) >> 8; } byte YUVPixel::getV() const { return (yuv & 0xFF) >> 0; } bool YUVPixel::operator==(const YUVPixel &px) const { return rgb == px.rgb; } bool YUVPixel::operator!=(const YUVPixel &px) const { return rgb != px.rgb; } #pragma endregion } } } nestopia-1.51.1/source/core/NstVideoFilterxBR.hpp000066400000000000000000000166561411157722000217150ustar00rootroot00000000000000#ifndef NST_VIDEO_FILTER_XBR_H #define NST_VIDEO_FILTER_XBR_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Video { struct YUVPixel { public: dword rgb; //<-- Stores a RGB pixel in output format. dword yuv; inline static YUVPixel FromWord(const dword num, int bpp); inline static YUVPixel FromDWord(const dword num); inline bool isLike(YUVPixel px) const; /** * Gets a 15-bit rgb number. (Only used as debuging aid) */ template inline byte getRed() const; template inline byte getGreen() const; template inline byte getBlue() const; inline byte getY() const; inline byte getU() const; inline byte getV() const; inline bool operator==(const YUVPixel &rhs) const; inline bool operator!=(const YUVPixel &rhs) const; inline uint YuvDifference(YUVPixel px) const; }; class Renderer::FilterxBR : public Renderer::Filter { public: explicit FilterxBR(const RenderState&, const bool blend, const schar corner_rounding); static bool Check(const RenderState&); private: ~FilterxBR(); void freeCache() const; void initCache() const; typedef void (FilterxBR::*Path)(const Input&,const Output&); static Path GetPath(const RenderState&, const bool blend, const schar corner_rounding); void Blit(const Input&,const Output&,uint); void Transform(const byte (&)[PALETTE][3],Input::Palette&) const; template void Xbr4X(const Input&,const Output&); template void Xbr3X(const Input&,const Output&); template void Xbr2X(const Input&,const Output&); template inline void Kernel2X(YUVPixel pe, YUVPixel pi, YUVPixel ph, YUVPixel pf, YUVPixel pg, YUVPixel pc, YUVPixel pd, YUVPixel pb, YUVPixel f4, YUVPixel i4, YUVPixel h5, YUVPixel i5, YUVPixel &n1, YUVPixel &n2, YUVPixel &n3); template inline void Kernel3X(const YUVPixel pe, const YUVPixel pi, const YUVPixel ph, const YUVPixel pf, const YUVPixel pg, const YUVPixel pc, const YUVPixel pd, const YUVPixel pb, const YUVPixel f4, const YUVPixel i4, const YUVPixel h5, const YUVPixel i5, YUVPixel &n2, YUVPixel &n5, YUVPixel &n6, YUVPixel &n7, YUVPixel &n8) const; template inline void Kernel4X(const YUVPixel pe, const YUVPixel pi, const YUVPixel ph, const YUVPixel pf, const YUVPixel pg, const YUVPixel pc, const YUVPixel pd, const YUVPixel pb, const YUVPixel f4, const YUVPixel i4, const YUVPixel h5, const YUVPixel i5, YUVPixel &n15, YUVPixel &n14, YUVPixel &n11, YUVPixel &n3, YUVPixel &n7, YUVPixel &n10, YUVPixel &n13, YUVPixel &n12) const; template inline void Left2_2X(YUVPixel &n3, YUVPixel &n2, YUVPixel pixel); template inline void LeftUp2_3X(YUVPixel &n7, YUVPixel &n5, YUVPixel &n6, YUVPixel &n2, YUVPixel &n8, const YUVPixel pixel) const; template inline void LeftUp2_4X(YUVPixel &n15, YUVPixel &n14, YUVPixel &n11, YUVPixel &n13, YUVPixel &n12, YUVPixel &n10, YUVPixel &n7, YUVPixel &n3, const YUVPixel pixel) const; template inline void Left2_3X(YUVPixel &n7, YUVPixel &n5, YUVPixel &n6, YUVPixel &n8, const YUVPixel pixel) const; template inline void Left2_4X(YUVPixel &n15, YUVPixel &n14, YUVPixel &n11, YUVPixel &n13, YUVPixel &n12, YUVPixel &n10, const YUVPixel pixel) const; template inline void Up2_2X(YUVPixel &n3, YUVPixel &n1, YUVPixel pixel); template inline void Up2_3X(YUVPixel &n5, YUVPixel &n6, YUVPixel &n2, YUVPixel &n8, const YUVPixel pixel) const; template inline void Up2_4X(YUVPixel &n15, YUVPixel &n14, YUVPixel &n11, YUVPixel &n3, YUVPixel &n7, YUVPixel &n10, const YUVPixel pixel) const; template inline void Dia_2X(YUVPixel &n3, YUVPixel pixel); template inline void Dia_3X(YUVPixel &n8, YUVPixel &n5, YUVPixel &n7, const YUVPixel pixel) const; template inline void Dia_4X(YUVPixel &n15, YUVPixel &n14, YUVPixel &n11, const YUVPixel pixel) const; template inline void AlphaBlend32W(YUVPixel &dst, const YUVPixel src) const; template inline void AlphaBlend64W(YUVPixel &dst, const YUVPixel src) const; template inline void AlphaBlend128W(YUVPixel &dst, const YUVPixel src) const; template inline void AlphaBlend192W(YUVPixel &dst, const YUVPixel src) const; template inline void AlphaBlend224W(YUVPixel &dst, const YUVPixel src) const; inline YUVPixel& getPixel(dword col) const; //YUV cache. It works like this: //There's a 32KB lookup table where each index corresponds with a 15-bit //RGB color. This means one can convert a RGB color to YUV by making a //lookup in this table. // //For 32-bit RGB colors one have to reduce the color to 15-bit before //doing the lookup. // YUVPixel** _index; //Whenever to blend pixels or not. Unblended give a crisper but jagged image const bool _blend; //Execution path const Path path; }; } } } #endif nestopia-1.51.1/source/core/NstVideoRenderer.cpp000066400000000000000000000612331411157722000216040ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include #include "NstCore.hpp" #include "NstAssert.hpp" #include "NstFpuPrecision.hpp" #include "api/NstApiVideo.hpp" #include "NstVideoRenderer.hpp" #include "NstVideoFilterNone.hpp" #ifndef NO_NTSC #include "NstVideoFilterNtsc.hpp" #endif #ifndef NST_NO_SCALEX #include "NstVideoFilterScaleX.hpp" #endif #ifndef NST_NO_HQ2X #include "NstVideoFilterHqX.hpp" #endif #ifndef NST_NO_2XSAI #include "NstVideoFilter2xSaI.hpp" #endif #ifndef NST_NO_XBR #include "NstVideoFilterxBR.hpp" #endif namespace Nes { namespace Core { namespace Video { const byte Renderer::Palette::pc10Palette[64][3] = { {0x6D,0x6D,0x6D}, {0x00,0x24,0x92}, {0x00,0x00,0xDB}, {0x6D,0x49,0xDB}, {0x92,0x00,0x6D}, {0xB6,0x00,0x6D}, {0xB6,0x24,0x00}, {0x92,0x49,0x00}, {0x6D,0x49,0x00}, {0x24,0x49,0x00}, {0x00,0x6D,0x24}, {0x00,0x92,0x00}, {0x00,0x49,0x49}, {0x00,0x00,0x00}, {0x00,0x00,0x00}, {0x00,0x00,0x00}, {0xB6,0xB6,0xB6}, {0x00,0x6D,0xDB}, {0x00,0x49,0xFF}, {0x92,0x00,0xFF}, {0xB6,0x00,0xFF}, {0xFF,0x00,0x92}, {0xFF,0x00,0x00}, {0xDB,0x6D,0x00}, {0x92,0x6D,0x00}, {0x24,0x92,0x00}, {0x00,0x92,0x00}, {0x00,0xB6,0x6D}, {0x00,0x92,0x92}, {0x24,0x24,0x24}, {0x00,0x00,0x00}, {0x00,0x00,0x00}, {0xFF,0xFF,0xFF}, {0x6D,0xB6,0xFF}, {0x92,0x92,0xFF}, {0xDB,0x6D,0xFF}, {0xFF,0x00,0xFF}, {0xFF,0x6D,0xFF}, {0xFF,0x92,0x00}, {0xFF,0xB6,0x00}, {0xDB,0xDB,0x00}, {0x6D,0xDB,0x00}, {0x00,0xFF,0x00}, {0x49,0xFF,0xDB}, {0x00,0xFF,0xFF}, {0x49,0x49,0x49}, {0x00,0x00,0x00}, {0x00,0x00,0x00}, {0xFF,0xFF,0xFF}, {0xB6,0xDB,0xFF}, {0xDB,0xB6,0xFF}, {0xFF,0xB6,0xFF}, {0xFF,0x92,0xFF}, {0xFF,0xB6,0xB6}, {0xFF,0xDB,0x92}, {0xFF,0xFF,0x49}, {0xFF,0xFF,0x6D}, {0xB6,0xFF,0x49}, {0x92,0xFF,0x6D}, {0x49,0xFF,0xDB}, {0x92,0xDB,0xFF}, {0x92,0x92,0x92}, {0x00,0x00,0x00}, {0x00,0x00,0x00} }; const byte Renderer::Palette::vsPalette[4][64][3] = { { {0xFF,0xB6,0xB6}, {0xDB,0x6D,0xFF}, {0xFF,0x00,0x00}, {0x92,0x92,0xFF}, {0x00,0x92,0x92}, {0x24,0x49,0x00}, {0x49,0x49,0x49}, {0xFF,0x00,0x92}, {0xFF,0xFF,0xFF}, {0x6D,0x6D,0x6D}, {0xFF,0xB6,0x00}, {0xB6,0x00,0x6D}, {0x92,0x00,0x6D}, {0xDB,0xDB,0x00}, {0x6D,0x49,0x00}, {0xFF,0xFF,0xFF}, {0x6D,0xB6,0xFF}, {0xDB,0xB6,0x6D}, {0x6D,0x24,0x00}, {0x6D,0xDB,0x00}, {0x92,0xDB,0xFF}, {0xDB,0xB6,0xFF}, {0xFF,0xDB,0x92}, {0x00,0x49,0xFF}, {0xFF,0xDB,0x00}, {0x49,0xFF,0xDB}, {0x00,0x00,0x00}, {0x49,0x00,0x00}, {0xDB,0xDB,0xDB}, {0x92,0x92,0x92}, {0xFF,0x00,0xFF}, {0x00,0x24,0x92}, {0x00,0x00,0x6D}, {0xB6,0xDB,0xFF}, {0xFF,0xB6,0xFF}, {0x00,0xFF,0x00}, {0x00,0xFF,0xFF}, {0x00,0x49,0x49}, {0x00,0xB6,0x6D}, {0xB6,0x00,0xFF}, {0x00,0x00,0x00}, {0x92,0x49,0x00}, {0xFF,0x92,0xFF}, {0xB6,0x24,0x00}, {0x92,0x00,0xFF}, {0x00,0x00,0xDB}, {0xFF,0x92,0x00}, {0x00,0x00,0x00}, {0x00,0x00,0x00}, {0x24,0x92,0x00}, {0xB6,0xB6,0xB6}, {0x00,0x6D,0x24}, {0xB6,0xFF,0x49}, {0x6D,0x49,0xDB}, {0xFF,0xFF,0x00}, {0xDB,0x6D,0x00}, {0x00,0x49,0x00}, {0x00,0x6D,0xDB}, {0x00,0x92,0x00}, {0x24,0x24,0x24}, {0xFF,0xFF,0x6D}, {0xFF,0x6D,0xFF}, {0x92,0x6D,0x00}, {0x92,0xFF,0x6D} }, { {0x00,0x00,0x00}, {0xFF,0xB6,0x00}, {0x92,0x6D,0x00}, {0xB6,0xFF,0x49}, {0x92,0xFF,0x6D}, {0xFF,0x6D,0xFF}, {0x00,0x92,0x92}, {0xB6,0xDB,0xFF}, {0xFF,0x00,0x00}, {0x92,0x00,0xFF}, {0xFF,0xFF,0x6D}, {0xFF,0x92,0xFF}, {0xFF,0xFF,0xFF}, {0xDB,0x6D,0xFF}, {0x92,0xDB,0xFF}, {0x00,0x92,0x00}, {0x00,0x49,0x00}, {0x6D,0xB6,0xFF}, {0xB6,0x24,0x00}, {0xDB,0xDB,0xDB}, {0x00,0xB6,0x6D}, {0x6D,0xDB,0x00}, {0x49,0x00,0x00}, {0x92,0x92,0xFF}, {0x49,0x49,0x49}, {0xFF,0x00,0xFF}, {0x00,0x00,0x6D}, {0x49,0xFF,0xDB}, {0xDB,0xB6,0xFF}, {0x6D,0x49,0x00}, {0x00,0x00,0x00}, {0x6D,0x49,0xDB}, {0x92,0x00,0x6D}, {0xFF,0xDB,0x92}, {0xFF,0x92,0x00}, {0xFF,0xB6,0xFF}, {0x00,0x6D,0xDB}, {0x6D,0x24,0x00}, {0xB6,0xB6,0xB6}, {0x00,0x00,0xDB}, {0xB6,0x00,0xFF}, {0xFF,0xDB,0x00}, {0x6D,0x6D,0x6D}, {0x24,0x49,0x00}, {0x00,0x49,0xFF}, {0x00,0x00,0x00}, {0xDB,0xDB,0x00}, {0xFF,0xFF,0xFF}, {0xDB,0xB6,0x6D}, {0x24,0x24,0x24}, {0x00,0xFF,0x00}, {0xDB,0x6D,0x00}, {0x00,0x49,0x49}, {0x00,0x24,0x92}, {0xFF,0x00,0x92}, {0x24,0x92,0x00}, {0x00,0x00,0x00}, {0x00,0xFF,0xFF}, {0x92,0x49,0x00}, {0xFF,0xFF,0x00}, {0xFF,0xB6,0xB6}, {0xB6,0x00,0x6D}, {0x00,0x6D,0x24}, {0x92,0x92,0x92} }, { {0xB6,0x00,0xFF}, {0xFF,0x6D,0xFF}, {0x92,0xFF,0x6D}, {0xB6,0xB6,0xB6}, {0x00,0x92,0x00}, {0xFF,0xFF,0xFF}, {0xB6,0xDB,0xFF}, {0x24,0x49,0x00}, {0x00,0x24,0x92}, {0x00,0x00,0x00}, {0xFF,0xDB,0x92}, {0x6D,0x49,0x00}, {0xFF,0x00,0x92}, {0xDB,0xDB,0xDB}, {0xDB,0xB6,0x6D}, {0x92,0xDB,0xFF}, {0x92,0x92,0xFF}, {0x00,0x92,0x92}, {0xB6,0x00,0x6D}, {0x00,0x49,0xFF}, {0x24,0x92,0x00}, {0x92,0x6D,0x00}, {0xDB,0x6D,0x00}, {0x00,0xB6,0x6D}, {0x6D,0x6D,0x6D}, {0x6D,0x49,0xDB}, {0x00,0x00,0x00}, {0x00,0x00,0xDB}, {0xFF,0x00,0x00}, {0xB6,0x24,0x00}, {0xFF,0x92,0xFF}, {0xFF,0xB6,0xB6}, {0xDB,0x6D,0xFF}, {0x00,0x49,0x00}, {0x00,0x00,0x6D}, {0xFF,0xFF,0x00}, {0x24,0x24,0x24}, {0xFF,0xB6,0x00}, {0xFF,0x92,0x00}, {0xFF,0xFF,0xFF}, {0x6D,0xDB,0x00}, {0x92,0x00,0x6D}, {0x6D,0xB6,0xFF}, {0xFF,0x00,0xFF}, {0x00,0x6D,0xDB}, {0x92,0x92,0x92}, {0x00,0x00,0x00}, {0x6D,0x24,0x00}, {0x00,0xFF,0xFF}, {0x49,0x00,0x00}, {0xB6,0xFF,0x49}, {0xFF,0xB6,0xFF}, {0x92,0x49,0x00}, {0x00,0xFF,0x00}, {0xDB,0xDB,0x00}, {0x49,0x49,0x49}, {0x00,0x6D,0x24}, {0x00,0x00,0x00}, {0xDB,0xB6,0xFF}, {0xFF,0xFF,0x6D}, {0x92,0x00,0xFF}, {0x49,0xFF,0xDB}, {0xFF,0xDB,0x00}, {0x00,0x49,0x49} }, { {0x92,0x6D,0x00}, {0x6D,0x49,0xDB}, {0x00,0x92,0x92}, {0xDB,0xDB,0x00}, {0x00,0x00,0x00}, {0xFF,0xB6,0xB6}, {0x00,0x24,0x92}, {0xDB,0x6D,0x00}, {0xB6,0xB6,0xB6}, {0x6D,0x24,0x00}, {0x00,0xFF,0x00}, {0x00,0x00,0x6D}, {0xFF,0xDB,0x92}, {0xFF,0xFF,0x00}, {0x00,0x92,0x00}, {0xB6,0xFF,0x49}, {0xFF,0x6D,0xFF}, {0x49,0x00,0x00}, {0x00,0x49,0xFF}, {0xFF,0x92,0xFF}, {0x00,0x00,0x00}, {0x49,0x49,0x49}, {0xB6,0x24,0x00}, {0xFF,0x92,0x00}, {0xDB,0xB6,0x6D}, {0x00,0xB6,0x6D}, {0x92,0x92,0xFF}, {0x24,0x92,0x00}, {0x92,0x00,0x6D}, {0x00,0x00,0x00}, {0x92,0xFF,0x6D}, {0x6D,0xB6,0xFF}, {0xB6,0x00,0x6D}, {0x00,0x6D,0x24}, {0x92,0x49,0x00}, {0x00,0x00,0xDB}, {0x92,0x00,0xFF}, {0xB6,0x00,0xFF}, {0x6D,0x6D,0x6D}, {0xFF,0x00,0x92}, {0x00,0x49,0x49}, {0xDB,0xDB,0xDB}, {0x00,0x6D,0xDB}, {0x00,0x49,0x00}, {0x24,0x24,0x24}, {0xFF,0xFF,0x6D}, {0x92,0x92,0x92}, {0xFF,0x00,0xFF}, {0xFF,0xB6,0xFF}, {0xFF,0xFF,0xFF}, {0x6D,0x49,0x00}, {0xFF,0x00,0x00}, {0xFF,0xDB,0x00}, {0x49,0xFF,0xDB}, {0xFF,0xFF,0xFF}, {0x92,0xDB,0xFF}, {0x00,0x00,0x00}, {0xFF,0xB6,0x00}, {0xDB,0x6D,0xFF}, {0xB6,0xDB,0xFF}, {0x6D,0xDB,0x00}, {0xDB,0xB6,0xFF}, {0x00,0xFF,0xFF}, {0x24,0x49,0x00} } }; const double Renderer::Palette::Constants::pi = 3.141592653589793; const double Renderer::Palette::Constants::deg = 0.017453292519943296; const double Renderer::Palette::Constants::levels[2][4] = { {-0.12, 0.00, 0.31, 0.72 }, { 0.40, 0.68, 1.00, 1.00 } }; #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif inline Renderer::Palette::Custom::Custom() : emphasis(NULL) {} inline Renderer::Palette::Custom::~Custom() { delete [] emphasis; } bool Renderer::Palette::Custom::EnableEmphasis(bool enable) { if (!enable) { delete [] emphasis; emphasis = NULL; } else if (!emphasis) { emphasis = new (std::nothrow) byte [7][64][3]; } return bool(emphasis) == enable; } Renderer::Palette::Palette() : type(PALETTE_YUV), custom(NULL) { } Renderer::Palette::~Palette() { delete custom; } Result Renderer::Palette::SetDecoder(const Decoder& d) { if (decoder == d) return RESULT_NOP; for (uint i=0; i < 3; ++i) { if (d.axes[i].angle >= 360 || d.axes[i].gain > 2.0) return RESULT_ERR_INVALID_PARAM; } decoder = d; return RESULT_OK; } void Renderer::Palette::Store(const double (&src)[3],byte (&dst)[3]) { for (uint i=0; i < 3; ++i) dst[i] = Clamp<0,255>( src[i] * 255 + 0.5 ); } Result Renderer::Palette::LoadCustom(const byte (*colors)[3],const bool emphasis) { if (!colors) return RESULT_ERR_INVALID_PARAM; if ((custom == NULL && NULL == (custom = new (std::nothrow) Custom)) || !custom->EnableEmphasis( emphasis )) return RESULT_ERR_OUT_OF_MEMORY; std::memcpy( custom->palette, colors, 64*3 ); if (emphasis) std::memcpy( custom->emphasis, colors + 64, 7*64*3 ); return RESULT_OK; } uint Renderer::Palette::SaveCustom(byte (*colors)[3],const bool emphasis) const { if (!colors) return 0; std::memcpy( colors, custom ? custom->palette : pc10Palette, 64*3 ); if (!emphasis || !custom || !custom->emphasis) return 64; std::memcpy( colors + 64, custom->emphasis, 7*64*3 ); return 7*64; } bool Renderer::Palette::ResetCustom() { if (custom) { custom->EnableEmphasis( false ); std::memcpy( custom->palette, pc10Palette, 64*3 ); return true; } return false; } Result Renderer::Palette::SetType(PaletteType t) { if (t == type) return RESULT_NOP; if (t == PALETTE_CUSTOM && !custom) { if (NULL == (custom = new (std::nothrow) Custom)) return RESULT_ERR_OUT_OF_MEMORY; ResetCustom(); } type = t; return RESULT_OK; } void Renderer::Palette::GenerateEmphasis(uint tint,double s,double& y,double& i,double& q) { if (tint == 7) { y = y * (0.79399 * 1.13) - (0.0782838 * 1.13); } else { s = s * (0.5 - 0.79399 * 0.5) + 0.0782838 * 0.5; y -= s * 0.5; if (tint >= 3 && tint != 4) { s *= 0.6; y -= s; } static const byte tints[8] = { 0, 6, 10, 8, 2, 4, 0, 0 }; const double a = Constants::pi / 12 * (tints[tint] * 2 - 7); i += std::sin( a ) * s; q += std::cos( a ) * s; } } void Renderer::Palette::Build(const int bi,const int si,const int ci,const int hue) { NST_ASSERT( type != PALETTE_YUV ); const double brightness = bi / 200.0; const double saturation = (si + 100) / 100.0; const double contrast = (ci + 100) / 100.0; const double matrix[6] = { std::sin( (90 - 33 - hue) * Constants::deg ) * (0.570 * 2), std::cos( (90 - 33 - hue) * Constants::deg ) * (0.570 * 2), std::sin( (236 - 33 - hue) * Constants::deg ) * (0.351 * 2), std::cos( (236 - 33 - hue) * Constants::deg ) * (0.351 * 2), std::sin( (0 - 33 - hue) * Constants::deg ) * (1.015 * 2), std::cos( (0 - 33 - hue) * Constants::deg ) * (1.015 * 2) }; const byte (*from)[3] = ( type == PALETTE_CUSTOM ? custom->palette : type == PALETTE_VS1 ? vsPalette[0] : type == PALETTE_VS2 ? vsPalette[1] : type == PALETTE_VS3 ? vsPalette[2] : type == PALETTE_VS4 ? vsPalette[3] : pc10Palette ); NST_ASSERT( from ); for (uint i=0; i < 8; ++i) { if (i && type == PALETTE_CUSTOM && custom->emphasis) from = custom->emphasis[i-1]; for (uint j=0; j < 64; ++j) { double rgb[3] = { from[j][0] / 255.0, from[j][1] / 255.0, from[j][2] / 255.0 }; if (i && type != PALETTE_CUSTOM) { switch (i) { case 1: rgb[0] = 1; break; case 2: rgb[1] = 1; break; case 3: rgb[0] = 1; rgb[1] = 1; break; case 4: rgb[2] = 1; break; case 5: rgb[0] = 1; rgb[2] = 1; break; case 6: rgb[1] = 1; rgb[2] = 1; break; case 7: rgb[0] = 1; rgb[1] = 1; rgb[2] = 1; break; } } double yiq[3] = { 0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2], 0.596 * rgb[0] - 0.275 * rgb[1] - 0.321 * rgb[2], 0.212 * rgb[0] - 0.523 * rgb[1] + 0.311 * rgb[2] }; if (i && type == PALETTE_CUSTOM && !custom->emphasis && (j & 0xF) <= 0xD) GenerateEmphasis( i, Constants::levels[(j & 0xF) != 0xD][j >> 4 & 0x3], yiq[0], yiq[1], yiq[2] ); yiq[0] = yiq[0] * contrast + brightness; yiq[1] *= saturation; yiq[2] *= saturation; for (uint k=0; k < 3; ++k) rgb[k] = yiq[0] + matrix[k*2+0] * yiq[1] + matrix[k*2+1] * yiq[2]; Store( rgb, palette[(i * 64) + j] ); } } } void Renderer::Palette::Generate(const int b,const int s,const int c,int hue) { NST_ASSERT( type == PALETTE_YUV ); const double brightness = b / 200.0; const double saturation = (s + 100) / 100.0; const double contrast = (c + 100) / 100.0; hue += 33; const double matrix[6] = { std::sin( (int(decoder.axes[0].angle) - hue) * Constants::deg ) * decoder.axes[0].gain * 2, std::cos( (int(decoder.axes[0].angle) - hue) * Constants::deg ) * decoder.axes[0].gain * 2, std::sin( (int(decoder.axes[1].angle) - hue) * Constants::deg ) * decoder.axes[1].gain * 2, std::cos( (int(decoder.axes[1].angle) - hue) * Constants::deg ) * decoder.axes[1].gain * 2, std::sin( (int(decoder.axes[2].angle) - hue) * Constants::deg ) * decoder.axes[2].gain * 2, std::cos( (int(decoder.axes[2].angle) - hue) * Constants::deg ) * decoder.axes[2].gain * 2 }; for (uint n=0; n < PALETTE; ++n) { double level[2] = { Constants::levels[0][n >> 4 & 3], Constants::levels[1][n >> 4 & 3] }; const int color = n & 0x0F; if (color == 0x00) { level[0] = level[1]; } else if (color == 0x0D) { level[1] = level[0]; } else if (color > 0x0D) { level[0] = 0; level[1] = 0; } double y = (level[1] + level[0]) * 0.5; double s = (level[1] - level[0]) * 0.5; double h = Constants::pi / 6 * (color - 3); double i = std::sin( h ) * s; double q = std::cos( h ) * s; const uint tint = n >> 6 & 7; if (tint && color <= 0x0D) GenerateEmphasis( tint, level[1], y, i, q ); if (decoder.boostYellow) { const double yellowness = i - q; if (yellowness > DBL_EPSILON) { i = i + yellowness * ((n >> 4 & 3) / 4.0); q = q - yellowness * ((n >> 4 & 3) / 4.0); } } i *= saturation; q *= saturation; y = y * contrast + brightness; const double rgb[3] = { y + matrix[0] * i + matrix[1] * q, y + matrix[2] * i + matrix[3] * q, y + matrix[4] * i + matrix[5] * q }; Store( rgb, palette[n] ); } } void Renderer::Palette::Update(int brightness,int saturation,int contrast,int hue) { FpuPrecision precision; (*this.*(type == PALETTE_YUV ? &Palette::Generate : &Palette::Build))( brightness, saturation, contrast, hue ); } inline const Renderer::PaletteEntries& Renderer::Palette::Get() const { return palette; } Renderer::Filter::Format::Format(const RenderState& state) : bpp(state.bits.count) { for (uint i=0; i < 3; ++i) { ulong mask = (i == 0 ? state.bits.mask.r : i == 1 ? state.bits.mask.g : state.bits.mask.b); shifts[i] = 0; if (mask) { while (!(mask & 0x1)) { mask >>= 1; shifts[i]++; } } masks[i] = mask; } } Renderer::Filter::Filter(const RenderState& state) : format(state) {} void Renderer::Filter::Transform(const byte (&src)[PALETTE][3],Input::Palette& dst) const { for (uint i=0; i < PALETTE; ++i) { dst[i] = ( ((src[i][0] * format.masks[0] + 0x7F) / 0xFF) << format.shifts[0] | ((src[i][1] * format.masks[1] + 0x7F) / 0xFF) << format.shifts[1] | ((src[i][2] * format.masks[2] + 0x7F) / 0xFF) << format.shifts[2] ); } } Renderer::State::State() : width (0), height (0), filter (RenderState::FILTER_NONE), update (UPDATE_PALETTE), fieldMerging (0), brightness (0), saturation (0), hue (0), contrast (0), sharpness (0), resolution (0), bleed (0), artifacts (0), fringing (0), blendPixels (1), xbr_corner_rounding(0) { mask.r = 0; mask.g = 0; mask.b = 0; } Renderer::Renderer() : filter(NULL) {} Renderer::~Renderer() { delete filter; } Result Renderer::SetState(const RenderState& renderState) { if (filter) { if ( state.filter == renderState.filter && state.width == renderState.width && state.height == renderState.height && filter->format.bpp == renderState.bits.count && state.mask.r == renderState.bits.mask.r && state.mask.g == renderState.bits.mask.g && state.mask.b == renderState.bits.mask.b ) return RESULT_NOP; delete filter; filter = NULL; } try { switch (renderState.filter) { case RenderState::FILTER_NONE: if (FilterNone::Check( renderState )) filter = new FilterNone( renderState ); break; #ifndef NST_NO_SCALEX case RenderState::FILTER_SCALE2X: case RenderState::FILTER_SCALE3X: if (FilterScaleX::Check( renderState )) filter = new FilterScaleX( renderState ); break; #endif #ifndef NST_NO_HQ2X case RenderState::FILTER_HQ2X: case RenderState::FILTER_HQ3X: case RenderState::FILTER_HQ4X: if (FilterHqX::Check( renderState )) filter = new FilterHqX( renderState ); break; #endif #ifndef NST_NO_2XSAI case RenderState::FILTER_2XSAI: if (Filter2xSaI::Check( renderState )) filter = new Filter2xSaI( renderState ); break; #endif #ifndef NO_NTSC case RenderState::FILTER_NTSC: if (FilterNtsc::Check( renderState )) { filter = new FilterNtsc ( renderState, GetPalette(), state.sharpness, state.resolution, state.bleed, state.artifacts, state.fringing, state.fieldMerging ); } break; #endif #ifndef NST_NO_XBR case RenderState::FILTER_2XBR: case RenderState::FILTER_3XBR: case RenderState::FILTER_4XBR: if (FilterxBR::Check( renderState )) filter = new FilterxBR( renderState, state.blendPixels, state.xbr_corner_rounding ); break; #endif } } catch (const std::bad_alloc&) { delete filter; filter = NULL; return RESULT_ERR_OUT_OF_MEMORY; } if (filter) { state.filter = renderState.filter; state.width = renderState.width; state.height = renderState.height; state.mask = renderState.bits.mask; if (state.filter == RenderState::FILTER_NTSC) state.update = 0; else state.update |= uint(State::UPDATE_FILTER); return RESULT_OK; } else { return RESULT_ERR_UNSUPPORTED; } } Result Renderer::GetState(RenderState& output) const { if (filter) { output.filter = static_cast(state.filter); output.width = state.width; output.height = state.height; output.bits.count = filter->format.bpp; output.bits.mask = state.mask; return RESULT_OK; } return RESULT_ERR_NOT_READY; } void Renderer::EnableFieldMerging(bool fieldMerging) { const bool old = state.fieldMerging; state.fieldMerging &= uint(State::FIELD_MERGING_FORCED); if (fieldMerging) state.fieldMerging |= uint(State::FIELD_MERGING_USER); if (bool(state.fieldMerging) != old) state.update |= uint(State::UPDATE_NTSC); } void Renderer::EnableForcedFieldMerging(bool fieldMerging) { const bool old = state.fieldMerging; state.fieldMerging &= uint(State::FIELD_MERGING_USER); if (fieldMerging) state.fieldMerging |= uint(State::FIELD_MERGING_FORCED); if (bool(state.fieldMerging) != old) state.update |= uint(State::UPDATE_NTSC); } Result Renderer::SetHue(int hue) { if (hue < -45 || hue > 45) return RESULT_ERR_INVALID_PARAM; if (state.hue == hue) return RESULT_NOP; state.hue = hue; state.update |= uint(State::UPDATE_PALETTE|State::UPDATE_FILTER); return RESULT_OK; } Result Renderer::SetLevel(schar& type,int value,uint update) { if (value < -100 || value > 100) return RESULT_ERR_INVALID_PARAM; if (type == value) return RESULT_NOP; type = value; state.update |= update; return RESULT_OK; } Result Renderer::SetDecoder(const Decoder& decoder) { const Result result = palette.SetDecoder( decoder ); if (NES_SUCCEEDED(result) && result != RESULT_NOP && palette.GetType() == PALETTE_YUV) state.update |= uint(State::UPDATE_PALETTE|State::UPDATE_FILTER); return result; } Result Renderer::SetPaletteType(PaletteType type) { const Result result = palette.SetType( type ); if (NES_SUCCEEDED(result) && result != RESULT_NOP) state.update |= uint(State::UPDATE_PALETTE|State::UPDATE_FILTER); return result; } Result Renderer::LoadCustomPalette(const byte (*colors)[3],const bool emphasis) { const Result result = palette.LoadCustom( colors, emphasis ); if (NES_SUCCEEDED(result) && result != RESULT_NOP && palette.GetType() == PALETTE_CUSTOM) state.update |= uint(State::UPDATE_PALETTE|State::UPDATE_FILTER); return result; } void Renderer::ResetCustomPalette() { if (palette.ResetCustom() && palette.GetType() == PALETTE_CUSTOM) state.update |= uint(State::UPDATE_PALETTE|State::UPDATE_FILTER); } const Renderer::PaletteEntries& Renderer::GetPalette() { if (state.update & uint(State::UPDATE_PALETTE)) { state.update &= ~uint(State::UPDATE_PALETTE); palette.Update( state.brightness, state.saturation, state.contrast, state.hue ); } return palette.Get(); } void Renderer::UpdateFilter(Input& input) { NST_VERIFY( state.update ); if (state.filter == RenderState::FILTER_NTSC || state.update == 1) { RenderState renderState; GetState( renderState ); delete filter; filter = NULL; SetState( renderState ); } else if (state.update & uint(State::UPDATE_FILTER)) { filter->Transform( GetPalette(), input.palette ); } state.update = 0; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Renderer::Blit(Output& output,Input& input,uint burstPhase) { if (filter) { if (state.update) UpdateFilter( input ); if (Output::lockCallback( output )) { NST_VERIFY( std::labs(output.pitch) >= dword(state.width) << (filter->format.bpp / 16) ); filter->bgColor = bgColor; if (std::labs(output.pitch) >= dword(state.width) << (filter->format.bpp / 16)) filter->Blit( input, output, burstPhase ); Output::unlockCallback( output ); } } } } } } nestopia-1.51.1/source/core/NstVideoRenderer.hpp000066400000000000000000000203511411157722000216050ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_VIDEO_RENDERER_H #define NST_VIDEO_RENDERER_H #include #include "api/NstApiVideo.hpp" #include "NstVideoScreen.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Video { class Renderer { typedef Api::Video::RenderState RenderState; typedef Api::Video::Decoder Decoder; typedef Screen Input; public: Renderer(); ~Renderer(); enum PaletteType { PALETTE_YUV, PALETTE_PC10, PALETTE_VS1, PALETTE_VS2, PALETTE_VS3, PALETTE_VS4, PALETTE_CUSTOM }; enum { WIDTH = Input::WIDTH, HEIGHT = Input::HEIGHT, PIXELS = Input::PIXELS, PALETTE = Input::PALETTE, DEFAULT_PALETTE = PALETTE_YUV }; Result SetState(const RenderState&); Result GetState(RenderState&) const; Result SetHue(int); void Blit(Output&,Input&,uint); Result SetDecoder(const Decoder&); Result SetPaletteType(PaletteType); Result LoadCustomPalette(const byte (*)[3],bool); void ResetCustomPalette(); void EnableFieldMerging(bool); void EnableForcedFieldMerging(bool); typedef byte PaletteEntries[PALETTE][3]; const PaletteEntries& GetPalette(); private: void UpdateFilter(Input&); class Palette { public: Palette(); ~Palette(); Result SetType(PaletteType); Result LoadCustom(const byte (*)[3],bool); uint SaveCustom(byte (*)[3],bool) const; bool ResetCustom(); void Update(int,int,int,int); Result SetDecoder(const Decoder&); inline const PaletteEntries& Get() const; private: struct Constants { static const double pi; static const double deg; static const double levels[2][4]; }; struct Custom { inline Custom(); inline ~Custom(); bool EnableEmphasis(bool); byte palette[64][3]; byte (*emphasis)[64][3]; }; void Generate(int,int,int,int); void Build(int,int,int,int); static void GenerateEmphasis(uint,double,double&,double&,double&); static void Store(const double (&)[3],byte (&)[3]); PaletteType type; Custom* custom; Decoder decoder; byte palette[64*8][3]; static const byte pc10Palette[64][3]; static const byte vsPalette[4][64][3]; public: PaletteType GetType() const { return type; } const Decoder& GetDecoder() const { return decoder; } bool HasCustomEmphasis() const { return custom && custom->emphasis; } }; class FilterNone; class FilterNtsc; #ifndef NST_NO_SCALEX class FilterScaleX; #endif #ifndef NST_NO_HQ2X class FilterHqX; #endif #ifndef NST_NO_2XSAI class Filter2xSaI; #endif #ifndef NST_NO_XBR class FilterxBR; #endif class NST_NO_VTABLE Filter { struct Format { explicit Format(const RenderState&); dword masks[3]; byte shifts[3]; const byte bpp; }; protected: explicit Filter(const RenderState&); public: virtual ~Filter() {} virtual void Blit(const Input&,const Output&,uint) = 0; virtual void Transform(const byte (&)[PALETTE][3],Input::Palette&) const; const Format format; uint bgColor; }; struct State { State(); enum { UPDATE_PALETTE = 0x1, UPDATE_FILTER = 0x2, UPDATE_NTSC = 0x4, UPDATE_FILTER_STATE = 0x8, FIELD_MERGING_USER = 0x1, FIELD_MERGING_FORCED = 0x2 }; word width; word height; byte filter; byte update; byte fieldMerging; schar brightness; schar saturation; schar hue; schar contrast; schar sharpness; schar resolution; schar bleed; schar artifacts; schar fringing; schar blendPixels; schar xbr_corner_rounding; RenderState::Bits::Mask mask; }; Result SetLevel(schar&,int,uint=State::UPDATE_PALETTE|State::UPDATE_FILTER); Filter* filter; State state; Palette palette; public: uint bgColor; Result SetBrightness(int brightness) { return SetLevel( state.brightness, brightness ); } Result SetSaturation(int saturation) { return SetLevel( state.saturation, saturation ); } Result SetContrast(int contrast) { return SetLevel( state.contrast, contrast ); } Result SetSharpness(int sharpness) { return SetLevel( state.sharpness, sharpness, State::UPDATE_NTSC ); } Result SetColorResolution(int resolution) { return SetLevel( state.resolution, resolution, State::UPDATE_NTSC ); } Result SetColorBleed(int bleed) { return SetLevel( state.bleed, bleed, State::UPDATE_NTSC ); } Result SetColorArtifacts(int artifacts) { return SetLevel( state.artifacts, artifacts, State::UPDATE_NTSC ); } Result SetColorFringing(int fringing) { return SetLevel( state.fringing, fringing, State::UPDATE_NTSC ); } Result SetBlend(bool correct) { return SetLevel( state.blendPixels, correct, State::UPDATE_FILTER_STATE ); } Result SetCornerRounding(int mode) { return SetLevel( state.xbr_corner_rounding, mode, State::UPDATE_FILTER_STATE ); } /** * Workaround for black screen issue if this flag is set while the emulator is loading settings */ void ClearFilterUpdateFlag() { //state.update ^= State::UPDATE_FILTER_STATE; state.update = 1; } int GetBlend() const { return state.blendPixels; } int GetCornerRounding() const { return state.xbr_corner_rounding; } int GetBrightness() const { return state.brightness; } int GetSaturation() const { return state.saturation; } int GetContrast() const { return state.contrast; } int GetSharpness() const { return state.sharpness; } int GetColorResolution() const { return state.resolution; } int GetColorBleed() const { return state.bleed; } int GetColorArtifacts() const { return state.artifacts; } int GetColorFringing() const { return state.fringing; } int GetHue() const { return state.hue; } bool IsFieldMergingEnabled() const { return state.fieldMerging & uint(State::FIELD_MERGING_USER); } PaletteType GetPaletteType() const { return palette.GetType(); } bool HasCustomPaletteEmphasis() const { return palette.HasCustomEmphasis(); } uint SaveCustomPalette(byte (*colors)[3],bool emphasis) const { return palette.SaveCustom( colors, emphasis ); } const Decoder& GetDecoder() const { return palette.GetDecoder(); } bool IsReady() const { return filter; } }; } } } #endif nestopia-1.51.1/source/core/NstVideoScreen.cpp000066400000000000000000000030351411157722000212510ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstCore.hpp" #include "NstVideoScreen.hpp" namespace Nes { namespace Core { namespace Video { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Screen::Screen() { std::fill( palette, palette + sizeof(array(palette)), dword(0) ); Clear(); } void Screen::Clear() { std::fill( pixels, pixels + sizeof(array(pixels)), Pixel(0) ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } } nestopia-1.51.1/source/core/NstVideoScreen.hpp000066400000000000000000000030651411157722000212610ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_VIDEO_SCREEN_H #define NST_VIDEO_SCREEN_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Video { struct Screen { Screen(); void Clear(); enum { WIDTH = 256, HEIGHT = 240, PIXELS = uint(WIDTH) * HEIGHT, PIXELS_PADDING = 8, PALETTE = 64 * 8 }; typedef word Pixel; typedef dword Palette[PALETTE]; Palette palette; Pixel pixels[uint(PIXELS)+PIXELS_PADDING]; }; } } } #endif nestopia-1.51.1/source/core/NstXml.cpp000066400000000000000000000611711411157722000176100ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include "NstStream.hpp" #include "NstVector.hpp" #include "NstXml.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Xml::Xml() : root(NULL) {} Xml::~Xml() { Destroy(); } void Xml::Destroy() { delete root; root = NULL; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif Xml::Format::Format() : tab (" "), newline ("\r\n"), valueDelimiter (""), xmlHeader (true), byteOrderMark (true) { } inline int Xml::ToChar(idword ch) { return CHAR_MAX < 0xFF && ch > CHAR_MAX ? ch - (CHAR_MAX-CHAR_MIN+1) : ch; } inline wchar_t Xml::ToWideChar(idword ch) { return WCHAR_MAX < 0xFFFF && ch > WCHAR_MAX ? ch - (WCHAR_MAX-WCHAR_MIN+1) : ch; } byte* Xml::Input::Init(std::istream& stdStream,dword& size) { byte* data = NULL; try { Stream::In stream( &stdStream ); size = stream.Length(); data = new byte [size + 4]; stream.Read( data, size ); std::memset( data + size, 0, 4 ); } catch (...) { if (data) delete [] data; throw; } return data; } Xml::Input::Input(std::istream& s,dword t) : stream(Init(s,t)), size(t), pos(0) {} Xml::Input::~Input() { delete [] stream; } inline dword Xml::Input::Size() const { return size; } inline uint Xml::Input::ToByte(dword i) const { NST_ASSERT( i < size+4 ); return stream[i]; } inline int Xml::Input::ToChar(dword i) const { NST_ASSERT( i < size+4 ); return Xml::ToChar(stream[i]); } inline uint Xml::Input::FromUTF16BE(dword i) const { return ToByte(i+1) | ToByte(i+0) << 8; } inline uint Xml::Input::FromUTF16LE(dword i) const { return ToByte(i+0) | ToByte(i+1) << 8; } inline void Xml::Input::SetReadPointer(dword p) { NST_ASSERT( p <= size ); pos = p; } uint Xml::Input::ReadUTF8() { NST_ASSERT( pos <= size ); if (uint v = ToByte(pos)) { pos++; if (v & 0x80) { const uint w = ToByte(pos++); if ((v & 0xE0) == 0xC0) { if ((w & 0xC0) != 0x80) throw 1; v = (v << 6 & 0x7C0) | (w & 0x03F); } else if ((v & 0xF0) == 0xE0) { const uint z = ToByte(pos++); if ((w & 0xC0) == 0x80) { if ((z & 0xC0) != 0x80) throw 1; v = (v << 12 & 0xF000) | (w << 6 & 0x0FC0) | (z & 0x03F); } } else { throw 1; } } return v; } return 0; } Xml::Output::Output(std::ostream& s,const Format& f) : stream(s), format(f) {} inline Xml::Output::Type::Type(wcstring s) : string(s) {} inline Xml::Output::Value::Value(wcstring s) : string(s) {} void Xml::Output::Write(cstring s,uint n) const { stream.write( s, n ); } const Xml::Output& Xml::Output::operator << (char c) const { stream.put( c ); return *this; } const Xml::Output& Xml::Output::operator << (byte c) const { return *this << char(Xml::ToChar(c)); } const Xml::Output& Xml::Output::operator << (wchar_t c) const { const unsigned long int v = ((long)WCHAR_MIN < 0 ? (c + ((long)WCHAR_MAX-(long)WCHAR_MIN+1)) & 0xFFFFU : c); if (v < 0x80) { *this << byte( v ); } else if (v < 0x800) { *this << byte( 0xC0 | (v >> 6 & 0x1F) ); *this << byte( 0x80 | (v >> 0 & 0x3F) ); } else { *this << byte( 0xE0 | (v >> 12 & 0x0F) ); *this << byte( 0x80 | (v >> 6 & 0x3F) ); *this << byte( 0x80 | (v >> 0 & 0x3F) ); } return *this; } const Xml::Output& Xml::Output::operator << (Type type) const { while (const wchar_t c = *type.string++) (*this) << c; return *this; } const Xml::Output& Xml::Output::operator << (Value value) const { while (const wchar_t c = *value.string++) { switch (c) { case L'&': (*this) << "&"; break; case L'<': (*this) << "<"; break; case L'>': (*this) << ">"; break; case L'\'': (*this) << "'"; break; case L'\"': (*this) << """; break; default: (*this) << c; break; } } return *this; } inline const Xml::Output& Xml::Output::operator << (cstring s) const { while (const char c = *s++) (*this) << c; return *this; } template inline const Xml::Output& Xml::Output::operator << (const char (&s)[N]) const { Write( s, N-1 ); return *this; } Xml::Node Xml::Read(std::istream& stream) { Destroy(); Vector buffer; try { Input input( stream ); if (input.ToByte(0) == 0xFE && input.ToByte(1) == 0xFF) { buffer.Resize( input.Size() / 2 ); for (dword i=0, n=buffer.Size(); i < n; ++i) buffer[i] = input.FromUTF16BE( 2 + i * 2 ); } else if (input.ToByte(0) == 0xFF && input.ToByte(1) == 0xFE) { buffer.Resize( input.Size() / 2 ); for (dword i=0, n=buffer.Size(); i < n; ++i) buffer[i] = input.FromUTF16LE( 2 + i * 2 ); } else { bool utf8 = (input.ToByte(0) == 0xEF && input.ToByte(1) == 0xBB && input.ToByte(2) == 0xBF); if (utf8) { input.SetReadPointer(3); } else if (input.ToChar(0) == '<' && input.ToChar(1) == '?') { for (uint i=2; i < 128 && input.ToChar(i) && input.ToChar(i) != '>'; ++i) { if ( (input.ToChar( i+0 ) == 'U' || input.ToChar( i+0 ) == 'u') && (input.ToChar( i+1 ) == 'T' || input.ToChar( i+1 ) == 't') && (input.ToChar( i+2 ) == 'F' || input.ToChar( i+2 ) == 'f') && (input.ToChar( i+3 ) == '-' && input.ToChar( i+4 ) == '8') ) { utf8 = true; break; } } } if (utf8) { buffer.Reserve( input.Size() ); uint v; do { v = input.ReadUTF8(); buffer.Append( v ); } while (v); } else { buffer.Resize( input.Size() + 1 ); for (dword i=0, n=buffer.Size(); i < n; ++i) buffer[i] = input.ToByte( i ); } } } catch (...) { Destroy(); return NULL; } return Read( buffer.Begin() ); } Xml::Node Xml::Create(wcstring type) { Destroy(); if (type) { try { root = new BaseNode( type, type + std::wcslen(type), BaseNode::OUT ); } catch (...) { Destroy(); } } return root; } Xml::Node Xml::Read(utfstring file) { Destroy(); if (file) { try { for (utfstring stream = SkipVoid( file ); *stream; ) { switch (const Tag tag = CheckTag( stream )) { case TAG_XML: if (stream != file) throw 1; case TAG_COMMENT: case TAG_INSTRUCTION: stream = ReadTag( stream, root ); break; case TAG_OPEN: case TAG_OPEN_CLOSE: if (!root) { stream = ReadNode( stream, tag, root ); break; } default: throw 1; } } } catch (...) { Destroy(); } } return root; } void Xml::Write(const Node node,std::ostream& stream,const Format& format) const { if (node) { const Output output( stream, format ); if (format.byteOrderMark) output << byte(0xEF) << byte(0xBB) << byte(0xBF); if (format.xmlHeader) output << "" << format.newline; WriteNode( node, output, 0 ); } } void Xml::WriteNode(const Node node,const Output& output,const uint level) { for (uint i=level; i; --i) output << output.format.tab; output << '<' << Output::Type(node.GetType()); for (Attribute attribute(node.GetFirstAttribute()); attribute; attribute = attribute.GetNext()) { output << ' ' << Output::Type(attribute.GetType()) << "=\"" << Output::Value(attribute.GetValue()) << '\"'; } if (node.HasChildren() || *node.GetValue()) { output << '>'; if (*node.GetValue()) { output << output.format.valueDelimiter << Output::Value(node.GetValue()) << output.format.valueDelimiter; } if (node.HasChildren()) { output << output.format.newline; for (Node child(node.GetFirstChild()); child; child=child.GetNextSibling()) WriteNode( child, output, level+1 ); for (uint i=level; i; --i) output << output.format.tab; } output << "'; } else { output << " />"; } output << output.format.newline; } Xml::utfstring Xml::ReadNode(utfstring stream,Tag tag,BaseNode*& node) { NST_ASSERT( node == NULL && tag != TAG_CLOSE ); stream = ReadTag( stream, node ); if (tag == TAG_OPEN) { for (BaseNode** next = &node->child;;) { if (*stream == '<') { tag = CheckTag( stream ); if (tag == TAG_CLOSE) break; stream = ReadNode( stream, tag, *next ); if (*next) next = &(*next)->sibling; } else { stream = ReadValue( stream, *node ); } } stream = ReadTag( stream, node ); } return stream; } Xml::utfstring Xml::ReadTag(utfstring stream,BaseNode*& node) { NST_ASSERT( *stream == '<' ); ++stream; if (*stream == '!') { if (stream[1] == '-' && stream[2] == '-') { for (stream += 3; *stream; ++stream) { if (stream[0] == '-' && stream[1] == '-' && stream[2] == '>') { stream += 2; break; } } } } else if (*stream == '?') { while (*++stream) { if (stream[0] == '?' && stream[1] == '>') { ++stream; break; } } } else if (node) { if (*stream++ != '/') throw 1; for (wcstring type=node->type; *stream; ++stream, ++type) { if (ToWideChar(*stream) != *type) { if (*type) throw 1; stream = SkipVoid( stream ); break; } } } else { for (utfstring const t=stream; *stream; ++stream) { if (*stream == '>' || *stream == '/' || IsVoid( *stream )) { node = new BaseNode( t, stream, BaseNode::IN ); break; } } for (;;++stream) { if (*stream == '>') { break; } else if (*stream == '/') { ++stream; break; } else if (!IsVoid( *stream )) { utfstring const t = stream; while (*stream && *stream != '=' && !IsVoid( *stream )) ++stream; utfstring const tn = stream; stream = SkipVoid( stream ); if (*stream++ != '=') throw 1; stream = SkipVoid( stream ); const utfchar enclosing = *stream++; if (enclosing != '\"' && enclosing != '\'') throw 1; stream = SkipVoid( stream ); utfstring const v = stream; while (*stream && *stream != enclosing) ++stream; if (*stream != enclosing) throw 1; node->AddAttribute( t, tn, v, RewindVoid(stream,v) ); } } } if (*stream++ != '>') throw 1; return SkipVoid( stream ); } Xml::utfstring Xml::ReadValue(utfstring stream,BaseNode& node) { NST_ASSERT( *stream != '<' && !IsVoid( *stream ) ); for (utfstring const value = stream; *stream; ++stream) { if (*stream == '<') { node.SetValue( value, RewindVoid(stream), BaseNode::IN ); break; } } return stream; } bool Xml::IsEqual(wcstring a,wcstring b) { do { if (*a != *b) return false; } while (++b, *a++); return true; } bool Xml::IsEqualNonCase(wcstring a,wcstring b) { do { if ( (*a >= L'A' && *a <= L'Z' ? L'a' + (*a - L'A') : *a) != (*b >= L'A' && *b <= L'Z' ? L'a' + (*b - L'A') : *b) ) return false; } while (++b, *a++); return true; } long Xml::ToSigned(wcstring string,uint base,wcstring* end) { NST_ASSERT( string ); long value = 0; if (*string) { wchar_t* endptr = NULL; value = std::wcstol( string, end ? &endptr : NULL, base ); if (end) *end = (endptr ? endptr : string); if (errno == ERANGE) value = 0; } return value; } ulong Xml::ToUnsigned(wcstring string,uint base,wcstring* end) { NST_ASSERT( string ); ulong value = 0; if (*string) { wchar_t* endptr = NULL; value = std::wcstoul( string, end ? &endptr : NULL, base ); if (end) *end = (endptr ? endptr : string); if (errno == ERANGE) value = 0; } return value; } bool Xml::IsVoid(utfchar ch) { switch (ch) { case ' ': case '\r': case '\n': case '\t': return true; } return false; } bool Xml::IsCtrl(utfchar ch) { switch (ch) { case '\0': case '\a': case '\b': case '\t': case '\v': case '\n': case '\r': case '\f': return true; } return false; } Xml::utfstring Xml::SkipVoid(utfstring stream) { while (IsVoid( *stream )) ++stream; return stream; } Xml::utfstring Xml::RewindVoid(utfstring stream,utfstring stop) { while (stream != stop && IsVoid( stream[-1] )) --stream; return stream; } Xml::Tag Xml::CheckTag(utfstring stream) { if (stream[0] == '<') { if (stream[1] == '/') return TAG_CLOSE; if ( stream[1] == '!' && stream[2] == '-' && stream[3] == '-' ) return TAG_COMMENT; if (stream[1] == '?') { if ( stream[2] == 'x' && stream[3] == 'm' && stream[4] == 'l' && IsVoid( stream[5] ) ) return TAG_XML; else return TAG_INSTRUCTION; } while (*++stream) { if (*stream == '\"' || *stream == '\'') { for (const utfchar enclosing = *stream; stream[1]; ) { if (*++stream == enclosing) break; } } else if (*stream == '>') { if (stream[-1] == '/') return TAG_OPEN_CLOSE; else return TAG_OPEN; } } } throw 1; } template Xml::BaseNode::BaseNode(T t,T n,U u) : type (SetType(new wchar_t [n-t+1],t,n,u)), value (L""), attribute (NULL), child (NULL), sibling (NULL) { if (!type) throw 1; } template Xml::BaseNode::Attribute::Attribute(T t,T tn,T v,T vn,U u) : type (SetType(new wchar_t [(tn-t)+1+(vn-v)+1],t,tn,u)), value (SetValue(const_cast(type+(tn-t)+1),v,vn,u)), next (NULL) { } Xml::BaseNode::Attribute::~Attribute() { delete [] type; delete next; } Xml::BaseNode::~BaseNode() { delete [] type; if (*value) delete [] value; delete attribute; delete child; if (BaseNode* node = sibling) { do { BaseNode* tmp = node->sibling; node->sibling = NULL; delete node; node = tmp; } while (node); } } template void Xml::BaseNode::SetValue(T v,T vn,U u) { if (vn-v) { if (!*value) value = SetValue( new wchar_t [vn-v+1], v, vn, u ); else throw 1; } } void Xml::BaseNode::AddAttribute(utfstring t,utfstring tn,utfstring v,utfstring vn) { if (tn-t) { Attribute** a = &attribute; while (*a) a = &(*a)->next; (*a) = new Attribute( t, tn, v, vn, BaseNode::IN ); } else if (vn-t) { throw 1; } } wchar_t* Xml::BaseNode::SetType(wchar_t* NST_RESTRICT dst,utfstring src,utfstring const end,In) { NST_ASSERT( dst && src && end ); wchar_t* const ptr = dst; while (src != end) { const utfchar ch = *src++; if (!IsCtrl( ch )) { *dst++ = ToWideChar( ch ); } else { delete [] ptr; return NULL; } } *dst = L'\0'; return ptr; } wchar_t* Xml::BaseNode::SetType(wchar_t* NST_RESTRICT dst,wcstring src,wcstring const end,Out) { NST_ASSERT( dst && src && end ); wchar_t* const ptr = dst; while (src != end) *dst++ = *src++; *dst = L'\0'; return ptr; } wchar_t* Xml::BaseNode::SetValue(wchar_t* NST_RESTRICT dst,utfstring src,utfstring const end,In) { NST_ASSERT( dst && src && end ); wchar_t* const ptr = dst; while (src != end) { utfchar ch = *src++; if (ch == '&') ch = ParseReference( src, end ); if (!IsCtrl( ch ) || IsVoid( ch )) { *dst++ = ToWideChar( ch ); } else { delete [] ptr; return NULL; } } *dst = L'\0'; return ptr; } wchar_t* Xml::BaseNode::SetValue(wchar_t* NST_RESTRICT dst,wcstring src,wcstring const end,Out) { NST_ASSERT( dst && src && end ); wchar_t* const ptr = dst; while (src != end) *dst++ = *src++; *dst = L'\0'; return ptr; } Xml::utfchar Xml::BaseNode::ParseReference(utfstring& string,utfstring const end) { utfstring src = string; if (end-src >= 3) { switch (*src++) { case '#': for (utfstring const offset = src++; src != end; ++src) { if (*src == ';') { string = src + 1; if (*offset == 'x') { for (dword ch=0, n=0; ; n += (n < 16 ? 4 : 0)) { const utfchar v = *--src; if (v >= '0' && v <= '9') { ch |= dword(v - '0') << n; } else if (v >= 'a' && v <= 'f') { ch |= dword(v - 'a' + 10) << n; } else if (v >= 'A' && v <= 'F') { ch |= dword(v - 'A' + 10) << n; } else { return src == offset && ch <= 0xFFFF ? ch : '\0'; } } } else { for (dword ch=0, n=1; ; n *= (n < 100000 ? 10 : 1)) { const utfchar v = *--src; if (v >= '0' && v <= '9') { ch += (v - '0') * n; } else { return src < offset && ch <= 0xFFFF ? ch : '\0'; } } } } } break; case 'a': if (*src == 'm') { if ( end-src >= 3 && src[1] == 'p' && src[2] == ';' ) { string = src + 3; return '&'; } } else if (*src == 'p') { if ( end-src >= 4 && src[1] == 'o' && src[2] == 's' && src[3] == ';' ) { string = src + 4; return '\''; } } break; case 'l': if ( src[0] == 't' && src[1] == ';' ) { string = src + 2; return '<'; } break; case 'g': if ( src[0] == 't' && src[1] == ';' ) { string = src + 2; return '>'; } break; case 'q': if ( end-src >= 4 && src[0] == 'u' && src[1] == 'o' && src[2] == 't' && src[3] == ';' ) { string = src + 4; return '\"'; } break; } } return '\0'; } dword Xml::Node::NumAttributes() const { dword n = 0; if (node) { for (const BaseNode::Attribute* attribute = node->attribute; attribute; attribute = attribute->next) ++n; } return n; } dword Xml::Node::NumChildren(wcstring type) const { dword n = 0; if (node) { for (const BaseNode* next = node->child; next; next = next->sibling) n += (!type || !*type || IsEqual( next->type, type )); } return n; } Xml::Attribute Xml::Node::GetAttribute(dword i) const { BaseNode::Attribute* next = NULL; if (node) { for (next = node->attribute; i && next; --i) next = next->next; } return next; } Xml::Attribute Xml::Node::GetAttribute(wcstring type) const { if (node) { if (!type) type = L""; for (BaseNode::Attribute* next = node->attribute; next; next = next->next) { if (IsEqual( next->type, type )) return next; } } return NULL; } Xml::Node Xml::Node::GetChild(dword i) const { BaseNode* next = node; if (next) { for (next = node->child; i && next; --i) next = next->sibling; } return next; } Xml::Node Xml::Node::GetChild(wcstring type) const { if (node) { if (!type) type = L""; for (BaseNode* next = node->child; next; next = next->sibling) { if (IsEqual( next->type, type )) return next; } } return NULL; } long Xml::Node::GetSignedValue(uint base) const { return ToSigned( GetValue(), base, NULL ); } long Xml::Node::GetSignedValue(wcstring& end,uint base) const { return ToSigned( GetValue(), base, &end ); } ulong Xml::Node::GetUnsignedValue(uint base) const { return ToUnsigned( GetValue(), base, NULL ); } ulong Xml::Node::GetUnsignedValue(wcstring& end,uint base) const { return ToUnsigned( GetValue(), base, &end ); } Xml::BaseNode* Xml::Node::Add(wcstring type,wcstring value,BaseNode** next) const { while (*next) next = &(*next)->sibling; *next = new BaseNode( type, type + std::wcslen(type), BaseNode::OUT ); if (value && *value) (*next)->SetValue( value, value + std::wcslen(value), BaseNode::OUT ); return *next; } Xml::Attribute Xml::Node::AddAttribute(wcstring type,wcstring value) { if (type && *type && node) { BaseNode::Attribute** next = &node->attribute; while (*next) next = &(*next)->next; *next = new BaseNode::Attribute ( type, type + std::wcslen(type), value ? value : L"", value ? value + std::wcslen(value) : NULL, BaseNode::OUT ); return *next; } return NULL; } Xml::Node Xml::Node::AddChild(wcstring type,wcstring value) { return (type && *type && node) ? Add( type, value, &node->child ) : NULL; } Xml::Node Xml::Node::AddSibling(wcstring type,wcstring value) { return (type && *type && node) ? Add( type, value, &node->sibling ) : NULL; } long Xml::Attribute::GetSignedValue(uint base) const { return ToSigned( GetValue(), base, NULL ); } long Xml::Attribute::GetSignedValue(wcstring& end,uint base) const { return ToSigned( GetValue(), base, &end ); } ulong Xml::Attribute::GetUnsignedValue(uint base) const { return ToUnsigned( GetValue(), base, NULL ); } ulong Xml::Attribute::GetUnsignedValue(wcstring& end,uint base) const { return ToUnsigned( GetValue(), base, &end ); } } } nestopia-1.51.1/source/core/NstXml.hpp000066400000000000000000000172421411157722000176150ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_XML_H #define NST_XML_H #include #include #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class Xml { typedef word utfchar; typedef const word* utfstring; static inline int ToChar(idword); static inline wchar_t ToWideChar(idword); class BaseNode { public: enum In {IN}; enum Out {OUT}; private: static utfchar ParseReference(utfstring&,utfstring); static wchar_t* SetType(wchar_t* NST_RESTRICT,utfstring,utfstring,In); static wchar_t* SetType(wchar_t* NST_RESTRICT,wcstring,wcstring,Out); static wchar_t* SetValue(wchar_t* NST_RESTRICT,utfstring,utfstring,In); static wchar_t* SetValue(wchar_t* NST_RESTRICT,wcstring,wcstring,Out); public: struct Attribute { template Attribute(T,T,T,T,U); ~Attribute(); wcstring const type; wcstring const value; Attribute* next; }; template BaseNode(T,T,U); ~BaseNode(); template void SetValue(T,T,U); void AddAttribute(utfstring,utfstring,utfstring,utfstring); wcstring const type; wcstring value; Attribute* attribute; BaseNode* child; BaseNode* sibling; }; static bool IsEqual(wcstring,wcstring); static bool IsEqualNonCase(wcstring,wcstring); static long ToSigned(wcstring,uint,wcstring*); static ulong ToUnsigned(wcstring,uint,wcstring*); public: Xml(); ~Xml(); class Node; class Attribute : public ImplicitBool { public: long GetSignedValue(uint=0) const; long GetSignedValue(wcstring&,uint=0) const; ulong GetUnsignedValue(uint=0) const; ulong GetUnsignedValue(wcstring&,uint=0) const; private: friend class Node; BaseNode::Attribute* attribute; Attribute(BaseNode::Attribute* a) : attribute(a) {} public: bool operator ! () const { return !attribute; } wcstring GetType() const { return attribute ? attribute->type : L""; } wcstring GetValue() const { return attribute ? attribute->value : L""; } Attribute GetNext() const { return attribute ? attribute->next : NULL; } bool IsType(wcstring type) const { return IsEqual( GetType(), type ? type : L"" ); } bool IsValue(wcstring value) const { return IsEqualNonCase( GetValue(), value ? value : L"" ); } }; class Node : public ImplicitBool { friend class Xml; public: dword NumChildren(wcstring=NULL) const; dword NumAttributes() const; Attribute GetAttribute(dword) const; Attribute GetAttribute(wcstring) const; Node GetChild(dword) const; Node GetChild(wcstring) const; Node AddChild(wcstring,wcstring=NULL); Node AddSibling(wcstring,wcstring=NULL); Attribute AddAttribute(wcstring,wcstring); long GetSignedValue(uint=0) const; long GetSignedValue(wcstring&,uint=0) const; ulong GetUnsignedValue(uint=0) const; ulong GetUnsignedValue(wcstring&,uint=0) const; private: BaseNode* Add(wcstring,wcstring,BaseNode**) const; BaseNode* node; Node(BaseNode* n) : node(n) {} public: Node() : node(NULL) {} bool operator ! () const { return !node; } bool HasChildren() const { return node && node->child; } bool HasNextSibling() const { return node && node->sibling; } bool HasAttributes() const { return node && node->attribute; } Attribute GetFirstAttribute() const { return node ? node->attribute : NULL; } Node GetFirstChild() const { return node ? node->child : NULL; } Node GetNextSibling() const { return node ? node->sibling : NULL; } wcstring GetType() const { return node ? node->type : L""; } wcstring GetValue() const { return node ? node->value : L""; } bool IsType(wcstring type) const { return IsEqual( GetType(), type ? type : L"" ); } bool IsValue(wcstring value) const { return IsEqualNonCase( GetValue(), value ? value : L"" ); } }; struct Format { Format(); cstring tab; cstring newline; cstring valueDelimiter; bool xmlHeader; bool byteOrderMark; }; Node Create(wcstring); Node Read(utfstring); Node Read(std::istream&); void Write(Node,std::ostream&,const Format& = Format()) const; void Destroy(); private: enum Tag { TAG_XML, TAG_COMMENT, TAG_INSTRUCTION, TAG_OPEN, TAG_OPEN_CLOSE, TAG_CLOSE }; class Input { static byte* Init(std::istream&,dword&); const byte* const stream; const dword size; dword pos; public: Input(std::istream&,dword=0); ~Input(); inline dword Size() const; inline uint ToByte(dword) const; inline int ToChar(dword) const; inline uint FromUTF16LE(dword) const; inline uint FromUTF16BE(dword) const; uint ReadUTF8(); inline void SetReadPointer(dword); }; class Output { std::ostream& stream; void Write(cstring,uint) const; public: const Format format; Output(std::ostream&,const Format&); class Type { friend class Output; wcstring string; public: inline Type(wcstring); }; class Value { friend class Output; wcstring string; public: inline Value(wcstring); }; const Output& operator << (char) const; const Output& operator << (wchar_t) const; const Output& operator << (byte) const; const Output& operator << (Type) const; const Output& operator << (Value) const; inline const Output& operator << (cstring) const; template inline const Output& operator << (const char (&)[N]) const; }; static bool IsVoid(utfchar); static bool IsCtrl(utfchar); static Tag CheckTag(utfstring); static utfstring SkipVoid(utfstring); static utfstring RewindVoid(utfstring,utfstring=NULL); static utfstring ReadTag(utfstring,BaseNode*&); static utfstring ReadValue(utfstring,BaseNode&); static utfstring ReadNode(utfstring,Tag,BaseNode*&); static void WriteNode(Node,const Output&,uint); BaseNode* root; public: Node GetRoot() const { return root; } }; } } #endif nestopia-1.51.1/source/core/NstZlib.cpp000066400000000000000000000044441411157722000177500ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstAssert.hpp" #include "NstZlib.hpp" #ifndef NST_NO_ZLIB #ifdef NST_WIN32 #if NST_MSVC >= 800 #define ZEXPORT __stdcall #else #define ZLIB_WINAPI #endif #endif #include "zlib.h" #endif namespace Nes { namespace Core { namespace Zlib { #ifndef NST_NO_ZLIB ulong NST_CALL Compress(const byte* src,ulong srcSize,byte* dst,ulong dstSize,Compression compression) { if (srcSize && dstSize) { NST_ASSERT( src && dst ); int result; if (compression == BEST_COMPRESSION) result = compress2( dst, &dstSize, src, srcSize, Z_BEST_COMPRESSION ); else result = compress( dst, &dstSize, src, srcSize ); if (result == Z_OK) return dstSize; } return 0; } ulong NST_CALL Uncompress(const byte* src,ulong srcSize,byte* dst,ulong dstSize) { if (srcSize && dstSize) { NST_ASSERT( src && dst ); if (uncompress( dst, &dstSize, src, srcSize ) == Z_OK) return dstSize; } return 0; } #else ulong NST_CALL Compress(const byte*,ulong,byte*,ulong,Compression) { return 0; } ulong NST_CALL Uncompress(const byte*,ulong,byte*,ulong) { return 0; } #endif } } } nestopia-1.51.1/source/core/NstZlib.hpp000066400000000000000000000030051411157722000177450ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_ZLIB_H #define NST_ZLIB_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Zlib { enum { #ifndef NST_NO_ZLIB AVAILABLE = 1 #else AVAILABLE = 0 #endif }; enum Compression { NORMAL_COMPRESSION, BEST_COMPRESSION }; ulong NST_CALL Compress(const byte*,ulong,byte*,ulong,Compression); ulong NST_CALL Uncompress(const byte*,ulong,byte*,ulong); } } } #endif nestopia-1.51.1/source/core/api/000077500000000000000000000000001411157722000164225ustar00rootroot00000000000000nestopia-1.51.1/source/core/api/NstApi.hpp000066400000000000000000000043461411157722000203400ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_API_H #define NST_API_H #ifndef NST_BASE_H #include "../NstBase.hpp" #endif #ifdef NST_PRAGMA_ONCE #pragma once #endif #ifndef NST_CALLBACK #define NST_CALLBACK NST_CALL #endif #if NST_MSVC >= 1200 #pragma warning( push ) #pragma warning( disable : 4512 ) #endif namespace Nes { namespace Core { class Machine; template class UserCallback : public ImplicitBool< UserCallback > { public: typedef void* UserData; typedef T Function; protected: Function function; UserData userdata; UserCallback() : function(0), userdata(0) {} public: void Set(Function f,UserData d) { function = f; userdata = d; } void Unset() { function = 0; userdata = 0; } void Get(Function& f,UserData& d) const { f = function; d = userdata; } bool operator ! () const { return !function; } }; } namespace Api { class Base { public: typedef void* UserData; protected: Core::Machine& emulator; Base(Core::Machine& e) : emulator(e) {} }; } } #if NST_MSVC >= 1200 #pragma warning( pop ) #endif #endif nestopia-1.51.1/source/core/api/NstApiBarcodeReader.cpp000066400000000000000000000067141411157722000227370ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include "../NstMachine.hpp" #include "../NstImage.hpp" #include "../NstBarcodeReader.hpp" #include "../input/NstInpDevice.hpp" #include "../input/NstInpBarcodeWorld.hpp" #include "NstApiInput.hpp" #include "NstApiBarcodeReader.hpp" namespace Nes { namespace Api { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Core::BarcodeReader* BarcodeReader::Query() const { if (emulator.image) { if (Core::Image::ExternalDevice device = emulator.image->QueryExternalDevice( Core::Image::EXT_BARCODE_READER )) { return static_cast(device); } else if (emulator.expPort->GetType() == Input::BARCODEWORLD) { return &static_cast(emulator.expPort)->GetReader(); } } return NULL; } uint BarcodeReader::Randomize(char (&string)[MAX_DIGITS+1]) const throw() { uint digits = 0; if (Core::BarcodeReader* const barcodeReader = Query()) { static uint extra = 0x1234; std::srand( std::time(NULL) + extra++ ); if (!barcodeReader->IsDigitsSupported( MIN_DIGITS )) { digits = MAX_DIGITS; } else if (barcodeReader->IsDigitsSupported( MAX_DIGITS ) && (std::rand() & 0x1U)) { digits = MAX_DIGITS; } else { digits = MIN_DIGITS; } uint sum = 0; for (uint i=0; i < digits-1; ++i) { const uint digit = uint(std::rand()) / (RAND_MAX / 10 + 1); string[i] = '0' + digit; sum += (i & 1) ? (digit * 3) : (digit * 1); } string[digits-1] = '0' + (10 - sum % 10) % 10; } string[digits] = '\0'; return digits; } bool BarcodeReader::IsDigitsSupported(uint count) const throw() { if (Core::BarcodeReader* const barcodeReader = Query()) return barcodeReader->IsDigitsSupported( count ); return false; } bool BarcodeReader::CanTransfer() const throw() { return !emulator.tracker.IsLocked() && Query(); } Result BarcodeReader::Transfer(const char* string,uint length) throw() { if (!emulator.tracker.IsLocked()) { if (Core::BarcodeReader* const barcodeReader = Query()) return emulator.tracker.TryResync( barcodeReader->Transfer( string, length ) ? RESULT_OK : RESULT_ERR_INVALID_PARAM ); } return RESULT_ERR_NOT_READY; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } nestopia-1.51.1/source/core/api/NstApiBarcodeReader.hpp000066400000000000000000000055241411157722000227420ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_API_BARCODEREADER_H #define NST_API_BARCODEREADER_H #include "NstApi.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif #if NST_ICC >= 810 #pragma warning( push ) #pragma warning( disable : 444 ) #elif NST_MSVC >= 1200 #pragma warning( push ) #pragma warning( disable : 4512 ) #endif namespace Nes { namespace Core { class BarcodeReader; } namespace Api { /** * Bar code reader interface. */ class BarcodeReader : public Base { Core::BarcodeReader* Query() const; public: /** * Interface constructor. * * @param instance emulator instance */ template BarcodeReader(T& instance) : Base(instance) {} enum { MIN_DIGITS = 8, MAX_DIGITS = 13 }; /** * Checks if the number of bar code digits is supported. * * @param length number of digits in the range 8 to 13 * @return true if supported */ bool IsDigitsSupported(uint length) const throw(); /** * Checks if the reader is ready to scan. * * @return true if ready */ bool CanTransfer() const throw(); /** * Generates a randomized bar code. * * @param string string to be filled * @return length of randomized bar code, 0 if reader is disconnected */ uint Randomize(char (&string)[MAX_DIGITS+1]) const throw(); /** * Transfers a bar code to the reader. * * @param string bar code string * @param length string length * @return result code */ Result Transfer(const char* string,uint length) throw(); /** * Checks if a reader is connected. * * @return true if connected */ bool IsConnected() const { return Query(); } }; } } #if NST_MSVC >= 1200 || NST_ICC >= 810 #pragma warning( pop ) #endif #endif nestopia-1.51.1/source/core/api/NstApiCartridge.cpp000066400000000000000000000327471411157722000221660ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "../NstMachine.hpp" #include "../NstStream.hpp" #include "../NstChecksum.hpp" #include "../NstCartridge.hpp" #include "../NstImageDatabase.hpp" #include "../NstCartridgeInes.hpp" #include "NstApiMachine.hpp" namespace Nes { namespace Api { Cartridge::ChooseProfileCaller Cartridge::chooseProfileCallback; #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Cartridge::Profile::Hash::Hash() throw() { Clear(); } Cartridge::Profile::Hash::Hash(const char* sha1,const char* crc) throw() { Assign( sha1, crc ); } Cartridge::Profile::Hash::Hash(const wchar_t* sha1,const wchar_t* crc) throw() { Assign( sha1, crc ); } Cartridge::Profile::Hash::Hash(const dword* sha1,dword crc) throw() { Assign( sha1, crc ); } void Cartridge::Profile::Hash::Clear() throw() { Assign( NULL, dword(0) ); } template bool Cartridge::Profile::Hash::Set(dword& dst,const T* NST_RESTRICT src) { dword v = 0; uint i = 32; do { i -= 4; const T c = *src++; if (c >= '0' && c <= '9') { v |= dword(c - '0') << i; } else if (c >= 'A' && c <= 'F') { v |= dword(c - 'A' + 0xA) << i; } else if (c >= 'a' && c <= 'f') { v |= dword(c - 'a' + 0xA) << i; } else { return false; } } while (i); dst = v; return true; } template void Cartridge::Profile::Hash::Import(const T* sha1,const T* crc) { Clear(); if (crc && *crc) Set( data[0], crc ); if (sha1 && *sha1) { for (uint i=1; i < 1+SHA1_WORD_LENGTH; ++i, sha1 += 8) { if (!Set( data[i], sha1 )) { for (uint j=1; j < i; ++j) data[j] = 0; break; } } } } void Cartridge::Profile::Hash::Assign(const char* sha1,const char* crc) throw() { Import( sha1, crc ); } void Cartridge::Profile::Hash::Assign(const wchar_t* sha1,const wchar_t* crc) throw() { Import( sha1, crc ); } void Cartridge::Profile::Hash::Assign(const dword* sha1,dword crc) throw() { data[0] = crc & 0xFFFFFFFF; for (uint i=0; i < SHA1_WORD_LENGTH; ++i) data[1+i] = (sha1 ? sha1[i] & 0xFFFFFFFF : 0); } void Cartridge::Profile::Hash::Get(char* sha1,char* crc) const throw() { if (crc) { for (dword v=data[0], j=32; j; ) { j -= 4; uint c = v >> j & 0xF; *crc++ = (c < 0xA ? '0' + c : 'A' + (c - 0xA) ); } } if (sha1) { for (uint i=1; i < 1+SHA1_WORD_LENGTH; ++i) { for (dword v=data[i], j=32; j; ) { j -= 4; uint c = v >> j & 0xF; *sha1++ = (c < 0xA ? '0' + c : 'A' + (c - 0xA) ); } } } } bool Cartridge::Profile::Hash::operator < (const Hash& c) const throw() { for (const dword *a=data, *b=c.data, *end=data+(1+SHA1_WORD_LENGTH); a != end; ++a, ++b) { if (*a < *b) return true; if (*a > *b) return false; } return false; } bool Cartridge::Profile::Hash::operator == (const Hash& c) const throw() { for (const dword *a=data, *b=c.data, *end=data+(1+SHA1_WORD_LENGTH); a != end; ++a, ++b) { if (*a != *b) return false; } return true; } bool Cartridge::Profile::Hash::operator ! () const throw() { for (uint i=0; i < 1+SHA1_WORD_LENGTH; ++i) { if (data[i]) return false; } return true; } void Cartridge::Profile::Hash::Compute(const void* mem,ulong size) throw() { const Core::Checksum checksum( static_cast(mem), size ); Assign( checksum.GetSha1(), checksum.GetCrc() ); } const dword* Cartridge::Profile::Hash::GetSha1() const throw() { return data+1; } dword Cartridge::Profile::Hash::GetCrc32() const throw() { return data[0]; } Cartridge::Profile::System::System() throw() : type(NES_NTSC), cpu(CPU_RP2A03), ppu(PPU_RP2C02) {} Cartridge::Profile::Dump::Dump() throw() : state(UNKNOWN) {} Cartridge::Profile::Game::Game() throw() : adapter(Input::ADAPTER_NES), players(0) { controllers[0] = Input::PAD1; controllers[1] = Input::PAD2; controllers[2] = Input::UNCONNECTED; controllers[3] = Input::UNCONNECTED; controllers[4] = Input::UNCONNECTED; } Cartridge::Profile::Board::Pin::Pin() throw() : number(0) {} Cartridge::Profile::Board::Sample::Sample() throw() : id(0) {} Cartridge::Profile::Board::Rom::Rom() throw() : id(0), size(0) {} Cartridge::Profile::Board::Ram::Ram() throw() : id(0), size(0), battery(false) {} Cartridge::Profile::Board::Chip::Chip() throw() : battery(false) {} Cartridge::Profile::Board::Board() throw() : solderPads(0), mapper(NO_MAPPER), subMapper(0) {} Cartridge::Profile::Board::~Board() throw() { } Cartridge::Profile::Profile() throw() : multiRegion(false), patched(false) { } Cartridge::Profile::~Profile() throw() { } template dword Cartridge::Profile::Board::GetComponentSize(const T& components) const { dword size = 0; for (typename T::const_iterator it(components.begin()), end(components.end()); it != end; ++it) size += it->size; return size; } dword Cartridge::Profile::Board::GetPrg() const throw() { return GetComponentSize( prg ); } dword Cartridge::Profile::Board::GetChr() const throw() { return GetComponentSize( chr ); } dword Cartridge::Profile::Board::GetWram() const throw() { return GetComponentSize( wram ); } dword Cartridge::Profile::Board::GetVram() const throw() { return GetComponentSize( vram ); } template bool Cartridge::Profile::Board::HasComponentBattery(const T& components) const { for (typename T::const_iterator it(components.begin()), end(components.end()); it != end; ++it) { if (it->battery) return true; } return false; } bool Cartridge::Profile::Board::HasWramBattery() const throw() { return HasComponentBattery( wram ); } bool Cartridge::Profile::Board::HasMmcBattery() const throw() { return HasComponentBattery( chips ); } bool Cartridge::Profile::Board::HasBattery() const throw() { return HasWramBattery() || HasMmcBattery(); } Cartridge::NesHeader::NesHeader() throw() { Clear(); } void Cartridge::NesHeader::Clear() throw() { system = SYSTEM_CONSOLE; region = REGION_NTSC; prgRom = 0; prgRam = 0; prgNvRam = 0; chrRom = 0; chrRam = 0; chrNvRam = 0; ppu = PPU_RP2C02; mirroring = MIRRORING_VERTICAL; mapper = 0; subMapper = 0; security = 0; version = 0; trainer = false; } Result Cartridge::NesHeader::Import(const void* const data,const ulong length) throw() { return Core::Cartridge::Ines::ReadHeader( *this, static_cast(data), length ); } Result Cartridge::NesHeader::Export(void* data,ulong length) const throw() { return Core::Cartridge::Ines::WriteHeader( *this, static_cast(data), length ); } bool Cartridge::Database::IsLoaded() const throw() { return emulator.imageDatabase; } bool Cartridge::Database::IsEnabled() const throw() { return emulator.imageDatabase && emulator.imageDatabase->Enabled(); } bool Cartridge::Database::Create() { if (emulator.imageDatabase == NULL) emulator.imageDatabase = new (std::nothrow) Core::ImageDatabase; return emulator.imageDatabase; } Result Cartridge::Database::Load(std::istream& stream) throw() { return Create() ? emulator.imageDatabase->Load( stream ) : RESULT_ERR_OUT_OF_MEMORY; } Result Cartridge::Database::Load(std::istream& baseStream,std::istream& overloadStream) throw() { return Create() ? emulator.imageDatabase->Load( baseStream, overloadStream ) : RESULT_ERR_OUT_OF_MEMORY; } void Cartridge::Database::Unload() throw() { if (emulator.imageDatabase) emulator.imageDatabase->Unload(); } Result Cartridge::Database::Enable(bool state) throw() { if (Create()) { if (emulator.imageDatabase->Enabled() != state) { emulator.imageDatabase->Enable( state ); return RESULT_OK; } return RESULT_NOP; } return RESULT_ERR_OUT_OF_MEMORY; } Result Cartridge::ReadRomset(std::istream& stream,Machine::FavoredSystem system,bool askProfile,Profile& profile) throw() { try { Core::Cartridge::ReadRomset( stream, static_cast(system), askProfile, profile ); } catch (Result result) { return result; } catch (...) { return RESULT_ERR_GENERIC; } return RESULT_OK; } Result Cartridge::ReadInes(std::istream& stream,Machine::FavoredSystem system,Profile& profile) throw() { try { Core::Cartridge::ReadInes( stream, static_cast(system), profile ); } catch (Result result) { return result; } catch (...) { return RESULT_ERR_GENERIC; } return RESULT_OK; } Result Cartridge::ReadUnif(std::istream& stream,Machine::FavoredSystem system,Profile& profile) throw() { try { Core::Cartridge::ReadUnif( stream, static_cast(system), profile ); } catch (Result result) { return result; } catch (...) { return RESULT_ERR_GENERIC; } return RESULT_OK; } const Cartridge::Profile* Cartridge::GetProfile() const throw() { if (emulator.Is(Machine::CARTRIDGE)) return &static_cast(emulator.image)->GetProfile(); return NULL; } Cartridge::Database::Entry Cartridge::Database::FindEntry(const Profile::Hash& hash,Machine::FavoredSystem system) const throw() { return emulator.imageDatabase ? emulator.imageDatabase->Search( hash, static_cast(system) ).Reference() : NULL; } Cartridge::Database::Entry Cartridge::Database::FindEntry(const void* file,ulong length,Machine::FavoredSystem system) const throw() { if (emulator.imageDatabase) { Profile::Hash hash; hash.Compute( file, length ); return emulator.imageDatabase->Search( hash, static_cast(system) ).Reference(); } else { return NULL; } } Result Cartridge::Database::Entry::GetProfile(Profile& profile) const throw() { Core::ImageDatabase::Entry entry(ref); if (!entry) return RESULT_ERR_NOT_READY; try { entry.Fill(profile); } catch (const std::bad_alloc&) { return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { return RESULT_ERR_GENERIC; } return RESULT_OK; } const wchar_t* Cartridge::Database::Entry::GetTitle() const throw() { return Core::ImageDatabase::Entry(ref).GetTitle(); } const Cartridge::Profile::Hash* Cartridge::Database::Entry::GetHash() const throw() { return Core::ImageDatabase::Entry(ref).GetHash(); } const wchar_t* Cartridge::Database::Entry::GetRegion() const throw() { return Core::ImageDatabase::Entry(ref).GetRegion(); } Cartridge::Profile::System::Type Cartridge::Database::Entry::GetSystem() const throw() { return Core::ImageDatabase::Entry(ref).GetSystem(); } bool Cartridge::Database::Entry::IsMultiRegion() const throw() { return Core::ImageDatabase::Entry(ref).IsMultiRegion(); } dword Cartridge::Database::Entry::GetPrgRom() const throw() { return Core::ImageDatabase::Entry(ref).GetPrg(); } dword Cartridge::Database::Entry::GetChrRom() const throw() { return Core::ImageDatabase::Entry(ref).GetChr(); } uint Cartridge::Database::Entry::GetWram() const throw() { return Core::ImageDatabase::Entry(ref).GetWram(); } uint Cartridge::Database::Entry::GetVram() const throw() { return Core::ImageDatabase::Entry(ref).GetVram(); } bool Cartridge::Database::Entry::HasBattery() const throw() { return Core::ImageDatabase::Entry(ref).HasBattery(); } uint Cartridge::Database::Entry::GetMapper() const throw() { return Core::ImageDatabase::Entry(ref).GetMapper(); } Cartridge::Profile::Dump::State Cartridge::Database::Entry::GetDumpState() const throw() { return Core::ImageDatabase::Entry(ref).GetDumpState(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } nestopia-1.51.1/source/core/api/NstApiCartridge.hpp000066400000000000000000000660001411157722000221600ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_API_CARTRIDGE_H #define NST_API_CARTRIDGE_H #include #include #include #include "NstApiInput.hpp" #include "NstApiMachine.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif #if NST_MSVC >= 1200 #pragma warning( push ) #pragma warning( disable : 4512 ) #endif namespace Nes { namespace Api { /** * Cartridge interface. */ class Cartridge : public Base { struct ChooseProfileCaller; public: /** * Interface constructor. * * @param instance emulator instance */ template Cartridge(T& instance) : Base(instance) {} /** * Cartridge profile context. **/ struct Profile { Profile() throw(); ~Profile() throw(); /** * Hash checksum. * * Stores SHA-1 and CRC-32 combined or just one of the two. */ class Hash : public Core::ImplicitBool { public: enum { SHA1_LENGTH = 40, SHA1_WORD_LENGTH = SHA1_LENGTH / 8, CRC32_LENGTH = 8, CRC32_WORD_LENGTH = CRC32_LENGTH / 8 }; /** * Default constructor. */ Hash() throw(); /** * Constructs new checksum from null-terminated strings. * * @param sha SHA-1 string, set to NULL if values shouldn't be used * @param crc CRC-32 string, set to NULL if value shouldn't be used */ Hash(const char* sha,const char* crc) throw(); /** * Constructs new checksum from null-terminated wide-strings. * * @param sha SHA-1 string, set to NULL if values shouldn't be used * @param crc CRC-32 string, set to NULL if value shouldn't be used */ Hash(const wchar_t* sha,const wchar_t* crc) throw(); /** * Constructs new checksum from input values. * * @param sha SHA-1 value, set to NULL if values shouldn't be used * @param crc CRC-32 value, set to 0 if value shouldn't be used */ Hash(const dword* sha,dword crc) throw(); /** * Tests for less-than. * * @param hash hash to compare with * @return true if input hash is less than this */ bool operator < (const Hash& hash) const throw(); /** * Tests for equality. * * @param hash hash to compare with * @return true if hashes are equal */ bool operator == (const Hash& hash) const throw(); /** * Checks if checksum is cleared. * * @return true if cleared */ bool operator ! () const throw(); /** * Computes and updates checksum from input. * * @param mem pointer to memory * @param length length of memory in bytes */ void Compute(const void* mem,ulong length) throw(); /** * Assigns new checksum from null-terminated strings. * * @param sha SHA-1 string, set to NULL if values shouldn't be used * @param crc CRC-32 string, set to NULL if value shouldn't be used */ void Assign(const char* sha,const char* crc) throw(); /** * Assigns new checksum from null-terminated wide-strings. * * @param sha SHA-1 string, set to NULL if values shouldn't be used * @param crc CRC-32 string, set to NULL if value shouldn't be used */ void Assign(const wchar_t* sha,const wchar_t* crc) throw(); /** * Assigns new checksum from input values. * * @param sha SHA-1 value, set to NULL if values shouldn't be used * @param crc CRC-32 value, set to 0 if value shouldn't be used */ void Assign(const dword* sha,dword crc) throw(); /** * Returns the current checksum. * * @param sha SHA-1 string to be filled, set to to NULL if not needed * @param crc CRC-32 string to be filled, set to NULL if not needed */ void Get(char* sha,char* crc) const throw(); /** * Clears the current checksum. */ void Clear() throw(); /** * Returns the current SHA-1 values. * * @return SHA-1 values, zero-filled if unused */ const dword* GetSha1() const throw(); /** * Returns the current CRC-32 value. * * @return CRC-32 value, 0 if unused */ dword GetCrc32() const throw(); private: template void Import(const T*,const T*); template static bool Set(dword&,const T* NST_RESTRICT); dword data[CRC32_WORD_LENGTH+SHA1_WORD_LENGTH]; }; /** * Game context. */ struct Game { Game() throw(); /** * Game title. */ std::wstring title; /** * Alternative game title. */ std::wstring altTitle; /** * Class. */ std::wstring clss; /** * Sub-class. */ std::wstring subClss; /** * Catalog. */ std::wstring catalog; /** * Publisher. */ std::wstring publisher; /** * Developer. */ std::wstring developer; /** * Port Developer. */ std::wstring portDeveloper; /** * Region. */ std::wstring region; /** * Revision. */ std::wstring revision; /** * Utilized controller adapter. */ Input::Adapter adapter; /** * Utilized controllers. */ Input::Type controllers[5]; /** * Number of players. */ uint players; }; /** * Dump context. */ struct Dump { Dump() throw(); /** * Dump state type. */ enum State { /** * Good dump. */ OK, /** * Bad dump. */ BAD, /** * Unknown dump. */ UNKNOWN }; /** * Dumped by. */ std::wstring by; /** * Dump date. */ std::wstring date; /** * Dump state. */ State state; }; /** * System context. */ struct System { System() throw(); /** * System Type. */ enum Type { /** * NES NTSC console. */ NES_NTSC = Core::SYSTEM_NES_NTSC, /** * NES PAL console. */ NES_PAL = Core::SYSTEM_NES_PAL, /** * NES PAL-A console. */ NES_PAL_A = Core::SYSTEM_NES_PAL_A, /** * NES PAL-B console. */ NES_PAL_B = Core::SYSTEM_NES_PAL_B, /** * Famicom console. */ FAMICOM = Core::SYSTEM_FAMICOM, /** * Dendy console (clone). */ DENDY = Core::SYSTEM_DENDY, /** * Vs UniSystem arcade. */ VS_UNISYSTEM = Core::SYSTEM_VS_UNISYSTEM, /** * Vs DualSystem arcade. */ VS_DUALSYSTEM = Core::SYSTEM_VS_DUALSYSTEM, /** * PlayChoice-10 arcade. */ PLAYCHOICE_10 = Core::SYSTEM_PLAYCHOICE_10 }; /** * CPU type. */ enum Cpu { /** * RP2A03 NTSC CPU. */ CPU_RP2A03 = Core::CPU_RP2A03, /** * RP2A07 PAL CPU. */ CPU_RP2A07 = Core::CPU_RP2A07, /** * Dendy CPU (clone). */ CPU_DENDY = Core::CPU_DENDY }; /** * PPU type. */ enum Ppu { /** * RP2C02 NTSC PPU. */ PPU_RP2C02 = Core::PPU_RP2C02, /** * RP2C03B RGB PPU. */ PPU_RP2C03B = Core::PPU_RP2C03B, /** * RP2C03G RGB PPU. */ PPU_RP2C03G = Core::PPU_RP2C03G, /** * RP2C04-0001 RGB PPU. */ PPU_RP2C04_0001 = Core::PPU_RP2C04_0001, /** * RP2C04-0002 RGB PPU. */ PPU_RP2C04_0002 = Core::PPU_RP2C04_0002, /** * RP2C04-0003 RGB PPU. */ PPU_RP2C04_0003 = Core::PPU_RP2C04_0003, /** * RP2C04-0004 RGB PPU. */ PPU_RP2C04_0004 = Core::PPU_RP2C04_0004, /** * RC2C03B RGB PPU. */ PPU_RC2C03B = Core::PPU_RC2C03B, /** * RC2C03C RGB PPU. */ PPU_RC2C03C = Core::PPU_RC2C03C, /** * RC2C05-01 RGB PPU. */ PPU_RC2C05_01 = Core::PPU_RC2C05_01, /** * RC2C05-02 RGB PPU. */ PPU_RC2C05_02 = Core::PPU_RC2C05_02, /** * RC2C05-03 RGB PPU. */ PPU_RC2C05_03 = Core::PPU_RC2C05_03, /** * RC2C05-04 RGB PPU. */ PPU_RC2C05_04 = Core::PPU_RC2C05_04, /** * RC2C05-05 RGB PPU. */ PPU_RC2C05_05 = Core::PPU_RC2C05_05, /** * RP2C07 PAL PPU. */ PPU_RP2C07 = Core::PPU_RP2C07, /** * Dendy PPU (clone). */ PPU_DENDY = Core::PPU_DENDY }; /** * System type. */ Type type; /** * CPU type. */ Cpu cpu; /** * PPU type. */ Ppu ppu; }; /** * Cartridge property. */ struct Property { /** * Name. */ std::wstring name; /** * Value. */ std::wstring value; }; /** * Cartridge properties. */ typedef std::vector Properties; /** * Board context. */ class Board { template dword GetComponentSize(const T&) const; template bool HasComponentBattery(const T&) const; public: Board() throw(); ~Board() throw(); /** * Returns total size of PRG-ROM. * * @return size */ dword GetPrg() const throw(); /** * Returns total size of CHR-ROM. * * @return size */ dword GetChr() const throw(); /** * Returns total size of W-RAM. * * @return size */ dword GetWram() const throw(); /** * Returns total size of V-RAM. * * @return size */ dword GetVram() const throw(); /** * Returns battery status. * * @return true if a battery is present */ bool HasBattery() const throw(); /** * Returns W-RAM battery status. * * @return true if a battery is present and connected to W-RAM */ bool HasWramBattery() const throw(); /** * Returns custom chip battery status. * * @return true if a battery is present and connected to a custom chip */ bool HasMmcBattery() const throw(); enum { SOLDERPAD_H = 0x1, SOLDERPAD_V = 0x2, NO_MAPPER = 0xFFFF }; /** * Pin context. */ struct Pin { Pin() throw(); /** * Pin number. */ uint number; /** * Pin function. */ std::wstring function; }; /** * Pins. */ typedef std::vector Pins; /** * Analogue sound sample context. */ struct Sample { Sample() throw(); /** * Sound sample id. */ uint id; /** * Sound sample file. */ std::wstring file; }; /** * Analogue sound samples. */ typedef std::vector Samples; /** * ROM chip. */ struct Rom { Rom() throw(); /** * ROM chip ID. */ dword id; /** * ROM chip size. */ dword size; /** * ROM chip name. */ std::wstring name; /** * File pointing to ROM chip. */ std::wstring file; /** * ROM chip package method. */ std::wstring package; /** * ROM chip pins. */ Pins pins; /** * ROM chip checksum. */ Hash hash; }; /** * RAM chip. */ struct Ram { Ram() throw(); /** * RAM chip ID. */ dword id; /** * RAM chip size. */ dword size; /** * File pointing to RAM chip. */ std::wstring file; /** * RAM chip package method. */ std::wstring package; /** * RAM chip pins. */ Pins pins; /** * Battery connected to RAM chip. */ bool battery; }; /** * Custom chip. */ struct Chip { Chip() throw(); /** * Custom chip type. */ std::wstring type; /** * File pointing to custom chip. */ std::wstring file; /** * Custom chip package type. */ std::wstring package; /** * Custom chip pins. */ Pins pins; /** * Analogue sound samples for custom chip. */ Samples samples; /** * battery connected to custom chip. */ bool battery; }; /** * ROM chips. */ typedef std::vector Roms; /** * RAM chips. */ typedef std::vector Rams; /** * Custom chips. */ typedef std::vector Chips; /** * PRG-ROM chips. */ typedef Roms Prg; /** * CHR-ROM chips. */ typedef Roms Chr; /** * W-RAM chips. */ typedef Rams Wram; /** * V-RAM chips. */ typedef Rams Vram; /** * Board type. */ std::wstring type; /** * CIC type. */ std::wstring cic; /** * Board PCB name. */ std::wstring pcb; /** * PRG-ROM. */ Prg prg; /** * CHR-ROM. */ Chr chr; /** * W-RAM. */ Wram wram; /** * V-RAM. */ Vram vram; /** * Custom chips. */ Chips chips; /** * Solder pads. */ uint solderPads; /** * Mapper ID. */ uint mapper; /** * Submapper ID. */ uint subMapper; /** * CHR RAM Size. */ uint chrRam; }; /** * Hash of ROM chips combined. */ Hash hash; /** * Dump context. */ Dump dump; /** * Game context. */ Game game; /** * System context. */ System system; /** * Board context. */ Board board; /** * Properties. */ Properties properties; /** * Multi-region game. */ bool multiRegion; /** * Soft-patching state. */ bool patched; }; /** * Database interface */ class Database { Core::Machine& emulator; bool Create(); public: /** * Interface constructor. * * @param instance emulator instance */ Database(Core::Machine& instance) : emulator(instance) {} /** * Database entry. */ class Entry : public Core::ImplicitBool { public: /** * Returns the profile of this entry. * * @param profile object to be filled * @return result code */ Result GetProfile(Profile& profile) const throw(); /** * Returns the game title. * * @return game title or empty string on invalid entry */ const wchar_t* GetTitle() const throw(); /** * Returns the target region. * * @return target region or empty string on invalid entry */ const wchar_t* GetRegion() const throw(); /** * Returns the target system. * * @return target system */ Profile::System::Type GetSystem() const throw(); /** * Checks if the game targets multiple regions. * * @return true if targeting multiple regions */ bool IsMultiRegion () const throw(); /** * Returns hash code of ROM chips combined. * * @return hash code or NULL on invalid entry */ const Profile::Hash* GetHash() const throw(); /** * Returns total size of PRG-ROM. * * @return size or 0 on invalid entry */ dword GetPrgRom() const throw(); /** * Returns total size of CHR-ROM. * * @return size or 0 on invalid entry */ dword GetChrRom() const throw(); /** * Returns total size of W-RAM. * * @return size or 0 on invalid entry */ uint GetWram() const throw(); /** * Returns total size of V-RAM. * * @return size or 0 on invalid entry */ uint GetVram() const throw(); /** * Returns mapper ID. * * @return mapper ID or 0 on invalid entry */ uint GetMapper() const throw(); /** * Returns battery status. * * @return true if a battery is present */ bool HasBattery() const throw(); /** * Returns the dump state. * * @return dump state */ Profile::Dump::State GetDumpState() const throw(); private: friend class Database; const void* ref; Entry(const void* r) : ref(r) {} public: /** * Default constructor. */ Entry() : ref(NULL) {} /** * Checks if entry is invalid. * * @return true if invalid */ bool operator ! () const { return !ref; } }; /** * Resets and loads internal XML database. * * @param stream input stream * @return result code */ Result Load(std::istream& stream) throw(); /** * Resets and loads internal and external XML databases. * * @param streamInternal input stream to internal XML database * @param streamExternal input stream to external XML database * @return result code */ Result Load(std::istream& streamInternal,std::istream& streamExternal) throw(); /** * Removes all databases from the system. */ void Unload() throw(); /** * Enables image corrections. * * @param state true to enable, default is true * @return result code */ Result Enable(bool state=true) throw(); /** * Checks if image corrections are enabled. * * @return true if enabled */ bool IsEnabled() const throw(); /** * Checks if any database has been loaded into the system. * * @return true if loaded */ bool IsLoaded() const throw(); /** * Attempts to locate and return an entry from one of the databases. * * @param hash hash code of combined ROMs * @param system preferred system in case of multiple profiles * @return entry found */ Entry FindEntry(const Profile::Hash& hash,Machine::FavoredSystem system) const throw(); /** * Attempts to locate and return an entry from one of the databases. * * @param mem pointer to memory of combined ROMs * @param size size of memory * @param system preferred system in case of multiple profiles * @return entry found */ Entry FindEntry(const void* mem,ulong size,Machine::FavoredSystem system) const throw(); }; /** * iNES header format context. */ struct NesHeader { NesHeader() throw(); /** * Clears settings. */ void Clear() throw(); /** * Imports settings from iNES file header in memory. * * @param pointer to iNES header at least 16 byte in size * @param size size of memory * @return result code */ Result Import(const void* mem,ulong size) throw(); /** * Exports settings to iNES file header in memory. * * @param pointer to iNES header at least 16 byte in size * @param size size of memory * @return result code */ Result Export(void* mem,ulong size) const throw(); enum { MAX_PRG_ROM = 0x4000 * 0xFFFUL, MAX_CHR_ROM = 0x2000 * 0xFFFUL }; /** * Region type. */ enum Region { /** * NTSC only. */ REGION_NTSC = 1, /** * PAL only. */ REGION_PAL, /** * Both PAL and NTSC. */ REGION_BOTH }; /** * System type. */ enum System { /** * Console. */ SYSTEM_CONSOLE, /** * Vs System */ SYSTEM_VS, /** * PlayChoice-10 */ SYSTEM_PC10 }; /** * PPU type. */ enum Ppu { /** * RP2C02 NTSC PPU. */ PPU_RP2C02 = Core::PPU_RP2C02, /** * RP2C03B RGB PPU. */ PPU_RP2C03B = Core::PPU_RP2C03B, /** * RP2C03G RGB PPU. */ PPU_RP2C03G = Core::PPU_RP2C03G, /** * RP2C04-0001 RGB PPU. */ PPU_RP2C04_0001 = Core::PPU_RP2C04_0001, /** * RP2C04-0002 RGB PPU. */ PPU_RP2C04_0002 = Core::PPU_RP2C04_0002, /** * RP2C04-0003 RGB PPU. */ PPU_RP2C04_0003 = Core::PPU_RP2C04_0003, /** * RP2C04-0004 RGB PPU. */ PPU_RP2C04_0004 = Core::PPU_RP2C04_0004, /** * RC2C03B RGB PPU. */ PPU_RC2C03B = Core::PPU_RC2C03B, /** * RC2C03C RGB PPU. */ PPU_RC2C03C = Core::PPU_RC2C03C, /** * RC2C05-01 RGB PPU. */ PPU_RC2C05_01 = Core::PPU_RC2C05_01, /** * RC2C05-02 RGB PPU. */ PPU_RC2C05_02 = Core::PPU_RC2C05_02, /** * RC2C05-03 RGB PPU. */ PPU_RC2C05_03 = Core::PPU_RC2C05_03, /** * RC2C05-04 RGB PPU. */ PPU_RC2C05_04 = Core::PPU_RC2C05_04, /** * RC2C05-05 RGB PPU. */ PPU_RC2C05_05 = Core::PPU_RC2C05_05, /** * RP2C07 PAL PPU. */ PPU_RP2C07 = Core::PPU_RP2C07 }; /** * Name-table mirroring type. */ enum Mirroring { /** * Horizontal mirroring. */ MIRRORING_HORIZONTAL, /** * Vertical mirroring. */ MIRRORING_VERTICAL, /** * Four-screen mirroring. */ MIRRORING_FOURSCREEN, /** * Single-screen mirroring. */ MIRRORING_SINGLESCREEN, /** * Software-controlled mirroring. */ MIRRORING_CONTROLLED }; /** * System. */ System system; /** * Region. */ Region region; /** * PRG-ROM size. */ dword prgRom; /** * volatile PRG-RAM (aka W-RAM) size. */ dword prgRam; /** * Non-volatile PRG-RAM (aka W-RAM) size. */ dword prgNvRam; /** * CHR-ROM size. */ dword chrRom; /** * volatile CHR-RAM (aka V-RAM) size. */ dword chrRam; /** * Non-volatile CHR-RAM (aka V-RAM) size. */ dword chrNvRam; /** * PPU. */ Ppu ppu; /** * Name-table mirroring. */ Mirroring mirroring; /** * Mapper ID. */ ushort mapper; /** * Sub-mapper ID. */ uchar subMapper; /** * iNES version number. */ uchar version; /** * Vs System security bits. */ uchar security; /** * Trainer. */ bool trainer; }; /** * Returns the current cartridge profile. * * @return pointer to current profile, NULL if no cartridge has been loaded into the system */ const Profile* GetProfile() const throw(); /** * Creates a profile of an XML ROM set file. * * @param stream input stream to XML file * @param system preferred system in case of multiple profiles * @param askProfile allow callback triggering for choosing between multiple profiles * @param profile object to be filled * @return result code */ static Result ReadRomset(std::istream& stream,Machine::FavoredSystem system,bool askProfile,Profile& profile) throw(); /** * Creates a profile of an iNES file. * * @param stream input stream to iNES file * @param system preferred system in case of multiple profiles * @param profile object to be filled * @return result code */ static Result ReadInes(std::istream& stream,Machine::FavoredSystem system,Profile& profile) throw(); /** * Creates a profile of a UNIF file. * * @param stream input stream to UNIF file * @param system preferred system in case of multiple profiles * @param profile object to be filled * @return result code */ static Result ReadUnif(std::istream& stream,Machine::FavoredSystem system,Profile& profile) throw(); /** * Returns the database interface. * * @return database interface */ Database GetDatabase() throw() { return emulator; } enum { CHOOSE_DEFAULT_PROFILE = INT_MAX }; /** * Cartridge profile chooser callback prototype. * * @param userData optional user data * @param profiles pointer to an array of profiles * @param profileNames pointer to a wide-string array of profile names * @param numProfiles number of profiles to choose between * @return array index of chosen profile */ typedef uint (NST_CALLBACK *ChooseProfileCallback) (UserData userData,const Profile* profiles,const std::wstring* profileNames,uint numProfiles); /** * Cartridge profile chooser callback manager. * * Static object used for adding the user defined callback. */ static ChooseProfileCaller chooseProfileCallback; }; /** * Cartridge profile chooser callback invoker. * * Used internally by the core. */ struct Cartridge::ChooseProfileCaller : Core::UserCallback { uint operator () (const Profile* profiles,const std::wstring* names,uint count) const { return function ? function( userdata, profiles, names, count ) : CHOOSE_DEFAULT_PROFILE; } }; } } #if NST_MSVC >= 1200 #pragma warning( pop ) #endif #endif nestopia-1.51.1/source/core/api/NstApiCheats.cpp000066400000000000000000000217721411157722000214650ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "../NstMachine.hpp" #include "../NstCheats.hpp" #include "NstApiCheats.hpp" #include "NstApiMachine.hpp" namespace Nes { namespace Api { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Result NST_CALL Cheats::GameGenieEncode(const Code& code,char (&characters)[9]) throw() { if (code.address < 0x8000) return RESULT_ERR_INVALID_PARAM; const byte codes[8] = { (code.value >> 0 & 0x7U) | (code.value >> 4 & 0x8U), (code.value >> 4 & 0x7U) | (code.address >> 4 & 0x8U), (code.address >> 4 & 0x7U) | (code.useCompare ? 0x8U : 0x0U), (code.address >> 12 & 0x7U) | (code.address >> 0 & 0x8U), (code.address >> 0 & 0x7U) | (code.address >> 8 & 0x8U), (code.address >> 8 & 0x7U) | ((code.useCompare ? code.compare : code.value) & 0x8U), (code.useCompare ? ((code.compare >> 0 & 0x7U) | (code.compare >> 4 & 0x8U)) : 0), (code.useCompare ? ((code.compare >> 4 & 0x7U) | (code.value >> 0 & 0x8U)) : 0) }; uint i = (code.useCompare ? 8 : 6); characters[i--] = '\0'; do { static const char lut[] = { 'A','P','Z','L','G','I','T','Y', 'E','O','X','U','K','S','V','N' }; characters[i] = lut[codes[i]]; } while (i--); return RESULT_OK; } Result NST_CALL Cheats::GameGenieDecode(const char* const characters,Code& code) throw() { if (characters == NULL) return RESULT_ERR_INVALID_PARAM; byte codes[8]; uint length = 6; for (uint i=0; i < length; ++i) { switch (characters[i]) { case 'A': case 'a': codes[i] = 0x0; break; case 'P': case 'p': codes[i] = 0x1; break; case 'Z': case 'z': codes[i] = 0x2; break; case 'L': case 'l': codes[i] = 0x3; break; case 'G': case 'g': codes[i] = 0x4; break; case 'I': case 'i': codes[i] = 0x5; break; case 'T': case 't': codes[i] = 0x6; break; case 'Y': case 'y': codes[i] = 0x7; break; case 'E': case 'e': codes[i] = 0x8; break; case 'O': case 'o': codes[i] = 0x9; break; case 'X': case 'x': codes[i] = 0xA; break; case 'U': case 'u': codes[i] = 0xB; break; case 'K': case 'k': codes[i] = 0xC; break; case 'S': case 's': codes[i] = 0xD; break; case 'V': case 'v': codes[i] = 0xE; break; case 'N': case 'n': codes[i] = 0xF; break; default: return RESULT_ERR_INVALID_PARAM; } if (i == 2 && codes[2] & 0x8U) length = 8; } code.address = 0x8000 | ( ( codes[4] & 0x1U ) << 0x0 | ( codes[4] & 0x2U ) << 0x0 | ( codes[4] & 0x4U ) << 0x0 | ( codes[3] & 0x8U ) << 0x0 | ( codes[2] & 0x1U ) << 0x4 | ( codes[2] & 0x2U ) << 0x4 | ( codes[2] & 0x4U ) << 0x4 | ( codes[1] & 0x8U ) << 0x4 | ( codes[5] & 0x1U ) << 0x8 | ( codes[5] & 0x2U ) << 0x8 | ( codes[5] & 0x4U ) << 0x8 | ( codes[4] & 0x8U ) << 0x8 | ( codes[3] & 0x1U ) << 0xC | ( codes[3] & 0x2U ) << 0xC | ( codes[3] & 0x4U ) << 0xC ); code.value = ( ( codes[0] & 0x1U ) << 0x0 | ( codes[0] & 0x2U ) << 0x0 | ( codes[0] & 0x4U ) << 0x0 | ( codes[1] & 0x1U ) << 0x4 | ( codes[1] & 0x2U ) << 0x4 | ( codes[1] & 0x4U ) << 0x4 | ( codes[0] & 0x8U ) << 0x4 ); if (length == 8) { code.useCompare = true; code.value |= codes[7] & 0x8U; code.compare = ( ( codes[6] & 0x1U ) << 0x0 | ( codes[6] & 0x2U ) << 0x0 | ( codes[6] & 0x4U ) << 0x0 | ( codes[5] & 0x8U ) << 0x0 | ( codes[7] & 0x1U ) << 0x4 | ( codes[7] & 0x2U ) << 0x4 | ( codes[7] & 0x4U ) << 0x4 | ( codes[6] & 0x8U ) << 0x4 ); } else { code.useCompare = false; code.value |= codes[5] & 0x8U; code.compare = 0x00; } return RESULT_OK; } struct Cheats::Lut { static const byte rocky[]; }; const byte Cheats::Lut::rocky[] = { 3, 13, 14, 1, 6, 9, 5, 0, 12, 7, 2, 8, 10, 11, 4, 19, 21, 23, 22, 20, 17, 16, 18, 29, 31, 24, 26, 25, 30, 27, 28 }; Result NST_CALL Cheats::ProActionRockyEncode(const Code& code,char (&characters)[9]) throw() { if (code.address < 0x8000 || !code.useCompare) return RESULT_ERR_INVALID_PARAM; const dword input = (code.address & 0x7FFFU) | dword(code.compare) << 16 | dword(code.value) << 24; dword output = 0; for (dword i=31, key=0xFCBDD274; i--; key = key << 1 & 0xFFFFFFFF) { const uint ctrl = input >> Lut::rocky[i] & 0x1; output |= (key >> 31 ^ ctrl) << (i+1); if (ctrl) key ^= 0xB8309722; } characters[8] = '\0'; for (uint i=0; i < 8; ++i) { const int value = (output >> (i * 4)) & 0xF; characters[i ^ 7] = (value >= 0xA) ? (value - 0xA + 'A') : (value + '0'); } return RESULT_OK; } Result NST_CALL Cheats::ProActionRockyDecode(const char* const characters,Code& code) throw() { if (characters == NULL) return RESULT_ERR_INVALID_PARAM; dword input=0, output=0; for (uint i=0; i < 8; ++i) { dword num; const int character = characters[i ^ 7]; if (character >= '0' && character <= '9') { num = character - '0'; } else if (character >= 'A' && character <= 'F') { num = character - 'A' + 0xA; } else if (character >= 'a' && character <= 'f') { num = character - 'a' + 0xA; } else { return RESULT_ERR_INVALID_PARAM; } input |= num << (i * 4); } for (dword i=31, key=0xFCBDD274; i--; input <<= 1, key <<= 1) { if ((key ^ input) & 0x80000000) { output |= 1UL << Lut::rocky[i]; key ^= 0xB8309722; } } code.address = (output & 0x7FFF) | 0x8000; code.compare = output >> 16 & 0xFF; code.value = output >> 24 & 0xFF; code.useCompare = true; return RESULT_OK; } Result Cheats::SetCode(const Code& code) throw() { if (emulator.tracker.IsLocked( true )) return RESULT_ERR_NOT_READY; try { if (emulator.cheats == NULL) emulator.cheats = new Core::Cheats( emulator.cpu ); return emulator.tracker.TryResync ( emulator.cheats->SetCode ( code.address, code.value, code.compare, code.useCompare, emulator.Is(Machine::GAME) ), true ); } catch (const std::bad_alloc&) { return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { return RESULT_ERR_GENERIC; } } Result Cheats::DeleteCode(const ulong index) throw() { if (emulator.tracker.IsLocked( true )) return RESULT_ERR_NOT_READY; if (!emulator.cheats) return RESULT_ERR_INVALID_PARAM; const Result result = emulator.tracker.TryResync( emulator.cheats->DeleteCode( index ), true ); if (!emulator.cheats->NumCodes()) { delete emulator.cheats; emulator.cheats = NULL; } return result; } ulong Cheats::NumCodes() const throw() { return emulator.cheats ? emulator.cheats->NumCodes() : 0; } Result Cheats::GetCode(ulong index,ushort* address,uchar* value,uchar* compare,bool* useCompare) const throw() { if (emulator.cheats) return emulator.cheats->GetCode( index, address, value, compare, useCompare ); else return RESULT_ERR_INVALID_PARAM; } Result Cheats::GetCode(ulong index,Code& code) const throw() { return GetCode( index, &code.address, &code.value, &code.compare, &code.useCompare ); } Result Cheats::ClearCodes() throw() { if (emulator.tracker.IsLocked( true )) return RESULT_ERR_NOT_READY; if (!emulator.cheats) return RESULT_NOP; if (emulator.cheats->NumCodes()) emulator.tracker.Resync( true ); delete emulator.cheats; emulator.cheats = NULL; return RESULT_OK; } Cheats::Ram Cheats::GetRam() const throw() { return emulator.cpu.GetRam(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } nestopia-1.51.1/source/core/api/NstApiCheats.hpp000066400000000000000000000115071411157722000214650ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_API_CHEATS_H #define NST_API_CHEATS_H #include "NstApi.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif #if NST_ICC >= 810 #pragma warning( push ) #pragma warning( disable : 444 ) #elif NST_MSVC >= 1200 #pragma warning( push ) #pragma warning( disable : 4512 ) #endif namespace Nes { namespace Api { /** * Cheats interface. */ class Cheats : public Base { struct Lut; public: /** * Interface constructor. * * @param instance emulator instance */ template Cheats(T& instance) : Base(instance) {} /** * Cheat code. */ struct Code { /** * Address. */ ushort address; /** * Value. */ uchar value; /** * Compare-value. */ uchar compare; /** * Compare-value enable. */ bool useCompare; /** * Constructor. * * @param a address * @param v value * @param c compare-value * @param u compare-value enable */ Code(ushort a=0,uchar v=0,uchar c=0,bool u=false) : address(a), value(v), compare(c), useCompare(u) {} }; /** * Adds a new code. * * @param code code, any existing code using the same address will be replaced * @return result code */ Result SetCode(const Code& code) throw(); /** * Returns an existing code. * * @param index code index * @param code object to be filled * @return result code */ Result GetCode(ulong index,Code& code) const throw(); /** * Returns attributes of an existing code. * * @param index code index * @param address address to be filled or NULL if not needed * @param value value to be filled or NULL if not needed * @param compare compare-value to be filled or NULL if not needed * @param useCompare compare-value enable to be filled or NULL if not needed * @return result code */ Result GetCode(ulong index,ushort* address,uchar* value,uchar* compare,bool* useCompare) const throw(); /** * Removes an existing code. * * @param index code index * @return result code */ Result DeleteCode(ulong index) throw(); /** * Returns current number of codes. * * @return number */ ulong NumCodes() const throw(); /** * Removes all existing codes. * * @return result code */ Result ClearCodes() throw(); enum { RAM_SIZE = 0x800 }; /** * CPU RAM pointer reference. */ typedef const uchar (&Ram)[RAM_SIZE]; /** * Returns read-only content of CPU RAM. * * @return CPU RAM */ Ram GetRam() const throw(); /** * Encodes into a Game Genie code. * * @param code code to be encoded * @param string Game Genie code string to be filled * @return result code */ static Result NST_CALL GameGenieEncode(const Code& code,char (&string)[9]) throw(); /** * Decodes a Game Genie code. * * @param string Game Genie encoded string * @param code object to be filled * @return result code */ static Result NST_CALL GameGenieDecode(const char* string,Code& code) throw(); /** * Encodes into a Pro-Action Rocky code. * * @param code code to be encoded * @param string Pro-Action Rocky code string to be filled * @return result code */ static Result NST_CALL ProActionRockyEncode(const Code& code,char (&string)[9]) throw(); /** * Decodes a Pro-Action Rocky code. * * @param string Pro-Action Rocky encoded string * @param code object to be filled * @return result */ static Result NST_CALL ProActionRockyDecode(const char* string,Code& code) throw(); }; } } #if NST_MSVC >= 1200 || NST_ICC >= 810 #pragma warning( pop ) #endif #endif nestopia-1.51.1/source/core/api/NstApiConfig.hpp000066400000000000000000000136621411157722000214670ustar00rootroot00000000000000/* //////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// */ #ifndef NST_BASE_H #error Do not include NstApConfig.hpp directly! #endif /* //////////////////////////////////////////////////////////////////////////////////////// // // Compiler Configuration: // ----------------------- // // NST_DEBUG - Debug mode compilation. // // NST_PRAGMA_ONCE - Define if #pragma once is supported. Auto-defined if // compiler is MCW or MSVC. // // NST_U64 - For native 64bit (or greater) integer support. May not // be needed if compiler is BC, GCC, ICC, MSVC or supports // the C99 long long integer type. // // Example: #define NST_U64 unsigned long long // // If no suitable type is available, a default class based // implementation will be used which may generate slower code. // // NST_MM_INTRINSICS - For MMX/SSE compiler intrinsics support through // xmmintrin.h/emmintrin.h/mmintrin.h. Auto-defined if // compiler is Win32 MSVC and _M_IX86 is defined. // // NST_CALL - Compiler/platform specific calling convention for non-member // functions. Placed between return type and function name, e.g // void NST_CALL DoSomething(). // // Example usage on a Win32 platform: #define NST_CALL __fastcall // // NST_CALLBACK - Same as above but for user-callback functions only. If // defined, you're responsible for decorating your own // callback functions with it. // // NST_LINEBREAK - Character sequence for line breaks. Default is "\n", or "\r\n" // if target platform is Win32. // // Example usage in Nestopia: // // Print( "Hey!" NST_LINEBREAK "get off my lawn!" NST_LINEBREAK ); // // NST_NO_INLINE - To prevent automatic inline expansion of certain functions // that won't benefit from it. Auto-defined if compiler is // GCC, ICC or MSVC. // // NST_RESTRICT - C99 restrict qualifier support. Used on pointer types to // inform the compiler that they're are not aliased which may // enable it to generate faster code. Auto-defined if compiler // is GCC, ICC or MSVC. // // NST_ASSUME(x) y(x) - Optimization hint for the compiler. Informs that the condition // will always evaluate to true. Should not be used if the condition // checking imposes a performance penalty as it's not intended for // debugging use. Auto-defined if compiler is MSVC. // // Example usage in Nestopia: // // #ifdef NST_DEBUG // assert( miss_july == hot ); // #else // NST_ASSUME( miss_july == hot ); // #endif // // NST_FASTDELEGATE - Define this if your compiler can handle casts between member // function pointers of different types and calls through them. // // If the size required to store a non-virtual member function // pointer is deemed too large, as in // // sizeof( void (Class::*)() ) > sizeof( void (*)() ) // // this option is not worth using and Nestopia will force a // compile time error. Auto-defined if compiler is MSVC. // // Abbrevations: // // BC - Borland C++ // GCC - GNU Compiler Collection // ICC - Intel C/C++ Compiler // MCW - Metrowerks CodeWarrior // MSVC - Microsoft Visual C++ // //////////////////////////////////////////////////////////////////////////////////////// */ /* //////////////////////////////////////////////////////////////////////////////////////// // // Define to disable a particular feature. // // NST_NO_ZLIB - ZLib compression library. Not recommended to disable // unless it's unavailable on the target platform. The core // uses it internally for save states and the rewinder // feature. Although they'll still work without them, memory // footprint will increase drastically. // // NST_NO_HQ2X - hq2x and hq3x video filters // // NST_NO_SCALEX - Scale2x and Scale3x video filters // // NST_NO_2XSAI - 2xSaI video filter // //////////////////////////////////////////////////////////////////////////////////////// */ nestopia-1.51.1/source/core/api/NstApiDipSwitches.cpp000066400000000000000000000067171411157722000225060ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstMachine.hpp" #include "../NstDipSwitches.hpp" #include "../NstImage.hpp" #include "NstApiDipSwitches.hpp" namespace Nes { namespace Api { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Core::DipSwitches* DipSwitches::Query() const { if (emulator.image) { if (Core::Image::ExternalDevice device = emulator.image->QueryExternalDevice( Core::Image::EXT_DIP_SWITCHES )) return static_cast(device); } return NULL; } bool DipSwitches::CanModify() const throw() { return !emulator.tracker.IsLocked() && Query(); } uint DipSwitches::NumDips() const throw() { if (Core::DipSwitches* const dipSwitches = Query()) return dipSwitches->NumDips(); return 0; } uint DipSwitches::NumValues(uint dip) const throw() { if (Core::DipSwitches* const dipSwitches = Query()) { if (dipSwitches->NumDips() > dip) return dipSwitches->NumValues( dip ); } return 0; } const char* DipSwitches::GetDipName(uint dip) const throw() { if (Core::DipSwitches* const dipSwitches = Query()) { if (dipSwitches->NumDips() > dip) return dipSwitches->GetDipName( dip ); } return NULL; } const char* DipSwitches::GetValueName(uint dip,uint value) const throw() { if (Core::DipSwitches* const dipSwitches = Query()) { if (dipSwitches->NumDips() > dip && dipSwitches->NumValues( dip ) > value) return dipSwitches->GetValueName( dip, value ); } return NULL; } int DipSwitches::GetValue(uint dip) const throw() { if (Core::DipSwitches* const dipSwitches = Query()) { if (dipSwitches->NumDips() > dip) return dipSwitches->GetValue( dip ); } return INVALID; } Result DipSwitches::SetValue(uint dip,uint value) throw() { if (!emulator.tracker.IsLocked()) { if (Core::DipSwitches* const dipSwitches = Query()) { if (dip >= dipSwitches->NumDips() || value >= dipSwitches->NumValues( dip )) { return RESULT_ERR_INVALID_PARAM; } else if (value != dipSwitches->GetValue( dip )) { emulator.tracker.Resync(); dipSwitches->SetValue( dip, value ); return RESULT_OK; } else { return RESULT_NOP; } } } return RESULT_ERR_NOT_READY; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } nestopia-1.51.1/source/core/api/NstApiDipSwitches.hpp000066400000000000000000000061701411157722000225040ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_API_DIPSWITCHES_H #define NST_API_DIPSWITCHES_H #include "NstApi.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif #if NST_ICC >= 810 #pragma warning( push ) #pragma warning( disable : 444 ) #elif NST_MSVC >= 1200 #pragma warning( push ) #pragma warning( disable : 4512 ) #endif namespace Nes { namespace Core { class DipSwitches; } namespace Api { /** * DIP switches interface. */ class DipSwitches : public Base { Core::DipSwitches* Query() const; public: /** * Interface constructor. * * @param instance emulator instance */ template DipSwitches(T& instance) : Base(instance) {} enum { INVALID = -1 }; /** * Returns the number of available DIP switches. * * @return number */ uint NumDips() const throw(); /** * Returns the number of values that can be chosen for a DIP switch. * * @param dip DIP switch ID * @return number */ uint NumValues(uint dip) const throw(); /** * Checks if the DIP switches can be changed at this time. * * @return true if DIP switches can be changed */ bool CanModify() const throw(); /** * Returns the name of a DIP switch. * * @param dip DIP switch ID * @return DIP switch name or NULL if unavailable */ const char* GetDipName(uint dip) const throw(); /** * Returns the name of a DIP switch value. * * @param dip DIP switch ID * @param value value ID * @return value name or NULL if unavailable */ const char* GetValueName(uint dip,uint value) const throw(); /** * Returns the current DIP switch value. * * @param dip DIP switch ID * @return value ID or INVALID if unavailable */ int GetValue(uint dip) const throw(); /** * Sets a DIP switch value. * * @param dip DIP switch ID * @param value value ID * @return result code */ Result SetValue(uint dip,uint value) throw(); }; } } #if NST_MSVC >= 1200 || NST_ICC >= 810 #pragma warning( pop ) #endif #endif nestopia-1.51.1/source/core/api/NstApiEmulator.cpp000066400000000000000000000033121411157722000220340ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstMachine.hpp" #include "NstApiEmulator.hpp" namespace Nes { namespace Api { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Emulator::Emulator() : machine(*new Core::Machine) { } Emulator::~Emulator() throw() { delete &machine; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif Result Emulator::Execute ( Core::Video::Output* video, Core::Sound::Output* sound, Core::Input::Controllers* input ) throw() { return machine.tracker.Execute( machine, video, sound, input ); } ulong Emulator::Frame() const throw() { return machine.tracker.Frame(); } } } nestopia-1.51.1/source/core/api/NstApiEmulator.hpp000066400000000000000000000045311411157722000220450ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_API_EMULATOR_H #define NST_API_EMULATOR_H #ifndef NST_BASE_H #include "../NstBase.hpp" #endif #ifdef NST_PRAGMA_ONCE #pragma once #endif #if NST_MSVC >= 1200 #pragma warning( push ) #endif namespace Nes { namespace Core { class Machine; namespace Video { class Output; } namespace Sound { class Output; } namespace Input { class Controllers; } } namespace Api { /** * Emulator object instance. */ class Emulator { public: Emulator(); ~Emulator() throw(); /** * Executes one frame. * * @param video video context object or NULL to skip output * @param sound sound context object or NULL to skip output * @param input input context object or NULL to skip output * @return result code */ Result Execute ( Core::Video::Output* video, Core::Sound::Output* sound, Core::Input::Controllers* input ) throw(); /** * Returns the number of executed frames relative to the last machine power/reset. * * @return number */ ulong Frame() const throw(); private: Core::Machine& machine; public: operator Core::Machine& () { return machine; } }; } } #if NST_MSVC >= 1200 #pragma warning( pop ) #endif #endif nestopia-1.51.1/source/core/api/NstApiFds.cpp000066400000000000000000000124301411157722000207610ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "../NstMachine.hpp" #include "../NstStream.hpp" #include "../NstFds.hpp" #include "NstApiCartridge.hpp" #include "NstApiMachine.hpp" #include "NstApiFds.hpp" namespace Nes { namespace Api { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Fds::DiskCaller Fds::diskCallback; Fds::DriveCaller Fds::driveCallback; Fds::DiskData::File::File() throw() : id (0), index (0), address (0), type (TYPE_UNKNOWN) { for (uint i=0; i < sizeof(name); ++i) name[i] = '\0'; } Fds::DiskData::DiskData() throw() { } Fds::DiskData::~DiskData() throw() { } Result Fds::GetDiskData(uint side,DiskData& data) const throw() { if (emulator.Is(Machine::DISK)) return static_cast(emulator.image)->GetDiskData( side, data ); return RESULT_ERR_NOT_READY; } bool Fds::IsAnyDiskInserted() const throw() { if (emulator.Is(Machine::DISK)) return static_cast(emulator.image)->IsAnyDiskInserted(); return false; } Result Fds::InsertDisk(uint disk,uint side) throw() { if (emulator.Is(Machine::DISK) && !emulator.tracker.IsLocked()) return emulator.tracker.TryResync( static_cast(emulator.image)->InsertDisk( disk, side ) ); return RESULT_ERR_NOT_READY; } Result Fds::ChangeSide() throw() { const int disk = GetCurrentDisk(); if (disk != NO_DISK) return InsertDisk( disk, GetCurrentDiskSide() ^ 1 ); return RESULT_ERR_NOT_READY; } Result Fds::EjectDisk() throw() { if (emulator.Is(Machine::DISK) && !emulator.tracker.IsLocked()) return emulator.tracker.TryResync( static_cast(emulator.image)->EjectDisk() ); return RESULT_ERR_NOT_READY; } Result Fds::SetBIOS(std::istream* const stdStream) throw() { if (emulator.Is(Machine::GAME,Machine::ON)) return RESULT_ERR_NOT_READY; try { if (stdStream) { Core::Stream::In stream( stdStream ); idword offset; Cartridge::NesHeader setup; byte header[16]; stream.Read( header ); if (NES_FAILED(setup.Import( header, 16 ))) { offset = -16; } else if (setup.prgRom >= Core::SIZE_8K) { offset = (setup.trainer ? 512 : 0) + (setup.prgRom - Core::SIZE_8K); } else { return RESULT_ERR_CORRUPT_FILE; } stream.Seek( offset ); } Core::Fds::SetBios( stdStream ); } catch (Result result) { return result; } catch (const std::bad_alloc&) { return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { return RESULT_ERR_GENERIC; } return RESULT_OK; } Result Fds::GetBIOS(std::ostream& stream) const throw() { try { return Core::Fds::GetBios( stream ); } catch (Result result) { return result; } catch (const std::bad_alloc&) { return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { return RESULT_ERR_GENERIC; } } bool Fds::HasBIOS() const throw() { return Core::Fds::HasBios(); } uint Fds::GetNumDisks() const throw() { if (emulator.Is(Machine::DISK)) return static_cast(emulator.image)->NumDisks(); return 0; } uint Fds::GetNumSides() const throw() { if (emulator.Is(Machine::DISK)) return static_cast(emulator.image)->NumSides(); return 0; } int Fds::GetCurrentDisk() const throw() { if (emulator.Is(Machine::DISK)) return static_cast(emulator.image)->CurrentDisk(); return NO_DISK; } int Fds::GetCurrentDiskSide() const throw() { if (emulator.Is(Machine::DISK)) return static_cast(emulator.image)->CurrentDiskSide(); return NO_DISK; } bool Fds::CanChangeDiskSide() const throw() { if (emulator.Is(Machine::DISK)) return static_cast(emulator.image)->CanChangeDiskSide(); return false; } bool Fds::HasHeader() const throw() { return emulator.Is(Machine::DISK) && static_cast(emulator.image)->HasHeader(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } nestopia-1.51.1/source/core/api/NstApiFds.hpp000066400000000000000000000161331411157722000207720ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_API_FDS_H #define NST_API_FDS_H #include #include #include "NstApi.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif #if NST_ICC >= 810 #pragma warning( push ) #pragma warning( disable : 304 444 ) #elif NST_MSVC >= 1200 #pragma warning( push ) #pragma warning( disable : 4512 ) #endif namespace Nes { namespace Api { /** * Famicom Disk System interface. */ class Fds : public Base { struct DiskCaller; struct DriveCaller; public: /** * Interface constructor. * * @param instance emulator instance */ template Fds(T& instance) : Base(instance) {} enum { NO_DISK = -1 }; /** * Checks if a disk is inserted. * * @return true if a disk is inserted */ bool IsAnyDiskInserted() const throw(); /** * Inserts a disk. * * @param disk disk number * @param side disk side, 0(A) or 1(B) * @return result code */ Result InsertDisk(uint disk,uint side) throw(); /** * Changes disk side. * * @return result code */ Result ChangeSide() throw(); /** * Ejects disk. * * @return result code */ Result EjectDisk() throw(); /** * Sets BIOS. * * @param input stream to ROM binary or iNES file, set to NULL to remove current BIOS * @result result code */ Result SetBIOS(std::istream* stream) throw(); /** * Stores the current BIOS in an output stream. * * @param output stream * @return result code */ Result GetBIOS(std::ostream& stream) const throw(); /** * Checks if a BIOS has been loaded. * * @return true if a BIOS has been loaded. */ bool HasBIOS() const throw(); /** * Returns the total number of disks. * * @return number */ uint GetNumDisks() const throw(); /** * Returns the total number of disks and their sides. * * @return number */ uint GetNumSides() const throw(); /** * Returns the current disk inserted. * * @return current disk or NO_DISK if none */ int GetCurrentDisk() const throw(); /** * Returns the current disk side. * * @return 0(A), 1(B) or NO_DISK if no disk inserted */ int GetCurrentDiskSide() const throw(); /** * Checks if the current disk can change side. * * @return true if disk can change side */ bool CanChangeDiskSide() const throw(); /** * Checks if the current loaded image comes with a file header. * * @return true if it comes with a file header */ bool HasHeader() const throw(); /** * Disk data context. */ struct DiskData { DiskData() throw(); ~DiskData() throw(); /** * Data content. */ typedef std::vector Data; /** * File on disk. */ struct File { File() throw(); /** * File type. */ enum Type { /** * Unknown file. */ TYPE_UNKNOWN, /** * PRG data file. */ TYPE_PRG, /** * CHR data file. */ TYPE_CHR, /** * Name-table data file. */ TYPE_NMT }; /** * File ID. */ uchar id; /** * File index. */ uchar index; /** * File address. */ ushort address; /** * File type. */ Type type; /** * File content. */ Data data; /** * File name. */ char name[12]; }; /** * Files. */ typedef std::vector Files; /** * Files. */ Files files; /** * Raw binary content. */ Data raw; }; /** * Returns disk information. * * @param side disks and sides index * @param data object to be filled * @return result code */ Result GetDiskData(uint side,DiskData& data) const throw(); /** * Disk event. */ enum Event { /** * Disk has been inserted. */ DISK_INSERT, /** * Disk has been ejected. */ DISK_EJECT, /** * Disk is in a non-standard format. */ DISK_NONSTANDARD }; /** * Drive event. */ enum Motor { /** * Drive motor is OFF. */ MOTOR_OFF, /** * Drive motor is ON reading. */ MOTOR_READ, /** * Drive motor is ON writing. */ MOTOR_WRITE }; enum { NUM_DISK_CALLBACKS = 3, NUM_DRIVE_CALLBACKS = 3 }; /** * Disk event callback prototype. * * @param userData optional user data * @param event type of event * @param disk disk number * @param disk side, 0(A) or 1(B) */ typedef void (NST_CALLBACK *DiskCallback)(UserData userData,Event event,uint disk,uint side); /** * Drive event callback prototype. * * @param userData optional user data * @param event type of event */ typedef void (NST_CALLBACK *DriveCallback)(UserData userData,Motor event); /** * Disk event callback manager. * * Static object used for adding the user defined callback. */ static DiskCaller diskCallback; /** * Drive event callback manager. * * Static object used for adding the user defined callback. */ static DriveCaller driveCallback; }; /** * Disk event callback invoker. * * Used internally by the core. */ struct Fds::DiskCaller : Core::UserCallback { void operator () (Event event,uint disk,uint side) const { if (function) function( userdata, event, disk, side ); } }; /** * Drive event callback invoker. * * Used internally by the core. */ struct Fds::DriveCaller : Core::UserCallback { void operator () (Motor motor) const { if (function) function( userdata, motor ); } }; } } #if NST_MSVC >= 1200 || NST_ICC >= 810 #pragma warning( pop ) #endif #endif nestopia-1.51.1/source/core/api/NstApiHomebrew.cpp000066400000000000000000000115411411157722000220170ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2018-2018 Phil Smith // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "../NstMachine.hpp" #include "../NstHomebrew.hpp" #include "NstApiHomebrew.hpp" #include "NstApiMachine.hpp" namespace Nes { namespace Api { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Result Homebrew::SetExitPort(ushort address) throw() { if (emulator.tracker.IsLocked( true )) return RESULT_ERR_NOT_READY; try { if (emulator.homebrew == NULL) emulator.homebrew = new Core::Homebrew( emulator.cpu ); return emulator.tracker.TryResync ( emulator.homebrew->SetExitPort ( address, emulator.Is(Machine::GAME) ), true ); } catch (const std::bad_alloc&) { return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { return RESULT_ERR_GENERIC; } } Result Homebrew::ClearExitPort() throw() { if (emulator.tracker.IsLocked( true )) return RESULT_ERR_NOT_READY; if (!emulator.homebrew) return RESULT_ERR_INVALID_PARAM; const Result result = emulator.tracker.TryResync ( emulator.homebrew->ClearExitPort(), true ); if (!emulator.homebrew->NumPorts()) { delete emulator.homebrew; emulator.homebrew = NULL; } return result; } Result Homebrew::SetStdOutPort(ushort address) throw() { if (emulator.tracker.IsLocked( true )) return RESULT_ERR_NOT_READY; try { if (emulator.homebrew == NULL) emulator.homebrew = new Core::Homebrew( emulator.cpu ); return emulator.tracker.TryResync ( emulator.homebrew->SetStdOutPort ( address, emulator.Is(Machine::GAME) ), true ); } catch (const std::bad_alloc&) { return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { return RESULT_ERR_GENERIC; } } Result Homebrew::ClearStdOutPort() throw() { if (emulator.tracker.IsLocked( true )) return RESULT_ERR_NOT_READY; if (!emulator.homebrew) return RESULT_ERR_INVALID_PARAM; const Result result = emulator.tracker.TryResync ( emulator.homebrew->ClearStdOutPort(), true ); if (!emulator.homebrew->NumPorts()) { delete emulator.homebrew; emulator.homebrew = NULL; } return result; } Result Homebrew::SetStdErrPort(ushort address) throw() { if (emulator.tracker.IsLocked( true )) return RESULT_ERR_NOT_READY; try { if (emulator.homebrew == NULL) emulator.homebrew = new Core::Homebrew( emulator.cpu ); return emulator.tracker.TryResync ( emulator.homebrew->SetStdErrPort ( address, emulator.Is(Machine::GAME) ), true ); } catch (const std::bad_alloc&) { return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { return RESULT_ERR_GENERIC; } } Result Homebrew::ClearStdErrPort() throw() { if (emulator.tracker.IsLocked( true )) return RESULT_ERR_NOT_READY; if (!emulator.homebrew) return RESULT_ERR_INVALID_PARAM; const Result result = emulator.tracker.TryResync ( emulator.homebrew->ClearStdErrPort(), true ); if (!emulator.homebrew->NumPorts()) { delete emulator.homebrew; emulator.homebrew = NULL; } return result; } ulong Homebrew::NumPorts() const throw() { return emulator.homebrew ? emulator.homebrew->NumPorts() : 0; } Result Homebrew::ClearPorts() throw() { if (emulator.tracker.IsLocked( true )) return RESULT_ERR_NOT_READY; if (!emulator.homebrew) return RESULT_NOP; if (emulator.homebrew->NumPorts()) emulator.tracker.Resync( true ); delete emulator.homebrew; emulator.homebrew = NULL; return RESULT_OK; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } nestopia-1.51.1/source/core/api/NstApiHomebrew.hpp000066400000000000000000000057141411157722000220310ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2018-2018 Phil Smith // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_API_HOMEBREW_H #define NST_API_HOMEBREW_H #include "NstApi.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif #if NST_ICC >= 810 #pragma warning( push ) #pragma warning( disable : 444 ) #elif NST_MSVC >= 1200 #pragma warning( push ) #pragma warning( disable : 4512 ) #endif namespace Nes { namespace Api { /** * Homebrew interface. */ class Homebrew : public Base { public: /** * Interface constructor. * * @param instance emulator instance */ template Homebrew(T& instance) : Base(instance) {} /** * Sets the exit port. * * @param address exit port address, * any previous exit port will be removed * @return result code */ Result SetExitPort(ushort address) throw(); /** * Removes the exit port. * * @return result code */ Result ClearExitPort() throw(); /** * Sets the standard out port. * * @param address standard out port address, * any previous standard out port will be removed * @return result code */ Result SetStdOutPort(ushort address) throw(); /** * Removes the standard out port. * * @return result code */ Result ClearStdOutPort() throw(); /** * Sets the standard error port. * * @param address standard error port address, * any previous standard error port will be removed * @return result code */ Result SetStdErrPort(ushort address) throw(); /** * Removes the standard error port. * * @return result code */ Result ClearStdErrPort() throw(); /** * Returns current number of ports. * * @return number */ ulong NumPorts() const throw(); /** * Removes all existing ports. * * @return result code */ Result ClearPorts() throw(); }; } } #if NST_MSVC >= 1200 || NST_ICC >= 810 #pragma warning( pop ) #endif #endif nestopia-1.51.1/source/core/api/NstApiInput.cpp000066400000000000000000000345201411157722000213500ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include #include "../NstMachine.hpp" #include "../NstCartridge.hpp" #include "../input/NstInpDevice.hpp" #include "../input/NstInpAdapter.hpp" #include "../input/NstInpPad.hpp" #include "../input/NstInpZapper.hpp" #include "../input/NstInpPaddle.hpp" #include "../input/NstInpPowerPad.hpp" #include "../input/NstInpPowerGlove.hpp" #include "../input/NstInpMouse.hpp" #include "../input/NstInpFamilyTrainer.hpp" #include "../input/NstInpFamilyKeyboard.hpp" #include "../input/NstInpSuborKeyboard.hpp" #include "../input/NstInpDoremikkoKeyboard.hpp" #include "../input/NstInpHoriTrack.hpp" #include "../input/NstInpPachinko.hpp" #include "../input/NstInpOekaKidsTablet.hpp" #include "../input/NstInpKonamiHyperShot.hpp" #include "../input/NstInpBandaiHyperShot.hpp" #include "../input/NstInpCrazyClimber.hpp" #include "../input/NstInpMahjong.hpp" #include "../input/NstInpExcitingBoxing.hpp" #include "../input/NstInpTopRider.hpp" #include "../input/NstInpPokkunMoguraa.hpp" #include "../input/NstInpPartyTap.hpp" #include "../input/NstInpRob.hpp" #include "../input/NstInpTurboFile.hpp" #include "../input/NstInpBarcodeWorld.hpp" namespace Nes { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif namespace Api { Input::ControllerCaller Input::controllerCallback; Input::AdapterCaller Input::adapterCallback; } namespace Core { namespace Input { Controllers::PollCaller2< Controllers::Pad > Controllers::Pad::callback; Controllers::PollCaller1< Controllers::Zapper > Controllers::Zapper::callback; Controllers::PollCaller1< Controllers::Paddle > Controllers::Paddle::callback; Controllers::PollCaller1< Controllers::PowerPad > Controllers::PowerPad::callback; Controllers::PollCaller1< Controllers::PowerGlove > Controllers::PowerGlove::callback; Controllers::PollCaller1< Controllers::Mouse > Controllers::Mouse::callback; Controllers::PollCaller1< Controllers::FamilyTrainer > Controllers::FamilyTrainer::callback; Controllers::PollCaller3< Controllers::FamilyKeyboard > Controllers::FamilyKeyboard::callback; Controllers::PollCaller3< Controllers::SuborKeyboard > Controllers::SuborKeyboard::callback; Controllers::PollCaller3< Controllers::DoremikkoKeyboard > Controllers::DoremikkoKeyboard::callback; Controllers::PollCaller1< Controllers::HoriTrack > Controllers::HoriTrack::callback; Controllers::PollCaller1< Controllers::Pachinko > Controllers::Pachinko::callback; Controllers::PollCaller1< Controllers::VsSystem > Controllers::VsSystem::callback; Controllers::PollCaller1< Controllers::OekaKidsTablet > Controllers::OekaKidsTablet::callback; Controllers::PollCaller1< Controllers::KonamiHyperShot > Controllers::KonamiHyperShot::callback; Controllers::PollCaller1< Controllers::BandaiHyperShot > Controllers::BandaiHyperShot::callback; Controllers::PollCaller1< Controllers::CrazyClimber > Controllers::CrazyClimber::callback; Controllers::PollCaller2< Controllers::Mahjong > Controllers::Mahjong::callback; Controllers::PollCaller2< Controllers::ExcitingBoxing > Controllers::ExcitingBoxing::callback; Controllers::PollCaller1< Controllers::TopRider > Controllers::TopRider::callback; Controllers::PollCaller2< Controllers::PokkunMoguraa > Controllers::PokkunMoguraa::callback; Controllers::PollCaller1< Controllers::PartyTap > Controllers::PartyTap::callback; Controllers::PollCaller1< Controllers::KaraokeStudio > Controllers::KaraokeStudio::callback; Controllers::PowerPad::PowerPad() throw() { std::fill( sideA, sideA + NUM_SIDE_A_BUTTONS, false ); std::fill( sideB, sideB + NUM_SIDE_B_BUTTONS, false ); } Controllers::PowerGlove::PowerGlove() throw() { x = 0; y = 0; distance = 0; wrist = 0; gesture = GESTURE_OPEN; } Controllers::FamilyTrainer::FamilyTrainer() throw() { std::fill( sideA, sideA + NUM_SIDE_A_BUTTONS, false ); std::fill( sideB, sideB + NUM_SIDE_B_BUTTONS, false ); } Controllers::FamilyKeyboard::FamilyKeyboard() throw() { std::memset( parts, 0x00, sizeof(parts) ); } Controllers::SuborKeyboard::SuborKeyboard() throw() { std::memset( parts, 0x00, sizeof(parts) ); } Controllers::Controllers() throw() { } } } namespace Api { Result Input::ConnectController(const uint port,const Type type) throw() { Core::Input::Device* old = NULL; switch (port) { case PORT_1: case PORT_2: if (emulator.extPort->GetDevice( port ).GetType() == type) { return RESULT_NOP; } else switch (type) { case UNCONNECTED: old = new (std::nothrow) Core::Input::Device( emulator.cpu ); break; case PAD1: case PAD2: case PAD3: case PAD4: old = new (std::nothrow) Core::Input::Pad( emulator.cpu, uint(type) - PAD1 ); break; case ZAPPER: old = new (std::nothrow) Core::Input::Zapper( emulator.cpu, emulator.ppu ); break; case PADDLE: old = new (std::nothrow) Core::Input::Paddle( emulator.cpu, false ); break; case POWERPAD: old = new (std::nothrow) Core::Input::PowerPad( emulator.cpu ); break; case POWERGLOVE: old = new (std::nothrow) Core::Input::PowerGlove( emulator.cpu ); break; case MOUSE: old = new (std::nothrow) Core::Input::Mouse( emulator.cpu ); break; case ROB: old = new (std::nothrow) Core::Input::Rob( emulator.cpu, emulator.ppu ); break; default: return RESULT_ERR_INVALID_PARAM; } if (old) old = &emulator.extPort->Connect( port, *old ); else return RESULT_ERR_OUT_OF_MEMORY; break; case PORT_3: case PORT_4: if (emulator.extPort->NumPorts() > 2) { if (emulator.extPort->GetDevice( port ).GetType() == type) { return RESULT_NOP; } else switch (type) { case UNCONNECTED: if (emulator.extPort->GetDevice( port == PORT_3 ? PORT_4 : PORT_3 ).GetType() == UNCONNECTED) { Core::Input::Adapter* const adapter = new (std::nothrow) Core::Input::AdapterTwo ( emulator.extPort->GetDevice(0), emulator.extPort->GetDevice(1), emulator.extPort->GetType() ); if (adapter == NULL) return RESULT_ERR_OUT_OF_MEMORY; for (uint i=2; i < 4; ++i) delete &emulator.extPort->GetDevice(i); delete emulator.extPort; emulator.extPort = adapter; } else if (NULL != (old = new (std::nothrow) Core::Input::Device( emulator.cpu ))) { old = &emulator.extPort->Connect( port, *old ); } else { return RESULT_ERR_OUT_OF_MEMORY; } break; case PAD1: case PAD2: case PAD3: case PAD4: if (NULL != (old = new (std::nothrow) Core::Input::Pad( emulator.cpu, uint(type) - PAD1 ))) { old = &emulator.extPort->Connect( port, *old ); } else { return RESULT_ERR_OUT_OF_MEMORY; } break; default: return RESULT_ERR_INVALID_PARAM; } } else { switch (type) { case UNCONNECTED: return RESULT_NOP; case PAD1: case PAD2: case PAD3: case PAD4: { Core::Input::Device* const devices[2] = { new (std::nothrow) Core::Input::Device( emulator.cpu ), new (std::nothrow) Core::Input::Pad( emulator.cpu, uint(type) - PAD1 ) }; Core::Input::Adapter* adapter; if ( devices[0] && devices[1] && NULL != ( adapter = new (std::nothrow) Core::Input::AdapterFour ( emulator.extPort->GetDevice(0), emulator.extPort->GetDevice(1), *devices[port == PORT_3], *devices[port != PORT_3], emulator.extPort->GetType() ) ) ) { delete emulator.extPort; emulator.extPort = adapter; } else { delete devices[0]; delete devices[1]; return RESULT_ERR_OUT_OF_MEMORY; } break; } default: return RESULT_ERR_INVALID_PARAM; } } break; case EXPANSION_PORT: if (emulator.expPort->GetType() == type) { return RESULT_NOP; } else switch (type) { case UNCONNECTED: old = new (std::nothrow) Core::Input::Device( emulator.cpu ); break; case PADDLE: old = new (std::nothrow) Core::Input::Paddle( emulator.cpu, true ); break; case FAMILYTRAINER: old = new (std::nothrow) Core::Input::FamilyTrainer( emulator.cpu ); break; case FAMILYKEYBOARD: old = new (std::nothrow) Core::Input::FamilyKeyboard( emulator.cpu, true ); break; case SUBORKEYBOARD: old = new (std::nothrow) Core::Input::SuborKeyboard( emulator.cpu ); break; case DOREMIKKOKEYBOARD: old = new (std::nothrow) Core::Input::DoremikkoKeyboard( emulator.cpu ); break; case HORITRACK: old = new (std::nothrow) Core::Input::HoriTrack( emulator.cpu ); break; case PACHINKO: old = new (std::nothrow) Core::Input::Pachinko( emulator.cpu ); break; case OEKAKIDSTABLET: old = new (std::nothrow) Core::Input::OekaKidsTablet( emulator.cpu ); break; case KONAMIHYPERSHOT: old = new (std::nothrow) Core::Input::KonamiHyperShot( emulator.cpu ); break; case BANDAIHYPERSHOT: old = new (std::nothrow) Core::Input::BandaiHyperShot( emulator.cpu, emulator.ppu ); break; case CRAZYCLIMBER: old = new (std::nothrow) Core::Input::CrazyClimber( emulator.cpu ); break; case MAHJONG: old = new (std::nothrow) Core::Input::Mahjong( emulator.cpu ); break; case EXCITINGBOXING: old = new (std::nothrow) Core::Input::ExcitingBoxing( emulator.cpu ); break; case TOPRIDER: old = new (std::nothrow) Core::Input::TopRider( emulator.cpu ); break; case POKKUNMOGURAA: old = new (std::nothrow) Core::Input::PokkunMoguraa( emulator.cpu ); break; case PARTYTAP: old = new (std::nothrow) Core::Input::PartyTap( emulator.cpu ); break; case TURBOFILE: old = new (std::nothrow) Core::Input::TurboFile( emulator.cpu ); break; case BARCODEWORLD: old = new (std::nothrow) Core::Input::BarcodeWorld( emulator.cpu ); break; default: return RESULT_ERR_INVALID_PARAM; } if (old) std::swap( old, emulator.expPort ); else return RESULT_ERR_OUT_OF_MEMORY; break; default: return RESULT_ERR_INVALID_PARAM; } delete old; emulator.InitializeInputDevices(); controllerCallback( port, type ); return RESULT_OK; } Result Input::ConnectAdapter(Adapter adapter) throw() { if (emulator.extPort->SetType( adapter )) { adapterCallback( adapter ); return RESULT_OK; } else { return RESULT_NOP; } } Result Input::AutoSelectController(uint port) throw() { if (port >= NUM_PORTS) return RESULT_ERR_INVALID_PARAM; Type type; if (emulator.image) { type = static_cast(emulator.image->GetDesiredController( port )); } else switch (port) { case PORT_1: type = PAD1; break; case PORT_2: type = PAD2; break; default: type = UNCONNECTED; break; } return ConnectController( port, type ); } Result Input::AutoSelectControllers() throw() { Result result = RESULT_NOP; for (uint i=0; i < NUM_PORTS; ++i) { const Result tmp = AutoSelectController( i ); if (result > tmp) result = tmp; } return result; } Result Input::AutoSelectAdapter() throw() { return ConnectAdapter( emulator.image ? static_cast(emulator.image->GetDesiredAdapter()) : ADAPTER_NES ); } Input::Type Input::GetConnectedController(uint port) const throw() { if (port == EXPANSION_PORT) return emulator.expPort->GetType(); if (port < emulator.extPort->NumPorts()) return emulator.extPort->GetDevice( port ).GetType(); return UNCONNECTED; } Input::Adapter Input::GetConnectedAdapter() const throw() { return emulator.extPort->GetType(); } bool Input::IsControllerConnected(Type type) const throw() { if (emulator.expPort->GetType() == type) return true; for (uint ports=emulator.extPort->NumPorts(), i=0; i < ports; ++i) { if (emulator.extPort->GetDevice(i).GetType() == type) return true; } return false; } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } nestopia-1.51.1/source/core/api/NstApiInput.hpp000066400000000000000000000455761411157722000213720ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_API_INPUT_H #define NST_API_INPUT_H #include "NstApi.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif #if NST_ICC >= 810 #pragma warning( push ) #pragma warning( disable : 304 444 ) #elif NST_MSVC >= 1200 #pragma warning( push ) #pragma warning( disable : 4512 ) #endif namespace Nes { namespace Core { namespace Input { enum { NUM_PADS = 4, NUM_CONTROLLERS = 27 }; class Controllers { template struct PollCaller1 : UserCallback { bool operator () (T& t) const { return this->function ? this->function( this->userdata, t ) : true; } }; template struct PollCaller2 : UserCallback { bool operator () (T& t,uint a) const { return this->function ? this->function( this->userdata, t, a ) : true; } }; template struct PollCaller3 : UserCallback { bool operator () (T& t,uint a,uint b) const { return this->function ? this->function( this->userdata, t, a, b ) : true; } }; public: Controllers() throw(); /** * Standard NES pad. */ struct Pad { enum { A = 0x01, B = 0x02, SELECT = 0x04, START = 0x08, UP = 0x10, DOWN = 0x20, LEFT = 0x40, RIGHT = 0x80 }; enum { MIC = 0x4 }; uint buttons; uint mic; uint allowSimulAxes; Pad() : buttons(0), mic(0), allowSimulAxes(false) {} typedef bool (NST_CALLBACK *PollCallback) (void*,Pad&,uint); static PollCaller2 callback; }; /** * Standard light gun. */ struct Zapper { uint x; uint y; uint fire; Zapper() : x(0), y(0), fire(0) {} typedef bool (NST_CALLBACK *PollCallback) (void*,Zapper&); static PollCaller1 callback; }; /** * Arkanoid controller. */ struct Paddle { uint x; uint button; Paddle() : x(0), button(0) {} typedef bool (NST_CALLBACK *PollCallback) (void*,Paddle&); static PollCaller1 callback; }; /** * Power Pad / Family Fun Fittness. */ struct PowerPad { PowerPad() throw(); enum { NUM_SIDE_A_BUTTONS = 12, NUM_SIDE_B_BUTTONS = 8 }; bool sideA[NUM_SIDE_A_BUTTONS]; bool sideB[NUM_SIDE_B_BUTTONS]; typedef bool (NST_CALLBACK *PollCallback) (void*,PowerPad&); static PollCaller1 callback; }; /** * Power Glove. */ struct PowerGlove { PowerGlove() throw(); enum { DISTANCE_IN = 1, DISTANCE_OUT = -1, ROLL_LEFT = -1, ROLL_RIGHT = 1 }; enum Gesture { GESTURE_OPEN = 0x00, GESTURE_FINGER = 0x0F, GESTURE_FIST = 0xFF }; enum { SELECT = 0x1, START = 0x2 }; uchar x; uchar y; schar distance; schar wrist; Gesture gesture; uint buttons; typedef bool (NST_CALLBACK *PollCallback) (void*,PowerGlove&); static PollCaller1 callback; }; /** * Mouse. */ struct Mouse { uint x; uint y; uint button; Mouse() : x(0), y(0), button(0) {} typedef bool (NST_CALLBACK *PollCallback) (void*,Mouse&); static PollCaller1 callback; }; /** * Family Trainer. */ struct FamilyTrainer { FamilyTrainer() throw(); enum { NUM_SIDE_A_BUTTONS = 12, NUM_SIDE_B_BUTTONS = 8 }; bool sideA[NUM_SIDE_A_BUTTONS]; bool sideB[NUM_SIDE_B_BUTTONS]; typedef bool (NST_CALLBACK *PollCallback) (void*,FamilyTrainer&); static PollCaller1 callback; }; /** * Family Keyboard. */ struct FamilyKeyboard { FamilyKeyboard() throw(); enum { NUM_PARTS = 9, NUM_MODES = 2 }; uchar parts[NUM_PARTS+3]; typedef bool (NST_CALLBACK *PollCallback) (void*,FamilyKeyboard&,uint,uint); static PollCaller3 callback; }; /** * Subor Keyboard. */ struct SuborKeyboard { SuborKeyboard() throw(); enum { NUM_PARTS = 10, NUM_MODES = 2 }; uchar parts[NUM_PARTS+2]; typedef bool (NST_CALLBACK *PollCallback) (void*,SuborKeyboard&,uint,uint); static PollCaller3 callback; }; /** * Doremikko Keyboard. */ struct DoremikkoKeyboard { enum { PART_1 = 1, PART_2 = 2, PART_3 = 3, PART_4 = 4, PART_5 = 5, PART_6 = 6, PART_7 = 7, MODE_A = 0, MODE_A_0 = 0x02, MODE_A_1 = 0x04, MODE_A_2 = 0x08, MODE_A_3 = 0x10, MODE_B = 1, MODE_B_0 = 0x02, MODE_B_1 = 0x04 }; uint keys; DoremikkoKeyboard() : keys(0) {} typedef bool (NST_CALLBACK *PollCallback) (void*,DoremikkoKeyboard&,uint,uint); static PollCaller3 callback; }; /** * Hori Track. */ struct HoriTrack { enum { BUTTON_A = Pad::A, BUTTON_B = Pad::B, BUTTON_SELECT = Pad::SELECT, BUTTON_START = Pad::START, BUTTON_UP = Pad::UP, BUTTON_DOWN = Pad::DOWN, BUTTON_LEFT = Pad::LEFT, BUTTON_RIGHT = Pad::RIGHT }; enum { MODE_REVERSED = 0x1, MODE_LOWSPEED = 0x2 }; uint x; uint y; uint buttons; uint mode; HoriTrack() : x(0), y(0), buttons(0), mode(0) {} typedef bool (NST_CALLBACK *PollCallback) (void*,HoriTrack&); static PollCaller1 callback; }; /** * Pachinko. */ struct Pachinko { enum { BUTTON_A = Pad::A, BUTTON_B = Pad::B, BUTTON_SELECT = Pad::SELECT, BUTTON_START = Pad::START, BUTTON_UP = Pad::UP, BUTTON_DOWN = Pad::DOWN, BUTTON_LEFT = Pad::LEFT, BUTTON_RIGHT = Pad::RIGHT }; enum { MIN_THROTTLE = -64, MAX_THROTTLE = +63 }; uint buttons; int throttle; Pachinko() : buttons(0), throttle(0) {} typedef bool (NST_CALLBACK *PollCallback) (void*,Pachinko&); static PollCaller1 callback; }; /** * VS System input. */ struct VsSystem { enum { COIN_1 = 0x20, COIN_2 = 0x40 }; uint insertCoin; VsSystem() : insertCoin(0) {} typedef bool (NST_CALLBACK *PollCallback) (void*,VsSystem&); static PollCaller1 callback; }; /** * Oeka Kids Tablet. */ struct OekaKidsTablet { uint x; uint y; uint button; OekaKidsTablet() : x(0), y(0), button(0) {} typedef bool (NST_CALLBACK *PollCallback) (void*,OekaKidsTablet&); static PollCaller1 callback; }; /** * Konami Hyper Shot. */ struct KonamiHyperShot { enum { PLAYER1_BUTTON_1 = 0x02, PLAYER1_BUTTON_2 = 0x04, PLAYER2_BUTTON_1 = 0x08, PLAYER2_BUTTON_2 = 0x10 }; uint buttons; KonamiHyperShot() : buttons(0) {} typedef bool (NST_CALLBACK *PollCallback) (void*,KonamiHyperShot&); static PollCaller1 callback; }; /** * Bandai Hyper Shot */ struct BandaiHyperShot { uint x; uint y; uint fire; uint move; BandaiHyperShot() : x(0), y(0), fire(0), move(0) {} typedef bool (NST_CALLBACK *PollCallback) (void*,BandaiHyperShot&); static PollCaller1 callback; }; /** * Crazy Climber. */ struct CrazyClimber { enum { RIGHT = 0x10, LEFT = 0x20, UP = 0x40, DOWN = 0x80 }; uint left; uint right; CrazyClimber() : left(0), right(0) {} typedef bool (NST_CALLBACK *PollCallback) (void*,CrazyClimber&); static PollCaller1 callback; }; /** * Mahjong. */ struct Mahjong { enum { PART_1 = 0x02, PART_1_I = 0x80, PART_1_J = 0x40, PART_1_K = 0x20, PART_1_L = 0x10, PART_1_M = 0x08, PART_1_N = 0x04, PART_2 = 0x04, PART_2_A = 0x80, PART_2_B = 0x40, PART_2_C = 0x20, PART_2_D = 0x10, PART_2_E = 0x08, PART_2_F = 0x04, PART_2_G = 0x02, PART_2_H = 0x01, PART_3 = 0x06, PART_3_START = 0x80, PART_3_SELECT = 0x40, PART_3_KAN = 0x20, PART_3_PON = 0x10, PART_3_CHI = 0x08, PART_3_REACH = 0x04, PART_3_RON = 0x02, NUM_PARTS = 3 }; uint buttons; Mahjong() : buttons(0) {} typedef bool (NST_CALLBACK *PollCallback) (void*,Mahjong&,uint); static PollCaller2 callback; }; /** * Konami Exciting Boxing. */ struct ExcitingBoxing { enum { PART_1 = 0x00, PART_1_RIGHT_HOOK = 0x10, PART_1_LEFT_MOVE = 0x08, PART_1_RIGHT_MOVE = 0x04, PART_1_LEFT_HOOK = 0x02, PART_2 = 0x02, PART_2_STRAIGHT = 0x10, PART_2_RIGHT_JAB = 0x08, PART_2_BODY = 0x04, PART_2_LEFT_JAB = 0x02, NUM_PARTS = 2 }; uint buttons; ExcitingBoxing() : buttons(0) {} typedef bool (NST_CALLBACK *PollCallback) (void*,ExcitingBoxing&,uint); static PollCaller2 callback; }; /** * Top Rider bike. */ struct TopRider { enum { BRAKE = 0x01, ACCEL = 0x02, SELECT = 0x04, START = 0x08, SHIFT_GEAR = 0x10, REAR = 0x20, STEER_LEFT = 0x40, STEER_RIGHT = 0x80 }; uint buttons; TopRider() : buttons(0) {} typedef bool (NST_CALLBACK *PollCallback) (void*,TopRider&); static PollCaller1 callback; }; /** * Pokkun Moguraa. */ struct PokkunMoguraa { enum { ROW_1 = 0x04, ROW_2 = 0x02, ROW_3 = 0x01, NUM_ROWS = 3, BUTTON_1 = 0x02, BUTTON_2 = 0x04, BUTTON_3 = 0x08, BUTTON_4 = 0x10 }; uint buttons; PokkunMoguraa() : buttons(0) {} typedef bool (NST_CALLBACK *PollCallback) (void*,PokkunMoguraa&,uint); static PollCaller2 callback; }; /** * Party Tap. */ struct PartyTap { enum { UNIT_1 = 0x04, UNIT_2 = 0x08, UNIT_3 = 0x10, UNIT_4 = 0x20, UNIT_5 = 0x40, UNIT_6 = 0x80 }; uint units; PartyTap() : units(0) {} typedef bool (NST_CALLBACK *PollCallback) (void*,PartyTap&); static PollCaller1 callback; }; /** * Bandai Karaoke Studio. */ struct KaraokeStudio { enum { A = 0x1, B = 0x2, MIC = 0x4 }; uint buttons; KaraokeStudio() : buttons(0) {} typedef bool (NST_CALLBACK *PollCallback) (void*,KaraokeStudio&); static PollCaller1 callback; }; Pad pad[NUM_PADS]; Zapper zapper; Paddle paddle; PowerPad powerPad; PowerGlove powerGlove; Mouse mouse; FamilyTrainer familyTrainer; FamilyKeyboard familyKeyboard; SuborKeyboard suborKeyboard; DoremikkoKeyboard doremikkoKeyboard; HoriTrack horiTrack; Pachinko pachinko; VsSystem vsSystem; OekaKidsTablet oekaKidsTablet; KonamiHyperShot konamiHyperShot; BandaiHyperShot bandaiHyperShot; CrazyClimber crazyClimber; Mahjong mahjong; ExcitingBoxing excitingBoxing; TopRider topRider; PokkunMoguraa pokkunMoguraa; PartyTap partyTap; KaraokeStudio karaokeStudio; }; } } namespace Api { /** * Controller input interface. */ class Input : public Base { struct ControllerCaller; struct AdapterCaller; public: /** * Interface constructor. * * @param instance emulator instance */ template Input(T& instance) : Base(instance) {} enum { NUM_CONTROLLERS = Core::Input::NUM_CONTROLLERS, NUM_PADS = Core::Input::NUM_PADS }; /** * Adapter type. */ enum Adapter { /** * NES adapter. */ ADAPTER_NES, /** * Famicom adapter. */ ADAPTER_FAMICOM }; /** * Controller type. */ enum Type { /** * Unconnected. */ UNCONNECTED, /** * Standard pad #1 */ PAD1, /** * Standard pad #2 */ PAD2, /** * Standard pad #3 */ PAD3, /** * Standard pad #4 */ PAD4, /** * Zapper. */ ZAPPER, /** * Arkanoid paddle. */ PADDLE, /** * Powerpad. */ POWERPAD, /** * Powerglove. */ POWERGLOVE, /** * Mouse. */ MOUSE, /** * R.O.B. */ ROB, /** * Family Trainer. */ FAMILYTRAINER, /** * Family keyboard. */ FAMILYKEYBOARD, /** * Subor keyboard. */ SUBORKEYBOARD, /** * Doremikko keyboard. */ DOREMIKKOKEYBOARD, /** * Horitrack. */ HORITRACK, /** * Pachinko. */ PACHINKO, /** * Oeka Kids tablet. */ OEKAKIDSTABLET, /** * Konami hypershot. */ KONAMIHYPERSHOT, /** * Bandai hypershot. */ BANDAIHYPERSHOT, /** * Crazy Climber. */ CRAZYCLIMBER, /** * Mahjong. */ MAHJONG, /** * Exciting Boxing. */ EXCITINGBOXING, /** * Top Rider bike. */ TOPRIDER, /** * Pokkun Moguraa. */ POKKUNMOGURAA, /** * Party Tap. */ PARTYTAP, /** * Turbo File. */ TURBOFILE, /** * Barcode World. */ BARCODEWORLD }; enum { PORT_1, PORT_2, PORT_3, PORT_4, EXPANSION_PORT, NUM_PORTS }; /** * Controllers context. */ typedef Core::Input::Controllers Controllers; /** * Connects the most suited controller for a game into a port. * * @param port controller port * @return result code */ Result AutoSelectController(uint port) throw(); /** * Connects the most suited controllers for a game into all ports. * * @return result code */ Result AutoSelectControllers() throw(); /** * Connects the most suited adapter for a game. */ Result AutoSelectAdapter() throw(); /** * Connects a controller to a port. * * @param port port * @param type controller * @result result code */ Result ConnectController(uint port,Type type) throw(); /** * Connects an adapter. * * @param type adapter * @return result code */ Result ConnectAdapter(Adapter type) throw(); /** * Returns the current connected controller. * * @param port port * @return controller */ Type GetConnectedController(uint port) const throw(); /** * Returns the current connected adapter. * * @return adapter */ Adapter GetConnectedAdapter() const throw(); /** * Checks if a specific controller is connected. * * @param type controller * @return true if connected */ bool IsControllerConnected(Type type) const throw(); /** * Controller event callback prototype. * * Will be invoked every time a new controller is connected to a port. * * @param userData optional user data * @param port port * @param type controller */ typedef void (NST_CALLBACK *ControllerCallback) (UserData userData,uint port,Type type); /** * Adapter event callback prototype. * * Will be invoked every time a new adapter is connected. * * @param userData optional user data * @param adapter adapter type */ typedef void (NST_CALLBACK *AdapterCallback) (UserData userData,Adapter adapter); /** * Controller event callback manager. * * Static object used for adding the user defined callback. */ static ControllerCaller controllerCallback; /** * Adapter event callback manager. * * Static object used for adding the user defined callback. */ static AdapterCaller adapterCallback; }; /** * Controller event callback invoker. * * Used internally by the core. */ struct Input::ControllerCaller : Core::UserCallback { void operator () (uint port,Type type) const { if (function) function( userdata, port, type ); } }; /** * Adapter event callback invoker. * * Used internally by the core. */ struct Input::AdapterCaller : Core::UserCallback { void operator () (Adapter adapter) const { if (function) function( userdata, adapter ); } }; } } #if NST_MSVC >= 1200 || NST_ICC >= 810 #pragma warning( pop ) #endif #endif nestopia-1.51.1/source/core/api/NstApiMachine.cpp000066400000000000000000000141561411157722000216200ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "../NstMachine.hpp" #include "../NstImage.hpp" #include "../NstState.hpp" #include "NstApiMachine.hpp" namespace Nes { namespace Api { Machine::EventCaller Machine::eventCallback; uint Machine::Is(uint a) const throw() { return emulator.Is( a ); } bool Machine::Is(uint a,uint b) const throw() { return emulator.Is( a, b ); } bool Machine::IsLocked() const { return emulator.tracker.IsLocked(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Result Machine::Load(std::istream& stream,FavoredSystem system,AskProfile ask,Patch* patch,uint type) { Result result; const bool on = Is(ON); try { result = emulator.Load ( stream, static_cast(system), ask == ASK_PROFILE, patch ? &patch->stream : NULL, patch ? patch->bypassChecksum : false, patch ? &patch->result : NULL, type ); } catch (Result r) { return r; } catch (const std::bad_alloc&) { return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { return RESULT_ERR_GENERIC; } if (on) Power( true ); return result; } Result Machine::Load(std::istream& stream,FavoredSystem system,AskProfile ask) throw() { return Load( stream, system, ask, NULL, Core::Image::UNKNOWN ); } Result Machine::Load(std::istream& stream,FavoredSystem system,Patch& patch,AskProfile ask) throw() { return Load( stream, system, ask, &patch, Core::Image::UNKNOWN ); } Result Machine::LoadCartridge(std::istream& stream,FavoredSystem system,AskProfile ask) throw() { return Load( stream, system, ask, NULL, Core::Image::CARTRIDGE ); } Result Machine::LoadCartridge(std::istream& stream,FavoredSystem system,Patch& patch,AskProfile ask) throw() { return Load( stream, system, ask, &patch, Core::Image::CARTRIDGE ); } Result Machine::LoadDisk(std::istream& stream,FavoredSystem system) throw() { return Load( stream, system, DONT_ASK_PROFILE, NULL, Core::Image::DISK ); } Result Machine::LoadSound(std::istream& stream,FavoredSystem system) throw() { return Load( stream, system, DONT_ASK_PROFILE, NULL, Core::Image::SOUND ); } Result Machine::Unload() throw() { if (!Is(IMAGE)) return RESULT_NOP; return emulator.Unload(); } Result Machine::Power(const bool on) throw() { if (on == bool(Is(ON))) return RESULT_NOP; if (on) { try { emulator.Reset( true ); } catch (Result result) { return result; } catch (const std::bad_alloc&) { return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { return RESULT_ERR_GENERIC; } return RESULT_OK; } else { return emulator.PowerOff(); } } Result Machine::Reset(const bool hard) throw() { if (!Is(ON) || IsLocked()) return RESULT_ERR_NOT_READY; try { emulator.Reset( hard ); } catch (Result result) { return result; } catch (const std::bad_alloc&) { return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { return RESULT_ERR_GENERIC; } return RESULT_OK; } Result Machine::SetRamPowerState(const uint state) throw() { emulator.SetRamPowerState(state); return RESULT_OK; } Machine::Mode Machine::GetMode() const throw() { return static_cast(Is(NTSC|PAL)); } Machine::Mode Machine::GetDesiredMode() const throw() { return (!emulator.image || emulator.image->GetDesiredRegion() == Core::REGION_NTSC) ? NTSC : PAL; } Result Machine::SetMode(const Mode mode) throw() { if (mode == GetMode()) return RESULT_NOP; Result result = Power( false ); if (NES_SUCCEEDED(result)) { emulator.SwitchMode(); if (result != RESULT_NOP) result = Power( true ); } return result; } Result Machine::LoadState(std::istream& stream) throw() { if (!Is(GAME,ON) || IsLocked()) return RESULT_ERR_NOT_READY; try { emulator.tracker.Resync(); Core::State::Loader loader( &stream, true ); if (emulator.LoadState( loader, true )) return RESULT_OK; else return RESULT_ERR_INVALID_CRC; } catch (Result result) { return result; } catch (const std::bad_alloc&) { return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { return RESULT_ERR_GENERIC; } } Result Machine::SaveState(std::ostream& stream,Compression compression) const throw() { if (!Is(GAME,ON)) return RESULT_ERR_NOT_READY; try { Core::State::Saver saver( &stream, compression != NO_COMPRESSION, false ); emulator.SaveState( saver ); } catch (Result result) { return result; } catch (const std::bad_alloc&) { return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { return RESULT_ERR_GENERIC; } return RESULT_OK; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } nestopia-1.51.1/source/core/api/NstApiMachine.hpp000066400000000000000000000252111411157722000216170ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_API_MACHINE_H #define NST_API_MACHINE_H #include #include "NstApi.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif #if NST_ICC >= 810 #pragma warning( push ) #pragma warning( disable : 444 ) #elif NST_MSVC >= 1200 #pragma warning( push ) #pragma warning( disable : 4512 ) #endif namespace Nes { namespace Api { /** * Machine interface. */ class Machine : public Base { struct EventCaller; public: /** * Interface constructor. * * @param instance emulator instance */ template Machine(T& instance) : Base(instance) {} enum { ON = 0x001, VS = 0x010, PC10 = 0x020, CARTRIDGE = 0x040, DISK = 0x080, SOUND = 0x100, GAME = CARTRIDGE|DISK, IMAGE = GAME|SOUND }; /** * NTSC/PAL mode. */ enum Mode { /** * NTSC. */ NTSC = 0x04, /** * PAL. */ PAL = 0x08 }; /** * Favored System. * * Used for telling what console to emulate if the core can't decide by itself. */ enum FavoredSystem { /** * NES NTSC. */ FAVORED_NES_NTSC = Core::FAVORED_NES_NTSC, /** * NES PAL. */ FAVORED_NES_PAL = Core::FAVORED_NES_PAL, /** * Famicom. */ FAVORED_FAMICOM = Core::FAVORED_FAMICOM, /** * Dendy (clone). */ FAVORED_DENDY = Core::FAVORED_DENDY }; /** * Image profile questioning state. * * Used for allowing callback triggering if an image has multiple media profiles. */ enum AskProfile { /** * Don't trigger callback (default). */ DONT_ASK_PROFILE, /** * Trigger callback. */ ASK_PROFILE }; enum { CLK_NTSC_DOT = Core::CLK_NTSC, CLK_NTSC_DIV = Core::CLK_NTSC_DIV, CLK_NTSC_VSYNC = Core::PPU_RP2C02_HVSYNC * ulong(Core::CLK_NTSC_DIV), CLK_PAL_DOT = Core::CLK_PAL, CLK_PAL_DIV = Core::CLK_PAL_DIV, CLK_PAL_VSYNC = Core::PPU_RP2C07_HVSYNC * ulong(Core::CLK_PAL_DIV) }; /** * Soft-patching context object. * * Used as input parameter to some of the image loading methods. */ struct Patch { /** * Input stream containing the patch in UPS or IPS format. */ std::istream& stream; /** * Set to true to bypass checksum validation. */ bool bypassChecksum; /** * Will contain the result of the operation after the image has been loaded. */ Result result; /** * Constructor. * * @param s input stream * @param b true to bypass checksum validation, default is false */ Patch(std::istream& s,bool b=false) : stream(s), bypassChecksum(b), result(RESULT_NOP) {} }; /** * Loads any image. Input stream can be in XML, iNES, UNIF, FDS or NSF format. * * @param stream input stream containing the image to load * @param system console to emulate if the core can't do automatic detection * @param askProfile to allow callback triggering if the image has multiple media profiles, default is false * @return result code */ Result Load(std::istream& stream,FavoredSystem system,AskProfile askProfile=DONT_ASK_PROFILE) throw(); /** * Loads any image. Input stream can be in XML, iNES, UNIF, FDS or NSF format. * * @param stream input stream containing the image to load * @param system console to emulate if the core can't do automatic detection * @param patch object for performing soft-patching on the image * @param askProfile to allow callback triggering if the image has multiple media profiles, default is false * @return result code */ Result Load(std::istream& stream,FavoredSystem system,Patch& patch,AskProfile askProfile=DONT_ASK_PROFILE) throw(); /** * Loads a cartridge image. Input stream can be in XML, iNES or UNIF format. * * @param stream input stream containing the image to load * @param system console to emulate if the core can't do automatic detection * @param askProfile to allow callback triggering if the image has multiple media profiles, default is false * @return result code */ Result LoadCartridge(std::istream& stream,FavoredSystem system,AskProfile askProfile=DONT_ASK_PROFILE) throw(); /** * Loads a cartridge image. Input stream can be in XML, iNES or UNIF format. * * @param stream input stream containing the image to load * @param system console to emulate if the core can't do automatic detection * @param patch object for performing soft-patching on the image * @param askProfile to allow callback triggering if the image has multiple media profiles, default is false * @return result code */ Result LoadCartridge(std::istream& stream,FavoredSystem system,Patch& patch,AskProfile askProfile=DONT_ASK_PROFILE) throw(); /** * Loads a Famicom Disk System image. Input stream can be in FDS format. * * @param stream input stream containing the image to load * @param system console to emulate if the core can't do automatic detection * @return result code */ Result LoadDisk(std::istream& stream,FavoredSystem system) throw(); /** * Loads a sound image. Input stream can be in NSF format. * * @param stream input stream containing the image to load * @param system console to emulate if the core can't do automatic detection * @return result code */ Result LoadSound(std::istream& stream,FavoredSystem system) throw(); /** * Unloads the current image. * * @return result code */ Result Unload() throw(); /** * Powers ON or OFF the machine. * * @param state ON if true * @return result code */ Result Power(bool state) throw(); /** * Resets the machine. * * @param state hard-reset if true, soft-reset otherwise * @return result code */ Result Reset(bool state) throw(); /** * Sets the RAM's power state. * * @param power-up state * @return result code */ Result SetRamPowerState(uint state) throw(); /** * Returns the current mode. * * @return mode */ Mode GetMode() const throw(); /** * Returns the mode most appropriate for the current image. * * @return mode */ Mode GetDesiredMode() const throw(); /** * Sets the mode. * * @param mode new mode * @return result code */ Result SetMode(Mode mode) throw(); /** * Internal compression on states. */ enum Compression { /** * No compression. */ NO_COMPRESSION, /** * Compression enabled (default). */ USE_COMPRESSION }; /** * Loads a state. * * @param stream input stream containing the state * @return result code */ Result LoadState(std::istream& stream) throw(); /** * Saves a state. * * @param stream output stream which the state will be written to * @param compression to allow internal compression in the state, default is USE_COMPRESSION * @return result code */ Result SaveState(std::ostream& stream,Compression compression=USE_COMPRESSION) const throw(); /** * Returns a machine state. * * @param flags OR:ed flags to check * @return OR:ed flags evaluated to true */ uint Is(uint flags) const throw(); /** * Returns a machine state. * * @param flags1 OR:ed flags to check * @param flags2 OR:ed flags to check * @return true if both parameters has at least one flag evaluated to true */ bool Is(uint flags1,uint flags2) const throw(); /** * Tells if the machine is in a locked state. * * A locked state means that the machine can't respond to * certain operations because it's doing something special, * like playing a movie or rewinding. * * @return true if machine is in a locked state. */ bool IsLocked() const; /** * Machine events. */ enum Event { /** * A new image has been loaded into the system. */ EVENT_LOAD, /** * An image has been unloaded from the system. */ EVENT_UNLOAD, /** * Machine power ON. */ EVENT_POWER_ON, /** * Machine power OFF. */ EVENT_POWER_OFF, /** * Machine soft-reset. */ EVENT_RESET_SOFT, /** * Machine hard-reset. */ EVENT_RESET_HARD, /** * Mode has changed to NTSC. */ EVENT_MODE_NTSC, /** * Mode has changed to PAL. */ EVENT_MODE_PAL }; enum { NUM_EVENT_CALLBACKS = 8 }; /** * Machine event callback prototype. * * @param userData optional user data * @param event the event * @param result result code of event operation, in success or warning state */ typedef void (NST_CALLBACK *EventCallback) (UserData userData,Event event,Result result); /** * Machine event callback manager. * * Static object used for adding the user defined callback. */ static EventCaller eventCallback; private: Result Load(std::istream&,FavoredSystem,AskProfile,Patch*,uint); }; /** * Machine event callback invoker. * * Used internally by the core. */ struct Machine::EventCaller : Core::UserCallback { void operator () (Event event,Result result=RESULT_OK) const { if (function) function( userdata, event, result ); } }; } } #if NST_MSVC >= 1200 || NST_ICC >= 810 #pragma warning( pop ) #endif #endif nestopia-1.51.1/source/core/api/NstApiMovie.cpp000066400000000000000000000040041411157722000213220ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstMachine.hpp" #include "NstApiTapeRecorder.hpp" #include "NstApiMovie.hpp" namespace Nes { namespace Api { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Movie::EventCaller Movie::eventCallback; Result Movie::Play(std::istream& stream) throw() { Api::TapeRecorder(emulator).Stop(); return emulator.tracker.PlayMovie( emulator, stream ); } Result Movie::Record(std::iostream& stream,How how) throw() { return emulator.tracker.RecordMovie( emulator, stream, how == APPEND ); } void Movie::Stop() throw() { emulator.tracker.StopMovie(); } bool Movie::IsPlaying() const throw() { return emulator.tracker.IsMoviePlaying(); } bool Movie::IsRecording() const throw() { return emulator.tracker.IsMovieRecording(); } bool Movie::IsStopped() const throw() { return !IsPlaying() && !IsRecording(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } nestopia-1.51.1/source/core/api/NstApiMovie.hpp000066400000000000000000000100541411157722000213310ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_API_MOVIE_H #define NST_API_MOVIE_H #include #include "NstApi.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif #if NST_ICC >= 810 #pragma warning( push ) #pragma warning( disable : 304 444 ) #elif NST_MSVC >= 1200 #pragma warning( push ) #pragma warning( disable : 4512 ) #endif namespace Nes { namespace Api { /** * Movie playing/recording interface. */ class Movie : public Base { struct EventCaller; public: /** * Interface constructor. * * @param instance emulator instance */ template Movie(T& instance) : Base(instance) {} /** * Recording procedure. */ enum How { /** * Overwrite any previous content. */ CLEAN, /** * Keep any previous content. */ APPEND }; /** * Plays movie. * * @param stream input stream to movie * @return result code */ Result Play(std::istream& stream) throw(); /** * Records movie. * * @param stream stream to record movie to * @param how CLEAN to erase any previous content, APPEND to keep content, default is CLEAN * @return result code */ Result Record(std::iostream& stream,How how=CLEAN) throw(); /** * Stops movie. */ void Stop() throw(); /** * Ejects movie. * * @deprecated */ void Eject() {} /** * Checks if a movie is being played. * * @return true if playing */ bool IsPlaying() const throw(); /** * Checks if a movie is being recorded. * * @return true if recording */ bool IsRecording() const throw(); /** * Checks if a movie has stopped playing or recording. * * @return true if stopped */ bool IsStopped() const throw(); /** * Movie event. */ enum Event { /** * Movie has started playing. */ EVENT_PLAYING, /** * Movie has stopped playing. */ EVENT_PLAYING_STOPPED, /** * Movie has started recording. */ EVENT_RECORDING, /** * Movie has stopped recording. */ EVENT_RECORDING_STOPPED }; enum { NUM_EVENT_CALLBACKS = 4 }; /** * Movie event callback prototype. * * @param userData optional user data * @param event type of event * @param result result code of event */ typedef void (NST_CALLBACK *EventCallback) (UserData userData,Event event,Result result); /** * Movie event callback manager. * * Static object used for adding the user defined callback. */ static EventCaller eventCallback; }; /** * Movie event callback invoker. * * Used internally by the core. */ struct Movie::EventCaller : Core::UserCallback { void operator () (Event event,Result result=RESULT_OK) const { if (function) function( userdata, event, result ); } }; } } #if NST_MSVC >= 1200 || NST_ICC >= 810 #pragma warning( pop ) #endif #endif nestopia-1.51.1/source/core/api/NstApiNsf.cpp000066400000000000000000000114541411157722000210000ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstMachine.hpp" #include "../NstNsf.hpp" #include "NstApiMachine.hpp" #include "NstApiNsf.hpp" namespace Nes { namespace Api { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Nsf::EventCaller Nsf::eventCallback; const char* Nsf::GetName() const throw() { if (emulator.Is(Machine::SOUND)) return static_cast(emulator.image)->GetName(); return ""; } const char* Nsf::GetArtist() const throw() { if (emulator.Is(Machine::SOUND)) return static_cast(emulator.image)->GetArtist(); return ""; } const char* Nsf::GetCopyright() const throw() { if (emulator.Is(Machine::SOUND)) return static_cast(emulator.image)->GetCopyright(); return ""; } uint Nsf::GetChips() const throw() { if (emulator.Is(Machine::SOUND)) return static_cast(emulator.image)->GetChips(); return 0; } Nsf::TuneMode Nsf::GetMode() const throw() { if (emulator.Is(Machine::SOUND)) return static_cast(static_cast(emulator.image)->GetTuneMode()); return TUNE_MODE_NTSC; } uint Nsf::GetNumSongs() const throw() { if (emulator.Is(Machine::SOUND)) return static_cast(emulator.image)->NumSongs(); return 0; } int Nsf::GetCurrentSong() const throw() { if (emulator.Is(Machine::SOUND)) return static_cast(emulator.image)->CurrentSong(); return NO_SONG; } int Nsf::GetStartingSong() const throw() { if (emulator.Is(Machine::SOUND)) return static_cast(emulator.image)->StartingSong(); return NO_SONG; } uint Nsf::GetInitAddress() const throw() { if (emulator.Is(Machine::SOUND)) return static_cast(emulator.image)->GetInitAddress(); return 0x0000; } uint Nsf::GetLoadAddress() const throw() { if (emulator.Is(Machine::SOUND)) return static_cast(emulator.image)->GetLoadAddress(); return 0x0000; } uint Nsf::GetPlayAddress() const throw() { if (emulator.Is(Machine::SOUND)) return static_cast(emulator.image)->GetPlayAddress(); return 0x0000; } Result Nsf::SelectSong(uint song) throw() { if (emulator.Is(Machine::SOUND)) return static_cast(emulator.image)->SelectSong( song ); return RESULT_ERR_NOT_READY; } Result Nsf::PlaySong() throw() { if (emulator.Is(Machine::SOUND)) return static_cast(emulator.image)->PlaySong(); return RESULT_ERR_NOT_READY; } Result Nsf::StopSong() throw() { if (emulator.Is(Machine::SOUND)) return static_cast(emulator.image)->StopSong(); return RESULT_ERR_NOT_READY; } Result Nsf::SelectNextSong() throw() { if (emulator.Is(Machine::SOUND)) { return static_cast(emulator.image)->SelectSong ( static_cast(emulator.image)->CurrentSong() + 1U ); } return RESULT_ERR_NOT_READY; } Result Nsf::SelectPrevSong() throw() { if (emulator.Is(Machine::SOUND)) { return static_cast(emulator.image)->SelectSong ( static_cast(emulator.image)->CurrentSong() - 1U ); } return RESULT_ERR_NOT_READY; } bool Nsf::IsPlaying() const throw() { return emulator.Is(Machine::SOUND) && static_cast(emulator.image)->IsPlaying(); } bool Nsf::UsesBankSwitching() const throw() { return emulator.Is(Machine::SOUND) && static_cast(emulator.image)->UsesBankSwitching(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } nestopia-1.51.1/source/core/api/NstApiNsf.hpp000066400000000000000000000127741411157722000210130ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_API_NSF_H #define NST_API_NSF_H #include "NstApi.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif #if NST_ICC >= 810 #pragma warning( push ) #pragma warning( disable : 444 ) #elif NST_MSVC >= 1200 #pragma warning( push ) #pragma warning( disable : 4512 ) #endif namespace Nes { namespace Api { /** * NES Sound Files interface. */ class Nsf : public Base { struct EventCaller; public: /** * Interface constructor. * * @param instance emulator instance */ template Nsf(T& instance) : Base(instance) {} enum { NO_SONG = -1 }; /** * Tune mode. */ enum TuneMode { /** * NTSC only. */ TUNE_MODE_NTSC, /** * PAL only. */ TUNE_MODE_PAL, /** * Both NTSC and PAL. */ TUNE_MODE_BOTH }; enum { CHIP_VRC6 = 0x01, CHIP_VRC7 = 0x02, CHIP_FDS = 0x04, CHIP_MMC5 = 0x08, CHIP_N163 = 0x10, CHIP_S5B = 0x20, CHIP_ALL = 0x3F }; /** * Returns the name of the NSF. * * @return name or empty string if NSF hasn't been loaded */ const char* GetName() const throw(); /** * Returns the name of the artists. * * @return artist names or empty string if NSF hasn't been loaded */ const char* GetArtist() const throw(); /** * Returns the copyright string. * * @return copyright or empty string if NSF hasn't been loaded */ const char* GetCopyright() const throw(); /** * Return the tune mode. * * @return tune mode */ TuneMode GetMode() const throw(); /** * Returns the init-address. * * @return address */ uint GetInitAddress() const throw(); /** * Returns the load-address. * * @return address */ uint GetLoadAddress() const throw(); /** * Returns the play-address. * * @return address */ uint GetPlayAddress() const throw(); /** * Returns the total number of songs. * * @return number */ uint GetNumSongs() const throw(); /** * Returns the current song index. * * @return song index or NO_SONG if NSF hasn't been loaded */ int GetCurrentSong() const throw(); /** * Returns the starting song index. * * @return song index or NO_SONG if NSF hasn't been loaded */ int GetStartingSong() const throw(); /** * Returns the OR:ed chips in use. * * @return OR:ed chips used */ uint GetChips() const throw(); /** * Checks if a song is currently being played. * * @return true if playing */ bool IsPlaying() const throw(); /** * Checks if the NSF uses bank-switching. * * @return true if NSF uses bank-switching */ bool UsesBankSwitching() const throw(); /** * Selects a song. * * @param song index * @return result code */ Result SelectSong(uint song) throw(); /** * Selects the next song. * * @return result code */ Result SelectNextSong() throw(); /** * Selects the previous song. * * @return result code */ Result SelectPrevSong() throw(); /** * Plays current selected song. * * @return result code */ Result PlaySong() throw(); /** * Stops current selected song. * * @return result code */ Result StopSong() throw(); /** * Event. */ enum Event { /** * A new song has been selected. */ EVENT_SELECT_SONG, /* * Song has started playing. */ EVENT_PLAY_SONG, /** * Song has stopped playing. */ EVENT_STOP_SONG }; enum { NUM_EVENT_CALLBACKS = 3 }; /** * Event callback prototype. * * @param userData optional user data * @param event type of event */ typedef void (NST_CALLBACK *EventCallback) (UserData userData,Event event); /** * Event callback manager. * * Static object used for adding the user defined callback. */ static EventCaller eventCallback; }; /** * Song event callback invoker. * * Used internally by the core. */ struct Nsf::EventCaller : Core::UserCallback { void operator () (Event event) const { if (function) function( userdata, event ); } }; } } #if NST_MSVC >= 1200 || NST_ICC >= 810 #pragma warning( pop ) #endif #endif nestopia-1.51.1/source/core/api/NstApiRewinder.cpp000066400000000000000000000051201411157722000220220ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "../NstMachine.hpp" #include "NstApiMachine.hpp" #include "NstApiRewinder.hpp" namespace Nes { namespace Api { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Rewinder::StateCaller Rewinder::stateCallback; Result Rewinder::Enable(bool enable) throw() { try { return emulator.tracker.EnableRewinder( enable ? &emulator : NULL ); } catch (Result result) { return result; } catch (const std::bad_alloc&) { return RESULT_ERR_OUT_OF_MEMORY; } catch (...) { return RESULT_ERR_GENERIC; } } bool Rewinder::IsEnabled() const throw() { return emulator.tracker.IsRewinderEnabled(); } bool Rewinder::IsSoundEnabled() const throw() { return emulator.tracker.IsRewinderSoundEnabled(); } void Rewinder::EnableSound(bool enable) throw() { emulator.tracker.EnableRewinderSound( enable ); } Rewinder::Direction Rewinder::GetDirection() const throw() { return emulator.tracker.IsRewinding() ? BACKWARD : FORWARD; } Result Rewinder::SetDirection(Direction dir) throw() { if (emulator.Is(Machine::GAME,Machine::ON)) { if (dir == BACKWARD) return emulator.tracker.StartRewinding(); else return emulator.tracker.StopRewinding(); } return RESULT_ERR_NOT_READY; } void Rewinder::Reset() throw() { if (emulator.Is(Machine::GAME,Machine::ON)) emulator.tracker.ResetRewinder(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } nestopia-1.51.1/source/core/api/NstApiRewinder.hpp000066400000000000000000000073751411157722000220450ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_API_REWINDER_H #define NST_API_REWINDER_H #include "NstApi.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif #if NST_ICC >= 810 #pragma warning( push ) #pragma warning( disable : 304 444 ) #elif NST_MSVC >= 1200 #pragma warning( push ) #pragma warning( disable : 4512 ) #endif namespace Nes { namespace Api { /** * Game rewinder interface. */ class Rewinder : public Base { struct StateCaller; public: /** * Interface constructor. * * @param instance emulator instance */ template Rewinder(T& instance) : Base(instance) {} /** * Direction. */ enum Direction { /** * Forward. */ FORWARD, /** * Backward. */ BACKWARD }; /** * Enables rewinder. * * @param state true to enable * @return result code */ Result Enable(bool state=true) throw(); /** * Checks if rewinder is enabled. * * @return true if enabled */ bool IsEnabled() const throw(); /** * Resets rewinder. */ void Reset() throw(); /** * Enables backward sound. * * @param state true to enable */ void EnableSound(bool state=true) throw(); /** * Checks if backward sound is enabled. * * @return true if enabled */ bool IsSoundEnabled() const throw(); /** * Sets direction. * * @param direction direction, FORWARD or BACKWARD * @return result code */ Result SetDirection(Direction direction) throw(); /** * Returns the current direction. * * @return current direction */ Direction GetDirection() const throw(); /** * Rewinder state. */ enum State { /** * Rewinding has stopped. */ STOPPED, /** * Rewinding will soon start. */ PREPARING, /** * Rewinding has begun. */ REWINDING }; enum { NUM_STATE_CALLBACKS = 3 }; /** * Rewinder state callback prototype. * * @param userData optional user data * @param state type of state */ typedef void (NST_CALLBACK *StateCallback) (UserData userData,State state); /** * Rewinder state callback manager. * * Static object used for adding the user defined callback. */ static StateCaller stateCallback; }; /** * Rewinder state callback invoker. * * Used internally by the core. */ struct Rewinder::StateCaller : Core::UserCallback { void operator () (State state) const { if (function) function( userdata, state ); } }; } } #if NST_MSVC >= 1200 || NST_ICC >= 810 #pragma warning( pop ) #endif #endif nestopia-1.51.1/source/core/api/NstApiSound.cpp000066400000000000000000000102311411157722000213320ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstMachine.hpp" #include "NstApiSound.hpp" namespace Nes { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif namespace Core { namespace Sound { Output::Locker Output::lockCallback; Output::Unlocker Output::unlockCallback; } } namespace Api { NST_COMPILE_ASSERT ( Sound::CHANNEL_SQUARE1 == 1U << Core::Apu::Channel::APU_SQUARE1 && Sound::CHANNEL_SQUARE2 == 1U << Core::Apu::Channel::APU_SQUARE2 && Sound::CHANNEL_TRIANGLE == 1U << Core::Apu::Channel::APU_TRIANGLE && Sound::CHANNEL_NOISE == 1U << Core::Apu::Channel::APU_NOISE && Sound::CHANNEL_DPCM == 1U << Core::Apu::Channel::APU_DPCM && Sound::CHANNEL_FDS == 1U << Core::Apu::Channel::EXT_FDS && Sound::CHANNEL_MMC5 == 1U << Core::Apu::Channel::EXT_MMC5 && Sound::CHANNEL_VRC6 == 1U << Core::Apu::Channel::EXT_VRC6 && Sound::CHANNEL_VRC7 == 1U << Core::Apu::Channel::EXT_VRC7 && Sound::CHANNEL_N163 == 1U << Core::Apu::Channel::EXT_N163 && Sound::CHANNEL_S5B == 1U << Core::Apu::Channel::EXT_S5B ); Result Sound::SetSampleRate(ulong rate) throw() { return emulator.cpu.GetApu().SetSampleRate( rate ); } Result Sound::SetSampleBits(uint bits) throw() { return emulator.cpu.GetApu().SetSampleBits( bits ); } Result Sound::SetVolume(uint channels,uint volume) throw() { return emulator.cpu.GetApu().SetVolume( channels, volume ); } Result Sound::SetSpeed(uint speed) throw() { return emulator.cpu.GetApu().SetSpeed( speed ); } void Sound::SetAutoTranspose(bool enable) throw() { emulator.cpu.GetApu().SetAutoTranspose( enable ); } void Sound::SetGenie(bool enable) throw() { emulator.cpu.GetApu().SetGenie( enable ); } void Sound::SetSpeaker(Speaker speaker) throw() { emulator.cpu.GetApu().EnableStereo( speaker == SPEAKER_STEREO ); } ulong Sound::GetSampleRate() const throw() { return emulator.cpu.GetApu().GetSampleRate(); } uint Sound::GetSampleBits() const throw() { return emulator.cpu.GetApu().GetSampleBits(); } uint Sound::GetVolume(uint channel) const throw() { return emulator.cpu.GetApu().GetVolume( channel ); } uint Sound::GetSpeed() const throw() { return emulator.cpu.GetApu().GetSpeed(); } void Sound::Mute(bool mute) throw() { emulator.cpu.GetApu().Mute( mute ); } bool Sound::IsMuted() const throw() { return emulator.cpu.GetApu().IsMuted(); } bool Sound::IsAudible() const throw() { return emulator.cpu.GetApu().IsAudible(); } bool Sound::IsAutoTransposing() const throw() { return emulator.cpu.GetApu().IsAutoTransposing(); } bool Sound::IsGenie() const throw() { return emulator.cpu.GetApu().IsGenie(); } Sound::Speaker Sound::GetSpeaker() const throw() { return emulator.cpu.GetApu().InStereo() ? SPEAKER_STEREO : SPEAKER_MONO; } void Sound::EmptyBuffer() throw() { emulator.cpu.GetApu().ClearBuffers(); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } nestopia-1.51.1/source/core/api/NstApiSound.hpp000066400000000000000000000213131411157722000213420ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_API_SOUND_H #define NST_API_SOUND_H #include "NstApi.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif #if NST_ICC >= 810 #pragma warning( push ) #pragma warning( disable : 304 444 ) #elif NST_MSVC >= 1200 #pragma warning( push ) #pragma warning( disable : 4512 ) #endif namespace Nes { namespace Core { namespace Sound { /** * Sound output context. */ class Output { struct Locker; struct Unlocker; public: enum { MAX_LENGTH = 0x8000 }; /** * Pointer to sound memory to be written to. * * Assign NULL to samples[1] if circular buffers aren't needed. */ void* samples[2]; /** * Length in number of samples for one frame. * * Assign 0 to length[1] if circular buffers aren't needed. * Length doesn't neccesarily need to be the same value for every frame as long * as they eventually add up in relation to the emulation speed. The requested * number of samples will always be written even if the length is greater * than what the sound engine normally produces. Non-written samples for one frame will * be carried over to the next through an internal buffer. */ uint length[2]; Output(void* s0=0,uint l0=0,void* s1=0,uint l1=0) { samples[0] = s0; samples[1] = s1; length[0] = l0; length[1] = l1; } /** * Sound lock callback prototype. * * Called right before the core is about to render sound for one frame. Non-written * samples will be saved for the next frame. * * @param userData optional user data * @param output object to this class * @return true if output memory is valid and samples can be written to it */ typedef bool (NST_CALLBACK *LockCallback) (void* userData,Output& output); /** * Sound unlock callback prototype. * * Called when the core has finished rendering sound for one frame and a previously lock was made. * * @param userData optional user data * @param output object to this class */ typedef void (NST_CALLBACK *UnlockCallback) (void* userData,Output& output); /** * Sound lock callback manager. * * Static object used for adding the user defined callback. */ static Locker lockCallback; /** * Sound unlock callback manager. * * Static object used for adding the user defined callback. */ static Unlocker unlockCallback; }; /** * Sound lock callback invoker. * * Used internally by the core. */ struct Output::Locker : UserCallback { bool operator () (Output& output) const { return (!function || function( userdata, output )); } }; /** * Sound unlock callback invoker. * * Used internally by the core. */ struct Output::Unlocker : UserCallback { void operator () (Output& output) const { if (function) function( userdata, output ); } }; } } namespace Api { /** * Sound interface. */ class Sound : public Base { public: /** * Interface constructor. * * @param instance emulator instance */ template Sound(T& instance) : Base(instance) {} /** * Sound channel types. */ enum Channel { /** * First square channel. */ CHANNEL_SQUARE1 = 0x001, /** * Second square channel. */ CHANNEL_SQUARE2 = 0x002, /** * Triangle channel. */ CHANNEL_TRIANGLE = 0x004, /** * Noise channel. */ CHANNEL_NOISE = 0x008, /** * DPCM channel. */ CHANNEL_DPCM = 0x010, /** * FDS sound chip channel. */ CHANNEL_FDS = 0x020, /** * MMC5 sound chip channel. */ CHANNEL_MMC5 = 0x040, /** * Konami VRC6 sound chip channel. */ CHANNEL_VRC6 = 0x080, /** * Konami VRC7 sound chip channel. */ CHANNEL_VRC7 = 0x100, /** * Namcot 163 sound chip channel. */ CHANNEL_N163 = 0x200, /** * Sunsoft 5B sound chip channel. */ CHANNEL_S5B = 0x400, /** * All NES APU channels. */ APU_CHANNELS = CHANNEL_SQUARE1|CHANNEL_SQUARE2|CHANNEL_TRIANGLE|CHANNEL_NOISE|CHANNEL_DPCM, /** * All external sound chip channels. */ EXT_CHANNELS = CHANNEL_FDS|CHANNEL_MMC5|CHANNEL_VRC6|CHANNEL_VRC7|CHANNEL_N163|CHANNEL_S5B, /** * All channels. */ ALL_CHANNELS = APU_CHANNELS|EXT_CHANNELS }; /** * Speaker type. */ enum Speaker { /** * Mono sound (default). */ SPEAKER_MONO, /** * Pseudo stereo sound. */ SPEAKER_STEREO }; enum { DEFAULT_VOLUME = 85, MAX_VOLUME = 100, DEFAULT_SPEED = 0, MIN_SPEED = 30, MAX_SPEED = 240, MAX_CHANNELS = 11 }; /** * Sets the sample rate. * * @param rate value in the range 11025 to 96000, default is 44100 * @return result code */ Result SetSampleRate(ulong rate) throw(); /** * Returns the sample rate. * * @return sample rate */ ulong GetSampleRate() const throw(); /** * Sets the sample bits. * * @param bits value of 8 or 16, default is 16 * @return result code */ Result SetSampleBits(uint bits) throw(); /** * Returns the sample bits. * * @return number */ uint GetSampleBits() const throw(); /** * Sets the speaker type. * * @param speaker speaker type, default is SPEAKER_MONO */ void SetSpeaker(Speaker speaker) throw(); /** * Returns the speaker type. * * @return speaker type */ Speaker GetSpeaker() const throw(); /** * Sets one or more channel volumes. * * @param channels OR:ed channels * @param volume volume in the range 0 to 100, default is 85 * @return result code */ Result SetVolume(uint channels,uint volume) throw(); /** * Returns the volume of a channel. * * @param channel channel * @return volume */ uint GetVolume(uint channel) const throw(); /** * Mutes all sound. * * @param mute true to mute sound */ void Mute(bool mute) throw(); /** * Checks if sound is muted. * * @return true if muted */ bool IsMuted() const throw(); /** * Sets the speed. * * @param speed speed in the range 30 to 240, set to DEFAULT_SPEED for automatic adjustment * @return result code */ Result SetSpeed(uint speed) throw(); /** * Returns the current speed. * * @return speed */ uint GetSpeed() const throw(); /** * Enables automatic transposition. * * @param state true to enable */ void SetAutoTranspose(bool state) throw(); /** * Enables the "Game Genie" sound effect * * @param genie true to enable */ void SetGenie(bool genie) throw(); /** * Checks if automatic transposing is enabled. * * @return true if enabled */ bool IsAutoTransposing() const throw(); /** * Checks if a "Game Genie" is present * * @return true if enabled */ bool IsGenie() const throw(); /** * Checks if sound is audible at all. * * @return true if audible */ bool IsAudible() const throw(); /** * Empties the internal sound buffer. */ void EmptyBuffer() throw(); /** * Sound output context. */ typedef Core::Sound::Output Output; }; } } #if NST_MSVC >= 1200 || NST_ICC >= 810 #pragma warning( pop ) #endif #endif nestopia-1.51.1/source/core/api/NstApiTapeRecorder.cpp000066400000000000000000000066431411157722000226350ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstMachine.hpp" #include "../input/NstInpDevice.hpp" #include "../input/NstInpFamilyKeyboard.hpp" #include "NstApiTapeRecorder.hpp" #include "NstApiMachine.hpp" namespace Nes { namespace Api { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif TapeRecorder::EventCaller TapeRecorder::eventCallback; Core::Input::FamilyKeyboard* TapeRecorder::Query() const { if (emulator.expPort->GetType() == Input::FAMILYKEYBOARD) return static_cast(emulator.expPort); else return NULL; } bool TapeRecorder::IsPlaying() const throw() { if (Core::Input::FamilyKeyboard* const familyKeyboard = Query()) return familyKeyboard->IsTapePlaying(); return false; } bool TapeRecorder::IsRecording() const throw() { if (Core::Input::FamilyKeyboard* const familyKeyboard = Query()) return familyKeyboard->IsTapeRecording(); return false; } bool TapeRecorder::IsStopped() const throw() { if (Core::Input::FamilyKeyboard* const familyKeyboard = Query()) return familyKeyboard->IsTapeStopped(); return true; } bool TapeRecorder::IsPlayable() const throw() { if (Core::Input::FamilyKeyboard* const familyKeyboard = Query()) return familyKeyboard->IsTapePlayable(); return false; } Result TapeRecorder::Play() throw() { if (Core::Input::FamilyKeyboard* const familyKeyboard = Query()) { if (emulator.Is(Machine::ON) && !emulator.tracker.IsLocked()) return emulator.tracker.TryResync( familyKeyboard->PlayTape() ); } return RESULT_ERR_NOT_READY; } Result TapeRecorder::Record() throw() { if (Core::Input::FamilyKeyboard* const familyKeyboard = Query()) { if (emulator.Is(Machine::ON) && !emulator.tracker.IsLocked()) return emulator.tracker.TryResync( familyKeyboard->RecordTape() ); } return RESULT_ERR_NOT_READY; } Result TapeRecorder::Stop() throw() { if (Core::Input::FamilyKeyboard* const familyKeyboard = Query()) { if (familyKeyboard->IsTapePlaying() || familyKeyboard->IsTapeRecording()) { if (emulator.tracker.IsLocked()) return RESULT_ERR_NOT_READY; return emulator.tracker.TryResync( familyKeyboard->StopTape() ); } } return RESULT_NOP; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } nestopia-1.51.1/source/core/api/NstApiTapeRecorder.hpp000066400000000000000000000074341411157722000226410ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_API_TAPERECORDER_H #define NST_API_TAPERECORDER_H #include "NstApi.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif #if NST_ICC >= 810 #pragma warning( push ) #pragma warning( disable : 444 ) #elif NST_MSVC >= 1200 #pragma warning( push ) #pragma warning( disable : 4512 ) #endif namespace Nes { namespace Core { namespace Input { class FamilyKeyboard; } } namespace Api { /** * Tape interface. */ class TapeRecorder : public Base { struct EventCaller; Core::Input::FamilyKeyboard* Query() const; public: /** * Interface constructor. * * @param instance emulator instance */ template TapeRecorder(T& instance) : Base(instance) {} /** * Checks if tape is playing. * * @return true if playing */ bool IsPlaying() const throw(); /** * Checks if tape is recording. * * @return true if recording */ bool IsRecording() const throw(); /** * Checks if tape has stopped playing or recording. * * @return true if stopped */ bool IsStopped() const throw(); /** * Checks if tape can be played * * @return true if playable */ bool IsPlayable() const throw(); /** * Plays tape. * * @return result code */ Result Play() throw(); /** * Records tape. * * @return result code */ Result Record() throw(); /** * Stops tape. * * @return result code */ Result Stop() throw(); /** * Checks if a tape recorder is connected. * * @param true connected */ bool IsConnected() const throw() { return Query(); } /** * Tape events. */ enum Event { /** * Tape is playing. */ EVENT_PLAYING, /** * Tape is recording. */ EVENT_RECORDING, /** * Tape has stopped playing or recording. */ EVENT_STOPPED }; enum { NUM_EVENT_CALLBACKS = 3 }; /** * Tape event callback prototype. * * @param userData optional user data * @param event type of event */ typedef void (NST_CALLBACK *EventCallback) (UserData userData,Event event); /** * Tape event callback manager. * * Static object used for adding the user defined callback. */ static EventCaller eventCallback; }; /** * Tape event callback invoker. * * Used internally by the core. */ struct TapeRecorder::EventCaller : Core::UserCallback { void operator () (Event event) const { if (function) function( userdata, event ); } }; } } #if NST_MSVC >= 1200 || NST_ICC >= 810 #pragma warning( pop ) #endif #endif nestopia-1.51.1/source/core/api/NstApiUser.cpp000066400000000000000000000045661411157722000211760ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstApiUser.hpp" namespace Nes { namespace Api { User::LogCaller User::logCallback; User::EventCaller User::eventCallback; User::QuestionCaller User::questionCallback; User::FileIoCaller User::fileIoCallback; const wchar_t* User::File::GetName() const throw() { return L""; } uint User::File::GetId() const throw() { return 0; } ulong User::File::GetMaxSize() const throw() { return ULONG_MAX; } Result User::File::GetContent(const void*&,ulong&) const throw() { return RESULT_ERR_NOT_READY; } Result User::File::GetContent(std::ostream&) const throw() { return RESULT_ERR_NOT_READY; } Result User::File::GetPatchContent(Patch,std::ostream&) const throw() { return RESULT_ERR_NOT_READY; } Result User::File::SetContent(const void*,ulong) throw() { return RESULT_ERR_NOT_READY; } Result User::File::SetContent(std::istream&) throw() { return RESULT_ERR_NOT_READY; } Result User::File::SetPatchContent(std::istream&) throw() { return RESULT_ERR_NOT_READY; } Result User::File::SetSampleContent(const void*,ulong,bool,uint,ulong) throw() { return RESULT_ERR_NOT_READY; } void User::File::GetRawStorage(void*& data, ulong& size) const throw() { data = 0; size = 0; } } } nestopia-1.51.1/source/core/api/NstApiUser.hpp000066400000000000000000000263031411157722000211740ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_API_USER_H #define NST_API_USER_H #include #include "NstApi.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif #if NST_ICC >= 810 #pragma warning( push ) #pragma warning( disable : 304 444 ) #elif NST_MSVC >= 1200 #pragma warning( push ) #pragma warning( disable : 4512 ) #endif namespace Nes { namespace Api { /** * User IO interfaces. */ class User : public Base { struct LogCaller; struct EventCaller; struct QuestionCaller; struct FileIoCaller; public: /** * Interface constructor. * * @param instance emulator instance */ template User(T& instance) : Base(instance) {} /** * User questions. */ enum Question { /** * Whether to proceed or abort if CRC validation fails when loading a save state. */ QUESTION_NST_PRG_CRC_FAIL_CONTINUE = 1, /** * Whether to proceed or abort if CRC validation fails when playing a move. */ QUESTION_NSV_PRG_CRC_FAIL_CONTINUE }; /** * User answer. */ enum Answer { /** * No. */ ANSWER_NO, /** * Yes. */ ANSWER_YES, /** * Default answer (default). */ ANSWER_DEFAULT }; /** * User events. */ enum Event { /** * CPU jam. */ EVENT_CPU_JAM = 1, /** * Can display an in-game timer. */ EVENT_DISPLAY_TIMER, /** * An unofficial CPU opcode was executed. */ EVENT_CPU_UNOFFICIAL_OPCODE }; /** * File IO interface. */ struct File { /** * Action event. */ enum Action { /** * For loading battery-backed RAM into a cartridge. */ LOAD_BATTERY = 1, /** * For saving the battery-backed RAM in a cartridge. */ SAVE_BATTERY, /** * For patching a Famicom Disk System image. */ LOAD_FDS, /** * For saving a modified Famicom Disk System image to patch or directly to image. */ SAVE_FDS, /** * For loading EEPROM into a cartridge. */ LOAD_EEPROM, /** * For saving the EEPROM in a cartridge. */ SAVE_EEPROM, /** * For loading cassette tape recording. */ LOAD_TAPE, /** * For saving the cassette tape recording. */ SAVE_TAPE, /** * For loading Turbo File device data. */ LOAD_TURBOFILE, /** * For saving Turbo File device data. */ SAVE_TURBOFILE, /** * For loading ROM into a cartridge. */ LOAD_ROM, /** * For loading raw PCM audio samples. */ LOAD_SAMPLE, /** * For loading raw PCM audio samples used in Moero Pro Yakyuu. */ LOAD_SAMPLE_MOERO_PRO_YAKYUU, /** * For loading raw PCM audio samples used in Moero Pro Yakyuu 88. */ LOAD_SAMPLE_MOERO_PRO_YAKYUU_88, /** * For loading raw PCM audio samples used in Moero Pro Tennis. */ LOAD_SAMPLE_MOERO_PRO_TENNIS, /** * For loading raw PCM audio samples used in Terao No Dosukoi Oozumou. */ LOAD_SAMPLE_TERAO_NO_DOSUKOI_OOZUMOU, /** * For loading raw PCM audio samples used in Aerobics Studio. */ LOAD_SAMPLE_AEROBICS_STUDIO }; /** * Supported patch formats. */ enum Patch { /** * UPS. */ PATCH_UPS, /** * IPS. */ PATCH_IPS }; /** * Returns type of action. * * @return action */ virtual Action GetAction() const throw() = 0; /** * Returns the name of the file to load. * * Used only with the LOAD_ROM and LOAD_SAMPLE action callbacks. * * @return filename */ virtual const wchar_t* GetName() const throw(); /** * Returns the sound file ID to load. * * Used only with the LOAD_SAMPLE_xx action callbacks. * * @return sample id */ virtual uint GetId() const throw(); /** * Returns the maximum allowed size for the content to load. * * Used only with the LOAD_xx action callbacks. * * @return max size */ virtual ulong GetMaxSize() const throw(); /** * Saves the content into an output stream. * * Used only with the SAVE_xx action callbacks. * * @param stream output stream * @param result code */ virtual Result GetContent(std::ostream& stream) const throw(); /** * Returns a pointer to the content to be saved and its size. * * Used only with the SAVE_xx action callbacks. * * @param mem pointer to content * @param size size of content * @param result code */ virtual Result GetContent(const void*& mem,ulong& size) const throw(); /** * Saves the patch content into an output stream. * * Used only with the FDS_SAVE action callback. * * @param patch patch format to use * @param stream output stream */ virtual Result GetPatchContent(Patch patch,std::ostream& stream) const throw(); /** * Loads content into the core through stream. * * Used only with the LOAD_xx action callbacks. * This method can't be used for audio or patch content. Instead, use LoadSampleContent(..) * and SetPatchContent(..) for those. * * @param stream input stream * @return result code */ virtual Result SetContent(std::istream& stream) throw(); /** * Loads content into the core. * * Used only with the LOAD_xx action callbacks. * This method can't be used for audio or patch content. Instead, use LoadSampleContent(..) * and SetPatchContent(..) for those. * * @param mem content * @param size size of content * @return result code */ virtual Result SetContent(const void* mem,ulong size) throw(); /** * Loads patch content into the core. * * Used only with LOAD_FDS action callback. * * @param stream input stream to patch * @return result code */ virtual Result SetPatchContent(std::istream& stream) throw(); /** * Loads audio content into the core. * * Used only with the LOAD_SAMPLE and LOAD_SAMPLE_xx action callbacks. * * @param mem sample content * @param length number of samples * @param stereo dual channel if true * @param bits bits per sample * @param rate sample rate * @return result code */ virtual Result SetSampleContent(const void* mem,ulong length,bool stereo,uint bits,ulong rate) throw(); /** * Gets raw backed data of file. * * Used with LOAD_BATTERY to get a raw, persistent pointer to backed data, * which can be freely written or read from. * Returns non-NULL pointer in data if backed data is not contigous. * * @param data pointer to raw storage * @param size size of raw storage */ virtual void GetRawStorage(void*& data, ulong& size) const throw(); }; enum { NUM_QUESTION_CALLBACKS = 2, NUM_EVENT_CALLBACKS = 3, NUM_FILE_CALLBACKS = 17 }; /** * Logfile callback prototype. * * @param userData optional user data * @param string string content * @param length string length */ typedef void (NST_CALLBACK *LogCallback) (UserData userData,const char* string,ulong length); /** * Logfile callback prototype. * * @param userData optional user data * @param event type of event * @param context context depending on event */ typedef void (NST_CALLBACK *EventCallback) (UserData userData,Event event,const void* context); /** * User question callback prototype. * * @param userData optional user data * @param question type of question * @return user answer */ typedef Answer (NST_CALLBACK *QuestionCallback) (UserData userData,Question question); /** * File IO callback prototype. * * @param userData optional user data * @param file File IO interface */ typedef void (NST_CALLBACK *FileIoCallback) (UserData userData,File& file); /** * Logfile callback manager. * * Static object used for adding the user defined callback. */ static LogCaller logCallback; /** * User event callback manager. * * Static object used for adding the user defined callback. */ static EventCaller eventCallback; /** * User question callback manager. * * Static object used for adding the user defined callback. */ static QuestionCaller questionCallback; /** * File IO callback manager. * * Static object used for adding the user defined callback. */ static FileIoCaller fileIoCallback; }; /** * Logfile callback invoker. * * Used internally by the core. */ struct User::LogCaller : Core::UserCallback { void operator () (const char* text,ulong length) const { if (function) function( userdata, text, length ); } template void operator () (const char (&c)[N]) const { (*this)( c, N-1 ); } }; /** * User event callback invoker. * * Used internally by the core. */ struct User::EventCaller : Core::UserCallback { void operator () (Event event,const void* data=0) const { if (function) function( userdata, event, data ); } }; /** * User question callback invoker. * * Used internally by the core. */ struct User::QuestionCaller : Core::UserCallback { Answer operator () (Question question) const { return function ? function( userdata, question ) : ANSWER_DEFAULT; } }; /** * File IO callback invoker. * * Used internally by the core. */ struct User::FileIoCaller : Core::UserCallback { void operator () (File& file) const { if (function) function( userdata, file ); } }; } } #if NST_MSVC >= 1200 || NST_ICC >= 810 #pragma warning( pop ) #endif #endif nestopia-1.51.1/source/core/api/NstApiVideo.cpp000066400000000000000000000206261411157722000213210ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstMachine.hpp" #include "../NstVideoRenderer.hpp" #include "NstApiVideo.hpp" namespace Nes { namespace Core { namespace Video { Output::Locker Output::lockCallback; Output::Unlocker Output::unlockCallback; } } namespace Api { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Result Video::EnableUnlimSprites(bool state) throw() { if (emulator.tracker.IsLocked( true )) return RESULT_ERR_NOT_READY; if (!emulator.ppu.HasSpriteLimit() != state) { emulator.ppu.EnableSpriteLimit( !state ); emulator.tracker.Resync( true ); return RESULT_OK; } return RESULT_NOP; } bool Video::AreUnlimSpritesEnabled() const throw() { return !emulator.ppu.HasSpriteLimit(); } int Video::GetBrightness() const throw() { return emulator.renderer.GetBrightness(); } int Video::GetSaturation() const throw() { return emulator.renderer.GetSaturation(); } int Video::GetContrast() const throw() { return emulator.renderer.GetContrast(); } int Video::GetSharpness() const throw() { return emulator.renderer.GetSharpness(); } int Video::GetColorResolution() const throw() { return emulator.renderer.GetColorResolution(); } int Video::GetColorBleed() const throw() { return emulator.renderer.GetColorBleed(); } int Video::GetColorArtifacts() const throw() { return emulator.renderer.GetColorArtifacts(); } int Video::GetColorFringing() const throw() { return emulator.renderer.GetColorFringing(); } int Video::GetHue() const throw() { return emulator.renderer.GetHue(); } bool Video::GetBlend() const throw() { return emulator.renderer.GetBlend() != 0; } int Video::GetCornerRounding() const throw() { return emulator.renderer.GetCornerRounding(); } Result Video::SetBrightness(int value) throw() { return emulator.renderer.SetBrightness( value ); } Result Video::SetSaturation(int value) throw() { return emulator.renderer.SetSaturation( value ); } Result Video::SetContrast(int value) throw() { return emulator.renderer.SetContrast( value ); } Result Video::SetSharpness(int value) throw() { return emulator.renderer.SetSharpness( value ); } Result Video::SetColorResolution(int value) throw() { return emulator.renderer.SetColorResolution( value ); } Result Video::SetColorBleed(int value) throw() { return emulator.renderer.SetColorBleed( value ); } Result Video::SetColorArtifacts(int value) throw() { return emulator.renderer.SetColorArtifacts( value ); } Result Video::SetColorFringing(int value) throw() { return emulator.renderer.SetColorFringing( value ); } Result Video::SetHue(int value) throw() { return emulator.renderer.SetHue( value ); } Result Video::SetBlend(bool value) throw() { return emulator.renderer.SetBlend(value); } Result Video::SetCornerRounding(int value) throw() { return emulator.renderer.SetCornerRounding(value); } void Video::ClearFilterUpdateFlag() throw() { emulator.renderer.ClearFilterUpdateFlag(); } void Video::EnableFieldMerging(bool state) throw() { emulator.renderer.EnableFieldMerging( state ); } bool Video::IsFieldMergingEnabled() const throw() { return emulator.renderer.IsFieldMergingEnabled(); } Result Video::SetRenderState(const RenderState& state) throw() { const Result result = emulator.renderer.SetState( state ); if (NES_SUCCEEDED(result) && result != RESULT_NOP) emulator.UpdateColorMode(); return result; } Result Video::GetRenderState(RenderState& state) const throw() { return emulator.renderer.GetState( state ); } Result Video::Blit(Output& output) throw() { if (emulator.renderer.IsReady()) { emulator.renderer.Blit( output, emulator.ppu.GetScreen(), emulator.ppu.GetBurstPhase() ); return RESULT_OK; } return RESULT_ERR_NOT_READY; } Video::RenderState::RenderState() throw() : width (0), height (0), filter (FILTER_NONE) { bits.count = 0; bits.mask.r = 0; bits.mask.g = 0; bits.mask.b = 0; } Video::Decoder::Decoder(DecoderPreset preset) throw() { switch (preset) { case DECODER_CONSUMER: axes[0].angle = 105; axes[0].gain = 0.78f; axes[1].angle = 236; axes[1].gain = 0.33f; axes[2].angle = 0; axes[2].gain = 1.0f; boostYellow = false; break; case DECODER_ALTERNATIVE: axes[0].angle = 105; axes[0].gain = 0.570f; axes[1].angle = 251; axes[1].gain = 0.351f; axes[2].angle = 15; axes[2].gain = 1.015f; boostYellow = true; break; default: axes[0].angle = 105; axes[0].gain = 0.570f; axes[1].angle = 251; axes[1].gain = 0.351f; axes[2].angle = 15; axes[2].gain = 1.015f; boostYellow = false; break; } } bool Video::Decoder::operator == (const Decoder& decoder) const throw() { for (uint i=0; i < NUM_AXES; ++i) { if (axes[i].angle != decoder.axes[i].angle || axes[i].gain != decoder.axes[i].gain) return false; } if (boostYellow != decoder.boostYellow) return false; return true; } bool Video::Decoder::operator != (const Decoder& decoder) const throw() { return !(*this == decoder); } Result Video::SetDecoder(const Decoder& decoder) throw() { return emulator.renderer.SetDecoder( decoder ); } const Video::Decoder& Video::GetDecoder() const throw() { return emulator.renderer.GetDecoder(); } Result Video::Palette::SetMode(const Mode mode) throw() { return emulator.UpdateColorMode ( mode == MODE_RGB ? Core::Machine::COLORMODE_RGB : mode == MODE_CUSTOM ? Core::Machine::COLORMODE_CUSTOM : Core::Machine::COLORMODE_YUV ); } Video::Palette::Mode Video::Palette::GetMode() const throw() { if (emulator.renderer.GetPaletteType() == Core::Video::Renderer::PALETTE_YUV) { return MODE_YUV; } else if (emulator.renderer.GetPaletteType() == Core::Video::Renderer::PALETTE_CUSTOM) { return MODE_CUSTOM; } return MODE_RGB; } Video::Palette::Mode Video::Palette::GetDefaultMode() const throw() { NST_COMPILE_ASSERT( Core::Video::Renderer::DEFAULT_PALETTE - Core::Video::Renderer::PALETTE_YUV == 0 ); return MODE_YUV; } Result Video::Palette::SetCustom(Colors colors,CustomType type) throw() { return emulator.renderer.LoadCustomPalette( colors, type == EXT_PALETTE ); } uint Video::Palette::GetCustom(uchar (*colors)[3],CustomType type) const throw() { return emulator.renderer.SaveCustomPalette( colors, type == EXT_PALETTE ); } void Video::Palette::ResetCustom() throw() { return emulator.renderer.ResetCustomPalette(); } Video::Palette::CustomType Video::Palette::GetCustomType() const throw() { return emulator.renderer.HasCustomPaletteEmphasis() ? EXT_PALETTE : STD_PALETTE; } Video::Palette::Colors Video::Palette::GetColors() const throw() { return emulator.renderer.GetPalette(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } nestopia-1.51.1/source/core/api/NstApiVideo.hpp000066400000000000000000000412501411157722000213220ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_API_VIDEO_H #define NST_API_VIDEO_H #include "NstApi.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif #if NST_ICC >= 810 #pragma warning( push ) #pragma warning( disable : 304 444 ) #elif NST_MSVC >= 1200 #pragma warning( push ) #pragma warning( disable : 4512 ) #endif namespace Nes { namespace Core { namespace Video { /** * Video output context. */ class Output { struct Locker; struct Unlocker; public: enum { WIDTH = 256, HEIGHT = 240, NTSC_WIDTH = 602 }; /** * Pointer to surface memory to be written to. Size must be equal to * or greater than bitsPerPixel/8 * NES screen width * NES screen height. */ void* pixels; /** * Distance in bytes for each line in the surface memory. * Must be equal to or greater than the actual NES screen width. * Value is allowed to be negative. */ long pitch; Output(void* v=0,long p=0) : pixels(v), pitch(p) {} /** * Surface lock callback prototype. * * Called right before the core is about to render to the surface. * * @param userData optional user data * @param output object to this class * @return true if surface is valid and can be written to */ typedef bool (NST_CALLBACK *LockCallback) (void* userData,Output& output); /** * Surface unlock callback prototype. * * Called when the core has finished rendering to the surface and a previous locked was made. * * @param userData optional user data * @param output object to this class */ typedef void (NST_CALLBACK *UnlockCallback) (void* userData,Output& output); /** * Surface lock callback manager. * * Static object used for adding the user defined callback. */ static Locker lockCallback; /** * Surface unlock callback manager. * * Static object used for adding the user defined callback. */ static Unlocker unlockCallback; }; /** * Surface lock callback invoker. * * Used internally by the core. */ struct Output::Locker : UserCallback { bool operator () (Output& output) const { return (!function || function( userdata, output )) && output.pixels && output.pitch; } }; /** * Surface unlock callback invoker. * * Used internally by the core. */ struct Output::Unlocker : UserCallback { void operator () (Output& output) const { if (function) function( userdata, output ); } }; } } namespace Api { /** * Video interface. */ class Video : public Base { public: /** * Interface constructor. * * @param instance emulator instance */ template Video(T& instance) : Base(instance) {} /** * Video output context. */ typedef Core::Video::Output Output; enum { MIN_BRIGHTNESS = -100, DEFAULT_BRIGHTNESS = 0, MAX_BRIGHTNESS = +100, MIN_SATURATION = -100, DEFAULT_SATURATION = 0, DEFAULT_SATURATION_COMP = 0, DEFAULT_SATURATION_SVIDEO = 0, DEFAULT_SATURATION_RGB = 0, DEFAULT_SATURATION_MONO = -100, MAX_SATURATION = +100, MIN_CONTRAST = -100, DEFAULT_CONTRAST = 0, MAX_CONTRAST = +100, MIN_SHARPNESS = -100, DEFAULT_SHARPNESS_COMP = 0, DEFAULT_SHARPNESS_SVIDEO = 20, DEFAULT_SHARPNESS_RGB = 20, DEFAULT_SHARPNESS_MONO = 0, MAX_SHARPNESS = +100, MIN_COLOR_RESOLUTION = -100, DEFAULT_COLOR_RESOLUTION_COMP = 0, DEFAULT_COLOR_RESOLUTION_SVIDEO = 20, DEFAULT_COLOR_RESOLUTION_RGB = 70, DEFAULT_COLOR_RESOLUTION_MONO = 0, MAX_COLOR_RESOLUTION = +100, MIN_COLOR_BLEED = -100, DEFAULT_COLOR_BLEED_COMP = 0, DEFAULT_COLOR_BLEED_SVIDEO = 0, DEFAULT_COLOR_BLEED_RGB = -100, DEFAULT_COLOR_BLEED_MONO = 0, MAX_COLOR_BLEED = +100, MIN_COLOR_ARTIFACTS = -100, DEFAULT_COLOR_ARTIFACTS_COMP = 0, DEFAULT_COLOR_ARTIFACTS_SVIDEO = -100, DEFAULT_COLOR_ARTIFACTS_RGB = -100, DEFAULT_COLOR_ARTIFACTS_MONO = 5, MAX_COLOR_ARTIFACTS = +100, MIN_COLOR_FRINGING = -100, DEFAULT_COLOR_FRINGING_COMP = 0, DEFAULT_COLOR_FRINGING_SVIDEO = -100, DEFAULT_COLOR_FRINGING_RGB = -100, DEFAULT_COLOR_FRINGING_MONO = 5, MAX_COLOR_FRINGING = +100, MIN_HUE = -45, DEFAULT_HUE = 0, MAX_HUE = +45 }; /** * Allows the PPU to render more than eight sprites per line. * * @param state true to allow it, default is false * @return result code */ Result EnableUnlimSprites(bool state) throw(); /** * Checks if the PPU sprite software extension is enabled. * * @return true if enabled */ bool AreUnlimSpritesEnabled() const throw(); /** * Returns the current brightness. * * @return brightness value in the range -100 to 100 */ int GetBrightness() const throw(); /** * Returns the current saturation. * * @return saturation value in the range -100 to 100 */ int GetSaturation() const throw(); /** * Returns the current contrast. * * @return contrast value in the range -100 to 100 */ int GetContrast() const throw(); /** * Returns the current sharpness for the NTSC filter. * * @return sharpness value in the range -100 to 100 */ int GetSharpness() const throw(); /** * Returns the current color resolution for the NTSC filter. * * @return color resolution value in the range -100 to 100 */ int GetColorResolution() const throw(); /** * Returns the current color bleed for the NTSC filter. * * @return color bleed value in the range -100 to 100 */ int GetColorBleed() const throw(); /** * Returns the current color artifacts for the NTSC filter. * * @return color artifacts value in the range -100 to 100 */ int GetColorArtifacts() const throw(); /** * Returns the current color fringing for the NTSC filter. * * @return color fringing value in the range -100 to 100 */ int GetColorFringing() const throw(); /** * Returns the current hue. * * @return hue value in the range -45 to 45 */ int GetHue() const throw(); /** * Returns whenever the xbr filters blends pixels or not */ bool GetBlend() const throw(); /** * Returns how the xbr filters rounds corners */ int GetCornerRounding() const throw(); /** * Sets the brightness. * * @param value brightness in the range -100 to 100, default is 0 * @return result code */ Result SetBrightness(int value) throw(); /** * Sets the saturation. * * @param value saturation in the range -100 to 100, default is 0 * @return result code */ Result SetSaturation(int value) throw(); /** * Sets the contrast. * * @param value contrast in the range -100 to 100, default is 0 * @return result code */ Result SetContrast(int value) throw(); /** * Sets the sharpness for the NTSC filter. * * @param value sharpness in the range -100 to 100, default is 0 * @return result code */ Result SetSharpness(int value) throw(); /** * Sets the color resolution for the NTSC filter. * * @param value color resolution in the range -100 to 100, default is 0 * @return result code */ Result SetColorResolution(int value) throw(); /** * Sets the color bleed for the NTSC filter. * * @param value color bleed in the range -100 to 100, default is 0 * @return result code */ Result SetColorBleed(int value) throw(); /** * Sets the color artifacts for the NTSC filter. * * @param value color artifacts in the range -100 to 100, default is 0 * @return result code */ Result SetColorArtifacts(int value) throw(); /** * Sets the color fringing for the NTSC filter. * * @param value fringing in the range -100 to 100, default is 0 * @return result code */ Result SetColorFringing(int value) throw(); /** * Sets the hue. * * @param value hue in the range -45 to 45, default is 0 * @return result code */ Result SetHue(int value) throw(); /** * Sets whenever the xbr filters is to blend pixels or not. */ Result SetBlend(bool value) throw(); /** * Sets whenever the xbr filters is to round corners or not. */ Result SetCornerRounding(int value) throw(); /** * Quickfix for blank screen issue. */ void ClearFilterUpdateFlag() throw(); /** * Enables field merging for the NTSC filter. * * @param state true to enable */ void EnableFieldMerging(bool state) throw(); /** * Checks if NTSC filter field merging is enabled. * * @return true if enabled */ bool IsFieldMergingEnabled() const throw(); /** * Performs a manual blit to the video output object. * * The core calls this method internally for each frame. * * @param output video output object to blit to * @return result code */ Result Blit(Output& output) throw(); /** * YUV decoder presets. */ enum DecoderPreset { /** * Canonical (default) */ DECODER_CANONICAL, /** * Consumer */ DECODER_CONSUMER, /** * Alternative */ DECODER_ALTERNATIVE }; /** * YUV decoder context. */ struct Decoder { /** * Constructor. * * @param preset preset, canonical by default */ Decoder(DecoderPreset preset=DECODER_CANONICAL) throw(); /** * Tests for equality. * * @param decoder object to compare * @return true if equal */ bool operator == (const Decoder& decoder) const throw(); /** * Tests for non-equality. * * @param decoder object to compare * @return true if non-equal */ bool operator != (const Decoder& decoder) const throw(); enum { AXIS_RY, AXIS_GY, AXIS_BY, NUM_AXES }; struct { float gain; uint angle; } axes[NUM_AXES]; bool boostYellow; }; /** * Sets the YUV decoder. * * @param decoder decoder * @return result code */ Result SetDecoder(const Decoder& decoder) throw(); /** * Returns the current YUV decoder. * * @return current decoder */ const Decoder& GetDecoder() const throw(); /** * Palette interface. */ class Palette { Core::Machine& emulator; public: /** * Interface constructor * * @param instance emulator instance */ Palette(Core::Machine& instance) : emulator(instance) {} enum { NUM_ENTRIES = 64, NUM_ENTRIES_EXT = 512 }; /** * Custom palette types. */ enum CustomType { /** * Standard palette. 64 colors. */ STD_PALETTE = NUM_ENTRIES, /** * Extended palette. 512 colors with emphasis included in it. */ EXT_PALETTE = NUM_ENTRIES_EXT }; /** * Palette modes */ enum Mode { /** * YUV (default) */ MODE_YUV, /** * RGB */ MODE_RGB, /** * Custom */ MODE_CUSTOM }; /** * RGB colors. */ typedef const uchar (*Colors)[3]; /** * Returns the current palette mode. * * @return current mode */ Mode GetMode() const throw(); /** * Returns the default palette mode. * * @return default palette mode */ Mode GetDefaultMode() const throw(); /** * Sets the custom palette. * * @param colors RGB color data * @param type custom palette type */ Result SetCustom(Colors colors,CustomType type=STD_PALETTE) throw(); /** * Returns the custom palette. * * @param colors RGB colors to be filled * @param type custom palette type * @return number of colors written */ uint GetCustom(uchar (*colors)[3],CustomType type) const throw(); /** * Resets the custom palette. */ void ResetCustom() throw(); /** * Returns the custom palette type. * * @return custom palette type */ CustomType GetCustomType() const throw(); /** * Return the current palette colors. * * @return palette colors */ Colors GetColors() const throw(); /** * Sets the palette mode. * * @param mode palette mode * @return result code */ Result SetMode(Mode mode) throw(); }; /** * Returns the palette interface. * * @return palette interface */ Palette GetPalette() { return emulator; } /** * Render state context. */ struct RenderState { RenderState() throw(); /** * Pixel context. */ struct Bits { /** * RGB bit mask. */ struct Mask { ulong r,g,b; }; /** * RGB bit mask. */ Mask mask; /** * Bits per pixel. */ uint count; }; /** * Pixel context. */ Bits bits; /** * Screen width. */ ushort width; /** * Screen height. */ ushort height; /** * Video Filter. */ enum Filter { /** * No filter (default). */ FILTER_NONE, /** * NTSC filter. */ FILTER_NTSC #ifndef NST_NO_SCALEX , /** * Scale2x filter. */ FILTER_SCALE2X, /** * Scale3x filter. */ FILTER_SCALE3X #endif #ifndef NST_NO_HQ2X , /** * Hq2x filter. */ FILTER_HQ2X, /** * Hq3x filter. */ FILTER_HQ3X, /** * Hq4x filter. */ FILTER_HQ4X #endif #ifndef NST_NO_2XSAI , /** * 2xSaI filter. */ FILTER_2XSAI #endif #ifndef NST_NO_XBR , FILTER_2XBR, FILTER_3XBR, FILTER_4XBR #endif }; /** * Scale factors. */ enum Scale { SCALE_NONE = 1 #ifndef NST_NO_SCALEX ,SCALE_SCALE2X = 2 ,SCALE_SCALE3X = 3 #endif #ifndef NST_NO_HQ2X ,SCALE_HQ2X = 2 ,SCALE_HQ3X = 3 #endif #ifndef NST_NO_2XSAI ,SCALE_2XSAI = 2 #endif }; /** * Filter. */ Filter filter; }; /** * Sets the render state. * * @param state render state to be set * @return result code */ Result SetRenderState(const RenderState& state) throw(); /** * Returns the current render state. * * @param state object to be filled * @return result code */ Result GetRenderState(RenderState& state) const throw(); }; } } #if NST_MSVC >= 1200 || NST_ICC >= 810 #pragma warning( pop ) #endif #endif nestopia-1.51.1/source/core/board/000077500000000000000000000000001411157722000167405ustar00rootroot00000000000000nestopia-1.51.1/source/core/board/NstBoard.cpp000066400000000000000000003565371411157722000212030ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include "../NstLog.hpp" #include "../NstTimer.hpp" #include "NstBoard.hpp" #include "NstBoardNRom.hpp" #include "NstBoardAxRom.hpp" #include "NstBoardAction53.hpp" #include "NstBoardBxRom.hpp" #include "NstBoardCxRom.hpp" #include "NstBoardDxRom.hpp" #include "NstBoardExRom.hpp" #include "NstBoardFxRom.hpp" #include "NstBoardGxRom.hpp" #include "NstBoardHxRom.hpp" #include "NstBoardJxRom.hpp" #include "NstBoardMxRom.hpp" #include "NstBoardNxRom.hpp" #include "NstBoardPxRom.hpp" #include "NstBoardSxRom.hpp" #include "NstBoardTxRom.hpp" #include "NstBoardUxRom.hpp" #include "NstBoardDiscrete.hpp" #include "NstBoardEvent.hpp" #include "NstBoardFb.hpp" #include "NstBoardQj.hpp" #include "NstBoardZz.hpp" #include "NstBoardAe.hpp" #include "NstBoardAcclaim.hpp" #include "NstBoardAgci.hpp" #include "NstBoardAve.hpp" #include "NstBoardBandai.hpp" #include "NstBoardCaltron.hpp" #include "NstBoardCamerica.hpp" #include "NstBoardCne.hpp" #include "NstBoardCony.hpp" #include "NstBoardDreamtech.hpp" #include "NstBoardFfe.hpp" #include "NstBoardFujiya.hpp" #include "NstBoardFukutake.hpp" #include "NstBoardFutureMedia.hpp" #include "NstBoardGouder.hpp" #include "NstBoardHes.hpp" #include "NstBoardHenggedianzi.hpp" #include "NstBoardHosenkan.hpp" #include "NstBoardInlNsf.hpp" #include "NstBoardIrem.hpp" #include "NstBoardJaleco.hpp" #include "NstBoardJyCompany.hpp" #include "NstBoardKaiser.hpp" #include "NstBoardKasing.hpp" #include "NstBoardKay.hpp" #include "NstBoardKonami.hpp" #include "NstBoardMagicKidGoogoo.hpp" #include "NstBoardMagicSeries.hpp" #include "NstBoardNanjing.hpp" #include "NstBoardNihon.hpp" #include "NstBoardNitra.hpp" #include "NstBoardNtdec.hpp" #include "NstBoardOpenCorp.hpp" #include "NstBoardRcm.hpp" #include "NstBoardRexSoft.hpp" #include "NstBoardRumbleStation.hpp" #include "NstBoardSachen.hpp" #include "NstBoardSomeriTeam.hpp" #include "NstBoardSubor.hpp" #include "NstBoardSunsoft.hpp" #include "NstBoardSuperGame.hpp" #include "NstBoardTaito.hpp" #include "NstBoardTengen.hpp" #include "NstBoardTxc.hpp" #include "NstBoardVsSystem.hpp" #include "NstBoardWaixing.hpp" #include "NstBoardWhirlwind.hpp" #include "NstBoardBenshengBs5.hpp" #include "NstBoardUnlA9746.hpp" #include "NstBoardUnlCc21.hpp" #include "NstBoardUnlEdu2000.hpp" #include "NstBoardUnlKingOfFighters96.hpp" #include "NstBoardUnlKingOfFighters97.hpp" #include "NstBoardUnlMortalKombat2.hpp" #include "NstBoardUnlN625092.hpp" #include "NstBoardUnlSuperFighter3.hpp" #include "NstBoardUnlTf1201.hpp" #include "NstBoardUnlWorldHero.hpp" #include "NstBoardUnlXzy.hpp" #include "NstBoardBtl2708.hpp" #include "NstBoardBtlAx5705.hpp" #include "NstBoardBtl6035052.hpp" #include "NstBoardBtlDragonNinja.hpp" #include "NstBoardBtlGeniusMerioBros.hpp" #include "NstBoardBtlMarioBaby.hpp" #include "NstBoardBtlPikachuY2k.hpp" #include "NstBoardBtlShuiGuanPipe.hpp" #include "NstBoardBtlSmb2a.hpp" #include "NstBoardBtlSmb2b.hpp" #include "NstBoardBtlSmb2c.hpp" #include "NstBoardBtlSmb3.hpp" #include "NstBoardBtlSuperBros11.hpp" #include "NstBoardBtlT230.hpp" #include "NstBoardBtlTobidaseDaisakusen.hpp" #include "NstBoardBmc110in1.hpp" #include "NstBoardBmc1200in1.hpp" #include "NstBoardBmc150in1.hpp" #include "NstBoardBmc15in1.hpp" #include "NstBoardBmc20in1.hpp" #include "NstBoardBmc21in1.hpp" #include "NstBoardBmc22Games.hpp" #include "NstBoardBmc31in1.hpp" #include "NstBoardBmc35in1.hpp" #include "NstBoardBmc36in1.hpp" #include "NstBoardBmc64in1.hpp" #include "NstBoardBmc72in1.hpp" #include "NstBoardBmc76in1.hpp" #include "NstBoardBmc800in1.hpp" #include "NstBoardBmc8157.hpp" #include "NstBoardBmc9999999in1.hpp" #include "NstBoardBmcA65as.hpp" #include "NstBoardBmcBallgames11in1.hpp" #include "NstBoardBmcCtc65.hpp" #include "NstBoardBmcFamily4646B.hpp" #include "NstBoardBmcFk23c.hpp" #include "NstBoardBmcGamestarA.hpp" #include "NstBoardBmcGamestarB.hpp" #include "NstBoardBmcGolden190in1.hpp" #include "NstBoardBmcGoldenCard6in1.hpp" #include "NstBoardBmcGoldenGame260in1.hpp" #include "NstBoardBmcHero.hpp" #include "NstBoardBmcMarioParty7in1.hpp" #include "NstBoardBmcNovelDiamond.hpp" #include "NstBoardBmcCh001.hpp" #include "NstBoardBmcPowerjoy84in1.hpp" #include "NstBoardBmcResetBased4in1.hpp" #include "NstBoardBmcSuper22Games.hpp" #include "NstBoardBmcSuper24in1.hpp" #include "NstBoardBmcSuper40in1.hpp" #include "NstBoardBmcSuper700in1.hpp" #include "NstBoardBmcSuperBig7in1.hpp" #include "NstBoardBmcSuperGun20in1.hpp" #include "NstBoardBmcSuperHiK4in1.hpp" #include "NstBoardBmcSuperHiK300in1.hpp" #include "NstBoardBmcSuperVision16in1.hpp" #include "NstBoardBmcT262.hpp" #include "NstBoardBmcVrc4.hpp" #include "NstBoardBmcVt5201.hpp" #include "NstBoardBmcY2k64in1.hpp" namespace Nes { namespace Core { namespace Boards { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Board::Type::Type() : id (UNKNOWN), nmt (NMT_VERTICAL), chrRam (0), battery (false), wramAuto (false) { } Board::Type::Type(Id i,Ram& prgRom,Ram& chrRom,Nmt n,bool b,bool a) : id(i), battery(b) { wramAuto = (a && GetWram() >= SIZE_8K); const dword oldPrg = prgRom.Size(); prgRom.Set( Ram::ROM, true, false, NST_MIN(oldPrg,GetMaxPrg()) ); prgRom.Mirror( SIZE_16K ); if (prgRom.Size() != oldPrg) { NST_DEBUG_MSG("PRG-ROM truncated!"); Log::Flush( "Board: warning, PRG-ROM truncated" NST_LINEBREAK ); } switch (dword(id) >> 7 & 0x7) { default: chrRam = 0; break; case CRM_1: chrRam = 1; break; case CRM_2: chrRam = 2; break; case CRM_4: chrRam = 4; break; case CRM_6: chrRam = 6; break; case CRM_8: chrRam = 8; break; case CRM_16: chrRam = 16; break; case CRM_32: chrRam = 32; break; } if (chrRam < 8 && chrRom.Empty()) chrRam = 8; const dword oldChr = chrRom.Size(); chrRom.Set( Ram::ROM, true, false, NST_MIN(oldChr,GetMaxChr()) ); if (chrRom.Size()) chrRom.Mirror( SIZE_8K ); if (chrRom.Size() != oldChr) { NST_DEBUG_MSG("CHR-ROM truncated!"); Log::Flush( "Board: warning, CHR-ROM truncated" NST_LINEBREAK ); } switch (dword(i) >> 4 & 0x7) { case NMT_H: case NMT_V: case NMT_Z: nmt = NMT_CONTROLLED; break; case NMT_1: nmt = NMT_SINGLESCREEN; break; case NMT_2: case NMT_4: nmt = NMT_FOURSCREEN; break; default: nmt = (n == NMT_CONTROLLED ? NMT_VERTICAL : n); break; } } uint Board::Type::GetMapper() const { return dword(id) >> 24; } dword Board::Type::GetMaxPrg() const { return 0x2000UL << (dword(id) >> 20 & 0xF); } dword Board::Type::GetMaxChr() const { uint v = dword(id) >> 16 & 0xF; return v ? 0x1000UL << v : 0UL; } uint Board::Type::GetSavableWram() const { uint v = dword(id) >> 13 & 0x7; return v ? 0x200U << v : 0UL; } uint Board::Type::GetNonSavableWram() const { uint v = dword(id) >> 10 & 0x7; return v ? 0x200U << v : 0UL; } uint Board::Type::GetWram() const { return GetSavableWram() + GetNonSavableWram(); } uint Board::Type::GetChrRam() const { return chrRam * SIZE_1K; } Board::Type::Nmt Board::Type::GetStartupNmt() const { switch (static_cast(dword(id) >> 4 & 0x7)) { case NMT_H: return NMT_HORIZONTAL; case NMT_V: return NMT_VERTICAL; case NMT_Z: case NMT_1: return NMT_SINGLESCREEN; case NMT_2: case NMT_4: return NMT_FOURSCREEN; default: return GetNmt(); } } uint Board::Type::GetNmtRam() const { if (nmt == NMT_FOURSCREEN) return (dword(id) >> 4 & 0x7) == NMT_2 ? SIZE_2K : SIZE_4K; else return 0; } uint Board::Type::GetSavableVram() const { return 0; } uint Board::Type::GetNonSavableVram() const { return GetChrRam() + GetNmtRam(); } uint Board::Type::GetVram() const { return GetSavableVram() + GetNonSavableVram(); } Board::Board(const Context& context) : cpu (*context.cpu), ppu (*context.ppu), chr (context.ppu->GetChrMem()), nmt (context.ppu->GetNmtMem()), vram (Ram::RAM,true,true,context.type.GetVram()), board (context.type) { prg.Source(0).Set( context.prg ); if (const uint size = board.GetWram()) { wrk.Source(0).Set( board.GetSavableWram() ? Ram::NVRAM : Ram::RAM, true, true, size ); wrk.Source(0).Fill( 0x00 ); } else { wrk.Source(0).Set( context.prg ); } prg.Source(1).Set( wrk.Source(0).Reference() ); wrk.Source(1).Set( prg.Source(0).Reference() ); if (const uint size = board.GetChrRam()) chr.Source(1).Set( Ram::RAM, true, true, size, vram.Mem() ); else chr.Source(1).Set( context.chr ); if (context.chr.Size()) chr.Source(0).Set( context.chr ); else chr.Source(0).Set( chr.Source(1).Reference() ); if (const uint size = board.GetNmtRam()) nmt.Source(1).Set( Ram::RAM, true, true, size, vram.Mem() + board.GetChrRam() ); else nmt.Source(1).Set( chr.Source().Reference() ); vram.Fill( 0x00 ); if (Log::Available()) { Log log; log << "Board: " << context.name << NST_LINEBREAK; log << "Board: " << (context.prg.Size() / SIZE_1K) << "k PRG-ROM" NST_LINEBREAK; if (context.chr.Size()) log << "Board: " << (context.chr.Size() / SIZE_1K) << "k CHR-ROM" NST_LINEBREAK; if (const uint size = board.GetWram()) log << "Board: " << (size / SIZE_1K) << (board.IsAutoWram() ? "k auto W-RAM" NST_LINEBREAK : "k W-RAM" NST_LINEBREAK); if (const uint size = board.GetVram()) log << "Board: " << (size / SIZE_1K) << "k V-RAM" NST_LINEBREAK; } } void Board::Reset(const bool hard) { cpu.Map( 0x4018, 0x5FFF ).Set( this, &Board::Peek_Nop, &Board::Poke_Nop ); if (board.GetWram() >= SIZE_8K) cpu.Map( 0x6000, 0x7FFF ).Set( this, &Board::Peek_Wram_6, &Board::Poke_Wram_6 ); else cpu.Map( 0x6000, 0x7FFF ).Set( this, &Board::Peek_Nop, &Board::Poke_Nop ); cpu.Map( 0x8000, 0x9FFF ).Set( this, &Board::Peek_Prg_8, &Board::Poke_Nop ); cpu.Map( 0xA000, 0xBFFF ).Set( this, &Board::Peek_Prg_A, &Board::Poke_Nop ); cpu.Map( 0xC000, 0xDFFF ).Set( this, &Board::Peek_Prg_C, &Board::Poke_Nop ); cpu.Map( 0xE000, 0xFFFF ).Set( this, &Board::Peek_Prg_E, &Board::Poke_Nop ); if (hard) { wrk.Source().SetSecurity( true, board.GetWram() > 0 ); uint i = board.GetSavableWram(); uint n = board.GetWram(); if (board.GetMapper() == 1 && board.GetWram() == SIZE_16K) { i = 0; n = SIZE_8K; } for (; i < n; ++i) *wrk.Source().Mem(i) = (board.IsAutoWram() && i < SIZE_8K) ? (0x6000 + i) >> 8 : 0x00; vram.Fill( 0x00 ); prg.SwapBanks(0U,~0U); chr.SwapBank(0); wrk.SwapBank(0); switch (board.GetStartupNmt()) { case Type::NMT_HORIZONTAL: ppu.SetMirroring( Ppu::NMT_H ); break; case Type::NMT_VERTICAL: ppu.SetMirroring( Ppu::NMT_V ); break; case Type::NMT_SINGLESCREEN: ppu.SetMirroring( Ppu::NMT_0 ); break; case Type::NMT_FOURSCREEN: if (board.GetNmtRam() == SIZE_2K) { nmt.Source(0).SwapBank(0); nmt.Source(1).SwapBank(0); } else { nmt.Source(1).SwapBank(0); } break; case Type::NMT_CONTROLLED: default: break; } } SubReset( hard ); } void Board::Save(File& file) const { if (board.HasBattery() && board.GetSavableWram()) file.Save( File::BATTERY, wrk.Source().Mem(), board.GetSavableWram() ); } void Board::Load(File& file) { if (board.HasBattery() && board.GetSavableWram()) file.Load( File::BATTERY, wrk.Source().Mem(), board.GetSavableWram() ); } void Board::SaveState(State::Saver& state,const dword baseChunk) const { state.Begin( baseChunk ); if (const uint size = board.GetWram()) state.Begin( AsciiId<'W','R','M'>::V ).Compress( wrk.Source().Mem(), size ).End(); if (const uint size = board.GetVram()) state.Begin( AsciiId<'V','R','M'>::V ).Compress( vram.Mem(), size ).End(); prg.SaveState( state, AsciiId<'P','R','G'>::V ); chr.SaveState( state, AsciiId<'C','H','R'>::V ); nmt.SaveState( state, AsciiId<'N','M','T'>::V ); wrk.SaveState( state, AsciiId<'W','R','K'>::V ); SubSave( state ); state.End(); } void Board::LoadState(State::Loader& state) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'W','R','M'>::V: NST_VERIFY( board.GetWram() ); if (const uint size = board.GetWram()) state.Uncompress( wrk.Source().Mem(), size ); break; case AsciiId<'V','R','M'>::V: NST_VERIFY( board.GetVram() ); if (const uint size = board.GetVram()) state.Uncompress( vram.Mem(), size ); break; case AsciiId<'P','R','G'>::V: prg.LoadState( state ); break; case AsciiId<'C','H','R'>::V: chr.LoadState( state ); break; case AsciiId<'N','M','T'>::V: nmt.LoadState( state ); break; case AsciiId<'W','R','K'>::V: wrk.LoadState( state ); break; default: SubLoad( state, chunk ); break; } state.End(); } } void Board::Map( uint a,uint b,PrgSwap8k0 ) const { cpu.Map(a,b).Set( &Board::Poke_Prg_8k_0 ); } void Board::Map( uint a,uint b,PrgSwap8k1 ) const { cpu.Map(a,b).Set( &Board::Poke_Prg_8k_1 ); } void Board::Map( uint a,uint b,PrgSwap8k2 ) const { cpu.Map(a,b).Set( &Board::Poke_Prg_8k_2 ); } void Board::Map( uint a,uint b,PrgSwap8k3 ) const { cpu.Map(a,b).Set( &Board::Poke_Prg_8k_3 ); } void Board::Map( uint a,uint b,PrgSwap16k0 ) const { cpu.Map(a,b).Set( &Board::Poke_Prg_16k_0 ); } void Board::Map( uint a,uint b,PrgSwap16k1 ) const { cpu.Map(a,b).Set( &Board::Poke_Prg_16k_1 ); } void Board::Map( uint a,uint b,PrgSwap32k ) const { cpu.Map(a,b).Set( &Board::Poke_Prg_32k ); } void Board::Map( uint a,uint b,ChrSwap1k0 ) const { cpu.Map(a,b).Set( &Board::Poke_Chr_1k_0 ); } void Board::Map( uint a,uint b,ChrSwap1k1 ) const { cpu.Map(a,b).Set( &Board::Poke_Chr_1k_1 ); } void Board::Map( uint a,uint b,ChrSwap1k2 ) const { cpu.Map(a,b).Set( &Board::Poke_Chr_1k_2 ); } void Board::Map( uint a,uint b,ChrSwap1k3 ) const { cpu.Map(a,b).Set( &Board::Poke_Chr_1k_3 ); } void Board::Map( uint a,uint b,ChrSwap1k4 ) const { cpu.Map(a,b).Set( &Board::Poke_Chr_1k_4 ); } void Board::Map( uint a,uint b,ChrSwap1k5 ) const { cpu.Map(a,b).Set( &Board::Poke_Chr_1k_5 ); } void Board::Map( uint a,uint b,ChrSwap1k6 ) const { cpu.Map(a,b).Set( &Board::Poke_Chr_1k_6 ); } void Board::Map( uint a,uint b,ChrSwap1k7 ) const { cpu.Map(a,b).Set( &Board::Poke_Chr_1k_7 ); } void Board::Map( uint a,uint b,ChrSwap2k0 ) const { cpu.Map(a,b).Set( &Board::Poke_Chr_2k_0 ); } void Board::Map( uint a,uint b,ChrSwap2k1 ) const { cpu.Map(a,b).Set( &Board::Poke_Chr_2k_1 ); } void Board::Map( uint a,uint b,ChrSwap2k2 ) const { cpu.Map(a,b).Set( &Board::Poke_Chr_2k_2 ); } void Board::Map( uint a,uint b,ChrSwap2k3 ) const { cpu.Map(a,b).Set( &Board::Poke_Chr_2k_3 ); } void Board::Map( uint a,uint b,ChrSwap4k0 ) const { cpu.Map(a,b).Set( &Board::Poke_Chr_4k_0 ); } void Board::Map( uint a,uint b,ChrSwap4k1 ) const { cpu.Map(a,b).Set( &Board::Poke_Chr_4k_1 ); } void Board::Map( uint a,uint b,ChrSwap8k ) const { cpu.Map(a,b).Set( &Board::Poke_Chr_8k ); } void Board::Map( uint a,uint b,NmtSwapHv ) const { cpu.Map(a,b).Set( &Board::Poke_Nmt_Hv ); } void Board::Map( uint a,uint b,NmtSwapVh ) const { cpu.Map(a,b).Set( &Board::Poke_Nmt_Vh ); } void Board::Map( uint a,uint b,NmtSwapVh01 ) const { cpu.Map(a,b).Set( &Board::Poke_Nmt_Vh01 ); } void Board::Map( uint a,uint b,NmtSwapHv01 ) const { cpu.Map(a,b).Set( &Board::Poke_Nmt_Hv01 ); } void Board::Map( uint a,uint b,NopPeek ) const { cpu.Map(a,b).Set( &Board::Peek_Nop ); } void Board::Map( uint a,uint b,NopPoke ) const { cpu.Map(a,b).Set( &Board::Poke_Nop ); } void Board::Map( PrgSwap8k0Bc ) const { cpu.Map(0x8000,0xFFFF).Set( &Board::Poke_Prg_8k_0_bc ); } void Board::Map( PrgSwap16k0Bc ) const { cpu.Map(0x8000,0xFFFF).Set( &Board::Poke_Prg_16k_0_bc ); } void Board::Map( PrgSwap32kBc ) const { cpu.Map(0x8000,0xFFFF).Set( &Board::Poke_Prg_32k_bc ); } void Board::Map( ChrSwap4k1Bc ) const { cpu.Map(0x8000,0xFFFF).Set( &Board::Poke_Chr_4k_1_bc ); } void Board::Map( ChrSwap8kBc ) const { cpu.Map(0x8000,0xFFFF).Set( &Board::Poke_Chr_8k_bc ); } void Board::Map(uint a,uint b,NopPeekPoke) const { cpu.Map(a,b).Set( &Board::Peek_Nop, &Board::Poke_Nop ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(Board,Prg_8) { return prg[0][address - 0x8000]; } NES_PEEK_A(Board,Prg_A) { return prg[1][address - 0xA000]; } NES_PEEK_A(Board,Prg_C) { return prg[2][address - 0xC000]; } NES_PEEK_A(Board,Prg_E) { return prg[3][address - 0xE000]; } NES_POKE_D(Board,Prg_8k_0) { prg.SwapBank( data ); } NES_POKE_D(Board,Prg_8k_1) { prg.SwapBank( data ); } NES_POKE_D(Board,Prg_8k_2) { prg.SwapBank( data ); } NES_POKE_D(Board,Prg_8k_3) { prg.SwapBank( data ); } NES_POKE_D(Board,Prg_16k_0) { prg.SwapBank( data ); } NES_POKE_D(Board,Prg_16k_1) { prg.SwapBank( data ); } NES_POKE_D(Board,Prg_32k) { prg.SwapBank( data ); } NES_POKE_D(Board,Chr_1k_0) { ppu.Update(); chr.SwapBank( data ); } NES_POKE_D(Board,Chr_1k_1) { ppu.Update(); chr.SwapBank( data ); } NES_POKE_D(Board,Chr_1k_2) { ppu.Update(); chr.SwapBank( data ); } NES_POKE_D(Board,Chr_1k_3) { ppu.Update(); chr.SwapBank( data ); } NES_POKE_D(Board,Chr_1k_4) { ppu.Update(); chr.SwapBank( data ); } NES_POKE_D(Board,Chr_1k_5) { ppu.Update(); chr.SwapBank( data ); } NES_POKE_D(Board,Chr_1k_6) { ppu.Update(); chr.SwapBank( data ); } NES_POKE_D(Board,Chr_1k_7) { ppu.Update(); chr.SwapBank( data ); } NES_POKE_D(Board,Chr_2k_0) { ppu.Update(); chr.SwapBank( data ); } NES_POKE_D(Board,Chr_2k_1) { ppu.Update(); chr.SwapBank( data ); } NES_POKE_D(Board,Chr_2k_2) { ppu.Update(); chr.SwapBank( data ); } NES_POKE_D(Board,Chr_2k_3) { ppu.Update(); chr.SwapBank( data ); } NES_POKE_D(Board,Chr_4k_0) { ppu.Update(); chr.SwapBank( data ); } NES_POKE_D(Board,Chr_4k_1) { ppu.Update(); chr.SwapBank( data ); } NES_POKE_D(Board,Chr_8k) { ppu.Update(); chr.SwapBank( data ); } uint Board::GetBusData(uint address,uint data) const { NST_VERIFY( data == prg.Peek(address & 0x7FFF) ); return data & prg.Peek(address & 0x7FFF); } NES_POKE_AD(Board,Prg_8k_0_bc) { prg.SwapBank( GetBusData(address,data) ); } NES_POKE_AD(Board,Prg_16k_0_bc) { prg.SwapBank( GetBusData(address,data) ); } NES_POKE_AD(Board,Prg_32k_bc) { prg.SwapBank( GetBusData(address,data) ); } NES_POKE_AD(Board,Chr_4k_1_bc) { ppu.Update(); chr.SwapBank( GetBusData(address,data) ); } NES_POKE_AD(Board,Chr_8k_bc) { ppu.Update(); chr.SwapBank( GetBusData(address,data) ); } NES_POKE_AD(Board,Wram_6) { NST_VERIFY( wrk.Writable(0) ); if (wrk.Writable(0)) wrk[0][address - 0x6000] = data; } NES_PEEK_A(Board,Wram_6) { NST_VERIFY( wrk.Readable(0) ); return wrk.Readable(0) ? wrk[0][address - 0x6000] : (address >> 8); } NES_POKE_D(Board,Nmt_Hv) { NST_VERIFY( data <= 0x1 ); ppu.SetMirroring( (data & 0x1) ? Ppu::NMT_H : Ppu::NMT_V ); } NES_POKE_D(Board,Nmt_Vh) { NST_VERIFY( data <= 0x1 ); ppu.SetMirroring( (data & 0x1) ? Ppu::NMT_V : Ppu::NMT_H ); } NES_POKE_D(Board,Nmt_Vh01) { NST_VERIFY( data <= 0x3 ); static const byte lut[4][4] = { {0,1,0,1}, {0,0,1,1}, {0,0,0,0}, {1,1,1,1} }; ppu.SetMirroring( lut[data & 0x3] ); } NES_POKE_D(Board,Nmt_Hv01) { NST_VERIFY( data <= 0x3 ); static const byte lut[4][4] = { {0,0,1,1}, {0,1,0,1}, {0,0,0,0}, {1,1,1,1} }; ppu.SetMirroring( lut[data & 0x3] ); } NES_POKE(Board,Nop) { NST_DEBUG_MSG("write ignored!"); } NES_PEEK_A(Board,Nop) { NST_DEBUG_MSG("read ignored!"); return address >> 8; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Board::Context::Context ( Cpu* c, Apu* a, Ppu* p, Ram& pr, Ram& cr, const Ram& t, Type::Nmt n, bool wb, bool mb, Chips& h ) : name (""), cpu (c), apu (a), ppu (p), prg (pr), chr (cr), trainer (t), nmt (n), chips (h), wramBattery (wb), mmcBattery (mb) { } struct Board::Context::Element { cstring name; dword id; struct Less { bool operator () (const Element& a,const Element& b) const { return Core::StringCompare( a.name, b.name ) < 0; } bool operator () (const Element& a,wcstring b) const { return Core::StringCompare( a.name, b ) < 0; } bool operator () (wcstring a,const Element& b) const { return Core::StringCompare( b.name, a ) >= 0; } }; }; bool Board::Context::DetectBoard(wcstring string,const dword wram) { static const Element lut[] = { { "ACCLAIM-AOROM", Type::STD_AOROM }, { "ACCLAIM-MC-ACC", Type::ACCLAIM_MCACC }, { "ACCLAIM-TLROM", Type::STD_TLROM }, { "AGCI-47516", Type::DISCRETE_74_377 }, { "AGCI-50282", Type::AGCI_50282 }, { "AVE-74*161", Type::UNL_CXROM }, { "AVE-MB-91", Type::AVE_MB_91 }, { "AVE-NINA-01", Type::AVE_NINA001 }, { "AVE-NINA-02", Type::AVE_NINA002 }, { "AVE-NINA-03", Type::AVE_NINA03 }, { "AVE-NINA-06", Type::AVE_NINA06 }, { "AVE-NINA-07", Type::AVE_NINA07 }, { "BANDAI-74*161/161/32", Type::DISCRETE_74_161_161_32_A }, { "BANDAI-CNROM", Type::STD_CNROM }, { "BANDAI-FCG-1", Type::BANDAI_FCG1 }, { "BANDAI-FCG-2", Type::BANDAI_FCG2 }, { "BANDAI-GNROM", Type::STD_GNROM }, { "BANDAI-JUMP2", Type::BANDAI_BAJUMP2 }, { "BANDAI-LZ93D50+24C01", Type::BANDAI_LZ93D50_24C01 }, { "BANDAI-LZ93D50+24C02", Type::BANDAI_LZ93D50_24C02 }, { "BANDAI-NROM-128", Type::STD_NROM }, { "BANDAI-NROM-256", Type::STD_NROM }, { "BANDAI-PT-554", Type::BANDAI_AEROBICSSTUDIO }, { "BMC-190IN1", Type::BMC_GOLDEN_190IN1 }, { "BMC-42IN1RESETSWITCH", Type::BMC_SUPER_22GAMES }, { "BMC-64IN1NOREPEAT", Type::BMC_Y2K_64IN1 }, { "BMC-70IN1", Type::BMC_GAME_800IN1 }, { "BMC-70IN1B", Type::BMC_GAME_800IN1 }, { "BMC-8157", Type::BMC_8157 }, { "BMC-A65AS", Type::BMC_A65AS }, { "BMC-BS-5", Type::BENSHENG_BS5 }, { "BMC-D1038", Type::BMC_VT5201 }, { "BMC-FK23C", Type::BMC_FKC23C }, { "BMC-GHOSTBUSTERS63IN1", Type::BMC_CTC65 }, { "BMC-GS-2004", Type::RCM_GS2004 }, { "BMC-GS-2013", Type::RCM_GS2013 }, { "BMC-NOVELDIAMOND9999999IN1", Type::BMC_NOVELDIAMOND }, { "BMC-SUPER24IN1SC03", Type::BMC_SUPER_24IN1 }, { "BMC-SUPERHIK8IN1", Type::BMC_HERO }, { "BMC-SUPERVISION16IN1", Type::BMC_SUPERVISION_16IN1 }, { "BMC-T-262", Type::BMC_T262 }, { "BMC-WS", Type::BMC_SUPER_40IN1 }, { "BTL-MARIO1-MALEE2", Type::BTL_GENIUSMERIOBROS }, { "CAMERICA-ALGN", Type::CAMERICA_ALGNV11 }, { "CAMERICA-ALGQ", Type::CAMERICA_ALGQV11 }, { "CAMERICA-BF9093", Type::CAMERICA_BF9093 }, { "CAMERICA-BF9096", Type::CAMERICA_BF9096 }, { "CAMERICA-BF9097", Type::CAMERICA_BF9097 }, { "CAMERICA-GAMEGENIE", Type::STD_NROM }, { "COLORDREAMS-74*377", Type::DISCRETE_74_377 }, { "DREAMTECH01", Type::DREAMTECH01 }, { "HVC-AMROM", Type::STD_AMROM }, { "HVC-AN1ROM", Type::STD_AN1ROM }, { "HVC-ANROM", Type::STD_ANROM }, { "HVC-AOROM", Type::STD_AOROM }, { "HVC-BNROM", Type::STD_BNROM }, { "HVC-CNROM", Type::STD_CNROM }, { "HVC-CPROM", Type::STD_CPROM }, { "HVC-DE1ROM", Type::STD_DE1ROM }, { "HVC-DEROM", Type::STD_DEROM }, { "HVC-DRROM", Type::STD_DRROM }, { "HVC-EKROM", Type::STD_EKROM }, { "HVC-ELROM", Type::STD_ELROM }, { "HVC-ETROM", Type::STD_ETROM }, { "HVC-EWROM", Type::STD_EWROM }, { "HVC-FAMILYBASIC", Type::CUSTOM_FB02 }, { "HVC-FJROM", Type::STD_FJROM }, { "HVC-FKROM", Type::STD_FKROM }, { "HVC-GNROM", Type::STD_GNROM }, { "HVC-HKROM", Type::STD_HKROM }, { "HVC-HROM", Type::STD_NROM }, { "HVC-JLROM", Type::STD_JLROM }, { "HVC-JSROM", Type::STD_JSROM }, { "HVC-MHROM", Type::STD_MHROM }, { "HVC-NROM", Type::STD_NROM }, { "HVC-NROM-128", Type::STD_NROM }, { "HVC-NROM-256", Type::STD_NROM }, { "HVC-NTBROM", Type::STD_NTBROM }, { "HVC-PEEOROM", Type::STD_PEEOROM }, { "HVC-PNROM", Type::STD_PNROM }, { "HVC-RROM", Type::STD_NROM }, { "HVC-RROM-128", Type::STD_NROM }, { "HVC-SAROM", Type::STD_SAROM }, { "HVC-SBROM", Type::STD_SBROM }, { "HVC-SC1ROM", Type::STD_SCROM }, { "HVC-SCROM", Type::STD_SCROM }, { "HVC-SEROM", Type::STD_SEROM }, { "HVC-SF1ROM", Type::STD_SFROM }, { "HVC-SFROM", Type::STD_SFROM }, { "HVC-SGROM", Type::STD_SGROM }, { "HVC-SH1ROM", Type::STD_SHROM }, { "HVC-SHROM", Type::STD_SHROM }, { "HVC-SJROM", Type::STD_SJROM }, { "HVC-SKROM", Type::STD_SKROM }, { "HVC-SL1ROM", Type::STD_SLROM }, { "HVC-SL2ROM", Type::STD_SLROM }, { "HVC-SL3ROM", Type::STD_SLROM }, { "HVC-SLROM", Type::STD_SLROM }, { "HVC-SLRROM", Type::STD_SLROM }, { "HVC-SNROM", Type::STD_SNROM }, { "HVC-SOROM", Type::STD_SOROM }, { "HVC-SROM", Type::STD_NROM }, { "HVC-STROM", Type::STD_NROM }, { "HVC-SUROM", Type::STD_SUROM }, { "HVC-SXROM", Type::STD_SXROM }, { "HVC-TBROM", Type::STD_TBROM }, { "HVC-TEROM", Type::STD_TEROM }, { "HVC-TFROM", Type::STD_TFROM }, { "HVC-TGROM", Type::STD_TGROM }, { "HVC-TKROM", Type::STD_TKROM }, { "HVC-TKSROM", Type::STD_TKSROM }, { "HVC-TL1ROM", Type::STD_TLROM }, { "HVC-TL2ROM", Type::STD_TLROM }, { "HVC-TLROM", Type::STD_TLROM }, { "HVC-TLSROM", Type::STD_TLSROM }, { "HVC-TNROM", Type::STD_TNROM }, { "HVC-TQROM", Type::STD_TQROM }, { "HVC-TR1ROM", Type::STD_TR1ROM }, { "HVC-TSROM", Type::STD_TSROM }, { "HVC-TVROM", Type::STD_TVROM }, { "HVC-UN1ROM", Type::STD_UN1ROM }, { "HVC-UNROM", Type::STD_UNROM }, { "HVC-UOROM", Type::STD_UOROM }, { "IREM-74*161/161/21/138", Type::IREM_LROG017 }, { "IREM-BNROM", Type::STD_BNROM }, { "IREM-G101", Type::IREM_G101A_0 }, { "IREM-G101-A", Type::IREM_G101A_0 }, { "IREM-G101-B", Type::IREM_G101B_0 }, { "IREM-HOLYDIVER", Type::IREM_HOLYDIVER }, { "IREM-NROM-128", Type::STD_NROM }, { "IREM-NROM-256", Type::STD_NROM }, { "IREM-UNROM", Type::STD_UNROM }, { "JALECO-JF-01", Type::JALECO_JF01 }, { "JALECO-JF-02", Type::JALECO_JF02 }, { "JALECO-JF-03", Type::JALECO_JF03 }, { "JALECO-JF-04", Type::JALECO_JF04 }, { "JALECO-JF-05", Type::JALECO_JF05 }, { "JALECO-JF-06", Type::JALECO_JF06 }, { "JALECO-JF-07", Type::JALECO_JF07 }, { "JALECO-JF-08", Type::JALECO_JF08 }, { "JALECO-JF-09", Type::JALECO_JF09 }, { "JALECO-JF-10", Type::JALECO_JF10 }, { "JALECO-JF-11", Type::JALECO_JF11 }, { "JALECO-JF-12", Type::JALECO_JF12 }, { "JALECO-JF-13", Type::JALECO_JF13 }, { "JALECO-JF-14", Type::JALECO_JF14 }, { "JALECO-JF-15", Type::JALECO_JF15 }, { "JALECO-JF-16", Type::JALECO_JF16 }, { "JALECO-JF-17", Type::JALECO_JF17 }, { "JALECO-JF-18", Type::JALECO_JF18 }, { "JALECO-JF-19", Type::JALECO_JF19 }, { "JALECO-JF-20", Type::JALECO_JF20 }, { "JALECO-JF-21", Type::JALECO_JF21 }, { "JALECO-JF-22", Type::JALECO_JF22 }, { "JALECO-JF-23", Type::JALECO_JF23 }, { "JALECO-JF-24", Type::JALECO_JF24 }, { "JALECO-JF-25", Type::JALECO_JF25 }, { "JALECO-JF-26", Type::JALECO_JF26 }, { "JALECO-JF-27", Type::JALECO_JF27 }, { "JALECO-JF-28", Type::JALECO_JF28 }, { "JALECO-JF-29", Type::JALECO_JF29 }, { "JALECO-JF-30", Type::JALECO_JF30 }, { "JALECO-JF-31", Type::JALECO_JF31 }, { "JALECO-JF-32", Type::JALECO_JF32 }, { "JALECO-JF-33", Type::JALECO_JF33 }, { "JALECO-JF-34", Type::JALECO_JF34 }, { "JALECO-JF-35", Type::JALECO_JF35 }, { "JALECO-JF-36", Type::JALECO_JF36 }, { "JALECO-JF-37", Type::JALECO_JF37 }, { "JALECO-JF-38", Type::JALECO_JF38 }, { "JALECO-JF-39", Type::JALECO_JF39 }, { "JALECO-JF-40", Type::JALECO_JF40 }, { "JALECO-JF-41", Type::JALECO_JF41 }, { "KONAMI-74*139/74", Type::DISCRETE_74_139_74 }, { "KONAMI-CNROM", Type::STD_CNROM }, { "KONAMI-NROM-128", Type::STD_NROM }, { "KONAMI-SLROM", Type::STD_SLROM }, { "KONAMI-TLROM", Type::STD_TLROM }, { "KONAMI-UNROM", Type::STD_UNROM }, { "KONAMI-VRC-1", Type::KONAMI_VRC1 }, { "KONAMI-VRC-2", Type::KONAMI_VRC2 }, { "KONAMI-VRC-3", Type::KONAMI_VRC3 }, { "KONAMI-VRC-4", Type::KONAMI_VRC4_0 }, { "KONAMI-VRC-6", Type::KONAMI_VRC6_0 }, { "KONAMI-VRC-7", Type::KONAMI_VRC7_0 }, { "KS7031", Type::KAISER_KS7031 }, { "MLT-ACTION52", Type::AE_STD }, { "MLT-CALTRON6IN1", Type::CALTRON_6IN1 }, { "MLT-MAXI15", Type::AVE_D1012 }, { "NAMCOT-163", Type::NAMCOT_163_0 }, { "NAMCOT-175", Type::NAMCOT_175 }, { "NAMCOT-340", Type::NAMCOT_340 }, { "NAMCOT-3301", Type::STD_NROM }, { "NAMCOT-3302", Type::STD_NROM }, { "NAMCOT-3303", Type::STD_NROM }, { "NAMCOT-3305", Type::STD_NROM }, { "NAMCOT-3311", Type::STD_NROM }, { "NAMCOT-3401", Type::STD_DE1ROM }, { "NAMCOT-3405", Type::STD_DE1ROM }, { "NAMCOT-3406", Type::STD_DE1ROM }, { "NAMCOT-3407", Type::STD_DE1ROM }, { "NAMCOT-3411", Type::STD_NROM }, { "NAMCOT-3413", Type::STD_DE1ROM }, { "NAMCOT-3414", Type::STD_DE1ROM }, { "NAMCOT-3415", Type::STD_DE1ROM }, { "NAMCOT-3416", Type::STD_DE1ROM }, { "NAMCOT-3417", Type::STD_DE1ROM }, { "NAMCOT-3425", Type::NAMCOT_3425 }, { "NAMCOT-3433", Type::NAMCOT_3433 }, { "NAMCOT-3443", Type::NAMCOT_3443 }, { "NAMCOT-3446", Type::NAMCOT_3446 }, { "NAMCOT-3451", Type::STD_DE1ROM }, { "NES-AMROM", Type::STD_AMROM }, { "NES-AN1ROM", Type::STD_AN1ROM }, { "NES-ANROM", Type::STD_ANROM }, { "NES-AOROM", Type::STD_AOROM }, { "NES-B4", Type::STD_TLROM }, { "NES-BNROM", Type::STD_BNROM }, { "NES-BTR", Type::CUSTOM_BTR }, { "NES-CNROM", Type::STD_CNROM }, { "NES-CPROM", Type::STD_CPROM }, { "NES-DE1ROM", Type::STD_DE1ROM }, { "NES-DEROM", Type::STD_DEROM }, { "NES-DRROM", Type::STD_DRROM }, { "NES-EKROM", Type::STD_EKROM }, { "NES-ELROM", Type::STD_ELROM }, { "NES-ETROM", Type::STD_ETROM }, { "NES-EVENT", Type::CUSTOM_EVENT }, { "NES-EWROM", Type::STD_EWROM }, { "NES-FJROM", Type::STD_FJROM }, { "NES-FKROM", Type::STD_FKROM }, { "NES-GNROM", Type::STD_GNROM }, { "NES-HKROM", Type::STD_HKROM }, { "NES-HROM", Type::STD_NROM }, { "NES-JLROM", Type::STD_JLROM }, { "NES-JSROM", Type::STD_JSROM }, { "NES-MHROM", Type::STD_MHROM }, { "NES-NROM", Type::STD_NROM }, { "NES-NROM-128", Type::STD_NROM }, { "NES-NROM-256", Type::STD_NROM }, { "NES-NTBROM", Type::STD_NTBROM }, { "NES-PEEOROM", Type::STD_PEEOROM }, { "NES-PNROM", Type::STD_PNROM }, { "NES-QJ", Type::CUSTOM_QJ }, { "NES-RROM", Type::STD_NROM }, { "NES-RROM-128", Type::STD_NROM }, { "NES-SAROM", Type::STD_SAROM }, { "NES-SBROM", Type::STD_SBROM }, { "NES-SC1ROM", Type::STD_SCROM }, { "NES-SCROM", Type::STD_SCROM }, { "NES-SEROM", Type::STD_SEROM }, { "NES-SF1ROM", Type::STD_SFROM }, { "NES-SFROM", Type::STD_SFROM }, { "NES-SGROM", Type::STD_SGROM }, { "NES-SH1ROM", Type::STD_SHROM }, { "NES-SHROM", Type::STD_SHROM }, { "NES-SJROM", Type::STD_SJROM }, { "NES-SKROM", Type::STD_SKROM }, { "NES-SL1ROM", Type::STD_SLROM }, { "NES-SL2ROM", Type::STD_SLROM }, { "NES-SL3ROM", Type::STD_SLROM }, { "NES-SLROM", Type::STD_SLROM }, { "NES-SLRROM", Type::STD_SLROM }, { "NES-SNROM", Type::STD_SNROM }, { "NES-SOROM", Type::STD_SOROM }, { "NES-SROM", Type::STD_NROM }, { "NES-STROM", Type::STD_NROM }, { "NES-SUROM", Type::STD_SUROM }, { "NES-SXROM", Type::STD_SXROM }, { "NES-TBROM", Type::STD_TBROM }, { "NES-TEROM", Type::STD_TEROM }, { "NES-TFROM", Type::STD_TFROM }, { "NES-TGROM", Type::STD_TGROM }, { "NES-TKROM", Type::STD_TKROM }, { "NES-TKSROM", Type::STD_TKSROM }, { "NES-TL1ROM", Type::STD_TLROM }, { "NES-TL2ROM", Type::STD_TLROM }, { "NES-TLROM", Type::STD_TLROM }, { "NES-TLSROM", Type::STD_TLSROM }, { "NES-TNROM", Type::STD_TNROM }, { "NES-TQROM", Type::STD_TQROM }, { "NES-TR1ROM", Type::STD_TR1ROM }, { "NES-TSROM", Type::STD_TSROM }, { "NES-TVROM", Type::STD_TVROM }, { "NES-UN1ROM", Type::STD_UN1ROM }, { "NES-UNROM", Type::STD_UNROM }, { "NES-UOROM", Type::STD_UOROM }, { "NES-WH", Type::CUSTOM_WH }, { "NTDEC-N715062", Type::NTDEC_N715062 }, { "PAL-MH", Type::STD_MHROM }, { "PAL-ZZ", Type::CUSTOM_ZZ }, { "SACHEN-8259A", Type::SACHEN_8259A }, { "SACHEN-8259B", Type::SACHEN_8259B }, { "SACHEN-8259C", Type::SACHEN_8259C }, { "SACHEN-8259D", Type::SACHEN_8259D }, { "SACHEN-CNROM", Type::STD_CXROM }, { "SETA-NROM-128", Type::STD_NROM }, { "SUNSOFT-1", Type::SUNSOFT_1 }, { "SUNSOFT-2", Type::SUNSOFT_2B }, { "SUNSOFT-3", Type::SUNSOFT_3 }, { "SUNSOFT-4", Type::SUNSOFT_4_0 }, { "SUNSOFT-5B", Type::SUNSOFT_5B_0 }, { "SUNSOFT-FME-7", Type::SUNSOFT_FME7_0 }, { "SUNSOFT-NROM-256", Type::STD_NROM }, { "TAITO-74*139/74", Type::DISCRETE_74_139_74 }, { "TAITO-74*161/161/32", Type::DISCRETE_74_161_161_32_A }, { "TAITO-CNROM", Type::STD_CNROM }, { "TAITO-NROM-128", Type::STD_NROM }, { "TAITO-NROM-256", Type::STD_NROM }, { "TAITO-TC0190FMC", Type::TAITO_TC0190FMC }, { "TAITO-TC0190FMC+PAL16R4", Type::TAITO_TC0190FMC_PAL16R4 }, { "TAITO-UNROM", Type::STD_UNROM }, { "TAITO-X1-005", Type::TAITO_X1005 }, { "TAITO-X1-017", Type::TAITO_X1017 }, { "TENGEN-800002", Type::TENGEN_800002 }, { "TENGEN-800003", Type::STD_NROM }, { "TENGEN-800004", Type::TENGEN_800004 }, { "TENGEN-800008", Type::TENGEN_800008 }, { "TENGEN-800030", Type::TENGEN_800030 }, { "TENGEN-800032", Type::TENGEN_800032 }, { "TENGEN-800037", Type::TENGEN_800037 }, { "TENGEN-800042", Type::TENGEN_800042 }, { "UNL-22211", Type::TXC_22211A }, { "UNL-603-5052", Type::BTL_6035052 }, { "UNL-8237", Type::SUPERGAME_POCAHONTAS2 }, { "UNL-A9746", Type::UNL_A9746 }, { "UNL-AX5705", Type::BTL_AX5705 }, { "UNL-CC-21", Type::UNL_CC21 }, { "UNL-EDU2000", Type::UNL_EDU2000 }, { "UNL-FS304", Type::UNL_FS304 }, { "UNL-H2288", Type::KAY_H2288 }, { "UNL-KOF97", Type::UNL_KINGOFFIGHTERS97 }, { "UNL-KS7013B", Type::KAISER_KS7013B }, { "UNL-KS7016", Type::KAISER_KS7016 }, { "UNL-KS7031", Type::KAISER_KS7031 }, { "UNL-KS7032", Type::KAISER_KS7032 }, { "UNL-KS7037", Type::KAISER_KS7037 }, { "UNL-KS7057", Type::KAISER_KS7057 }, { "UNL-N625092", Type::UNL_N625092 }, { "UNL-SA-0036", Type::SACHEN_SA0036 }, { "UNL-SA-0037", Type::SACHEN_SA0037 }, { "UNL-SA-016-1M", Type::SACHEN_SA0161M }, { "UNL-SA-72007", Type::SACHEN_SA72007 }, { "UNL-SA-72008", Type::SACHEN_SA72008 }, { "UNL-SA-NROM", Type::SACHEN_TCA01 }, { "UNL-SACHEN-74LS374N", Type::SACHEN_74_374B }, { "UNL-SACHEN-8259A", Type::SACHEN_8259A }, { "UNL-SACHEN-8259B", Type::SACHEN_8259B }, { "UNL-SACHEN-8259C", Type::SACHEN_8259C }, { "UNL-SACHEN-8259D", Type::SACHEN_8259D }, { "UNL-SHERO", Type::UNL_SHERO }, { "UNL-SL1632", Type::REXSOFT_SL1632 }, { "UNL-SMB2J", Type::BTL_SMB2_C }, { "UNL-T-230", Type::BTL_T230 }, { "UNL-TC-U01-1.5M", Type::SACHEN_TCU01 }, { "UNL-TEK90", Type::JYCOMPANY_TYPE_A }, { "UNL-TF1201", Type::UNL_TF1201 }, { "VIRGIN-SNROM", Type::STD_SNROM } }; #ifdef NST_DEBUG for (uint i=1; i < sizeof(array(lut)); ++i) NST_ASSERT( Element::Less()( lut[i-1], lut[i] ) ); #endif const Element* const result = std::lower_bound ( lut, lut + sizeof(array(lut)), string, Element::Less() ); if (result == lut+sizeof(array(lut)) || Core::StringCompare( result->name, string ) != 0) return false; name = result->name; Type::Id id = static_cast(result->id); switch (id) { case Type::STD_NTBROM: if (prg.Size() > SIZE_128K) id = Type::SUNSOFT_DCS; break; case Type::CUSTOM_FB02: if (wram == 0) { id = Type::STD_NROM; } else if (wram > SIZE_2K) { id = Type::CUSTOM_FB04; } break; case Type::DISCRETE_74_161_161_32_A: if (nmt != Type::NMT_VERTICAL && nmt != Type::NMT_HORIZONTAL) id = Type::DISCRETE_74_161_161_32_B; break; case Type::SUNSOFT_2B: if (nmt == Type::NMT_VERTICAL || nmt == Type::NMT_HORIZONTAL) id = Type::SUNSOFT_2A; break; case Type::SUNSOFT_4_0: if (prg.Size() > SIZE_128K) { id = Type::SUNSOFT_DCS; } else if (wram) { id = Type::SUNSOFT_4_1; } break; case Type::NAMCOT_163_0: if (mmcBattery) { id = (wram ? Type::NAMCOT_163_S_1 : Type::NAMCOT_163_S_0); } else if (wram) { id = Type::NAMCOT_163_1; } break; default: if (wram) { if (id == Type::KONAMI_VRC4_0) { id = (wram > SIZE_2K ? Type::KONAMI_VRC4_2 : Type::KONAMI_VRC4_1); } else if (id == Type::KONAMI_VRC6_0) { id = Type::KONAMI_VRC6_1; } else if (id == Type::KONAMI_VRC7_0) { id = Type::KONAMI_VRC7_1; } else if (id == Type::IREM_G101A_0) { id = Type::IREM_G101A_1; } else if (id == Type::IREM_G101B_0) { id = Type::IREM_G101B_1; } else if (id == Type::SUNSOFT_FME7_0) { id = Type::SUNSOFT_FME7_1; } else if (id == Type::SUNSOFT_5B_0) { id = Type::SUNSOFT_5B_1; } } break; } type = Type( id, prg, chr, nmt, wramBattery || mmcBattery, false ); return true; } bool Board::Context::DetectBoard(const word mapper,const byte submapper,const dword chrRam,const dword wram,bool wramAuto) { Type::Id id; const dword prg = this->prg.Size(); const dword chr = this->chr.Size(); bool useWramAuto = false; if (wram) { wramAuto = false; } else if (wramAuto) { wramAuto = false; useWramAuto = true; } switch (mapper) { case 0: if (prg == SIZE_8K && chr == SIZE_8K) { name = "NAMCOT-3301"; id = Type::STD_NROM; } else if ((prg < SIZE_32K && prg != SIZE_16K) || !chr || wram >= SIZE_8K || (nmt != Type::NMT_HORIZONTAL && nmt != Type::NMT_VERTICAL)) { name = "NROM (non-standard)"; id = Type::UNL_NROM; } else if (wram && wramBattery) { if (wram > SIZE_2K) { name = "FB-04"; id = Type::CUSTOM_FB04; } else { name = "FB-02"; id = Type::CUSTOM_FB02; } } else { if (prg == SIZE_16K) name = "NROM-128"; else name = "NROM-256"; id = Type::STD_NROM; } break; case 155: chips.Add(L"MMC1A"); case 1: if (prg == SIZE_64K && (chr == SIZE_16K || chr == SIZE_32K || chr == SIZE_64K) && wram <= SIZE_8K) { if (wram || useWramAuto) { wramAuto = useWramAuto; name = "SAROM"; id = Type::STD_SAROM; } else { name = "SBROM"; id = Type::STD_SBROM; } } else if (prg == SIZE_64K && chr >= SIZE_128K && !wram && !useWramAuto) { name = "SCROM"; id = Type::STD_SCROM; } else if (prg == SIZE_32K && (chr == SIZE_16K || chr == SIZE_32K || chr == SIZE_64K) && !wram && !useWramAuto) { name = "SEROM"; id = Type::STD_SEROM; } else if ((prg == SIZE_128K || prg == SIZE_256K) && (chr == SIZE_16K || chr == SIZE_32K || chr == SIZE_64K) && wram <= SIZE_8K) { if (wram || useWramAuto) { wramAuto = useWramAuto; name = "SJROM"; id = Type::STD_SJROM; } else { name = "SFROM"; id = Type::STD_SFROM; } } else if ((prg == SIZE_128K || prg == SIZE_256K) && !chr && wram <= SIZE_16K) { if (wram > SIZE_8K) { name = "SOROM"; id = Type::STD_SOROM; } else if (wram || useWramAuto) { wramAuto = useWramAuto; name = "SNROM"; id = Type::STD_SNROM; } else { name = "SGROM"; id = Type::STD_SGROM; } } else if (prg == SIZE_32K && chr == SIZE_128K && !wram && !useWramAuto) { name = "SHROM"; id = Type::STD_SHROM; } else if ((prg == SIZE_128K || prg == SIZE_256K) && chr == SIZE_128K && wram <= SIZE_8K) { if (wram || useWramAuto) { wramAuto = useWramAuto; name = "SKROM"; id = Type::STD_SKROM; } else { name = "SLROM"; id = Type::STD_SLROM; } } else if ((prg == SIZE_64K || prg == SIZE_128K || prg == SIZE_256K) && chr == SIZE_128K && !wram && !useWramAuto) { name = "SL1ROM"; id = Type::STD_SLROM; } else if (prg >= SIZE_512K && !chr && wram < SIZE_32K) { name = "SUROM"; id = Type::STD_SUROM; } else if ((prg == SIZE_128K || prg == SIZE_256K || prg >= SIZE_512K) && !chr && wram >= SIZE_32K) { name = "SXROM"; id = Type::STD_SXROM; } else { name = "SxROM (non-standard)"; if (wram || useWramAuto) { wramAuto = useWramAuto; id = Type::STD_SKROM; } else { id = Type::STD_SLROM; } } break; case 2: if (!chr && !wram && (nmt == Type::NMT_HORIZONTAL || nmt == Type::NMT_VERTICAL)) { if (prg == SIZE_128K) { name = "UNROM"; id = Type::STD_UXROM; break; } else if (prg == SIZE_256K) { name = "UOROM"; id = Type::STD_UXROM; break; } } name = "UxROM (non-standard)"; id = Type::UNL_UXROM; break; case 185: if (!this->prg.PinsDefined()) return false; case 3: if ((prg != SIZE_16K && prg != SIZE_32K) || (chr != SIZE_8K && chr != SIZE_16K && chr != SIZE_32K) || (nmt != Type::NMT_HORIZONTAL && nmt != Type::NMT_VERTICAL)) { name = "CxROM (non-standard)"; id = Type::UNL_CXROM; } else if (wram) { name = "X79B"; id = Type::CUSTOM_X79B; } else { name = "CNROM"; id = Type::STD_CXROM; } break; case 4: if (submapper == 1) { // StarTropics/Zoda's Revenge chips.Add(L"MMC6B"); name = "NES-HKROM"; id = Type::STD_HKROM; break; } if (submapper == 3) { name = "ACCLAIM-MC-ACC"; id = Type::ACCLAIM_MCACC; break; } if (chrRam == 32) { name = "UNL-MMC3BIGCHRRAM"; id = Type::UNL_MMC3BIGCHRRAM; break; } if (nmt == Type::NMT_FOURSCREEN) { if (prg == SIZE_64K && (chr == SIZE_32K || chr == SIZE_64K) && !wram && !useWramAuto) { name = "TVROM"; id = Type::STD_TVROM; } else if ((prg == SIZE_128K || prg == SIZE_256K || prg >= SIZE_512K) && chr == SIZE_64K && !wram && !useWramAuto) { name = "TR1ROM"; id = Type::STD_TR1ROM; } else { name = "TxROM (non-standard)"; wramAuto = useWramAuto; id = Type::UNL_TRXROM; } } else { if (prg == SIZE_32K && (chr == SIZE_32K || chr == SIZE_64K) && !wram && !useWramAuto) { name = "TEROM"; id = Type::STD_TEROM; } else if (prg == SIZE_64K && (chr == SIZE_32K || chr == SIZE_64K) && !wram && !useWramAuto) { name = "TBROM"; id = Type::STD_TBROM; } else if ((prg == SIZE_128K || prg == SIZE_256K || prg >= SIZE_512K) && (chr == SIZE_32K || chr == SIZE_64K) && !wram && !useWramAuto) { name = "TFROM"; id = Type::STD_TFROM; } else if ((prg == SIZE_128K || prg == SIZE_256K || prg >= SIZE_512K) && !chr) { if (wram || useWramAuto) { wramAuto = useWramAuto; name = "TNROM"; id = Type::STD_TNROM; } else { name = "TGROM"; id = Type::STD_TGROM; } } else if ((prg == SIZE_128K || prg == SIZE_256K || prg >= SIZE_512K) && (chr == SIZE_128K || chr >= SIZE_256K)) { if (wram || useWramAuto) { wramAuto = useWramAuto; if (wramBattery) { name = "TKROM"; id = Type::STD_TKROM; } else { name = "TSROM"; id = Type::STD_TSROM; } } else { name = "TLROM"; id = Type::STD_TLROM; } } else { name = "TxROM (non-standard)"; if (wram || useWramAuto) { wramAuto = useWramAuto; id = Type::STD_TKROM; } else { id = Type::STD_TLROM; } } } break; case 5: if ( (prg == SIZE_128K || prg == SIZE_256K || prg == SIZE_512K) && (chr == SIZE_128K || chr == SIZE_256K || chr == SIZE_512K) && (wram <= SIZE_32K) ) { if (wram > SIZE_16K) { name = "EWROM"; id = Type::STD_EWROM; } else if (wram > SIZE_8K) { name = "ETROM"; id = Type::STD_ETROM; } else if (wram || useWramAuto) { wramAuto = useWramAuto; name = "EKROM"; id = Type::STD_EKROM; } else { name = "ELROM"; id = Type::STD_ELROM; } } else { name = "ExROM (non-standard)"; if (wram > SIZE_40K) { id = Type::STD_EXROM_5; } else if (wram > SIZE_32K) { id = Type::STD_EXROM_4; } else if (wram > SIZE_16K) { id = Type::STD_EXROM_3; } else if (wram > SIZE_8K) { id = Type::STD_EXROM_2; } else if (wram || useWramAuto) { wramAuto = useWramAuto; id = Type::STD_EXROM_1; } else { id = Type::STD_EXROM_0; } } break; case 6: name = "FFE F4xxx / F3xxx (a)"; id = Type::CUSTOM_FFE4; break; case 7: if (!chr && !wram) { if (prg == SIZE_256K) { name = "AOROM"; id = Type::STD_AOROM; break; } else if (prg == SIZE_128K) { name = "ANROM"; id = Type::STD_ANROM; break; } else if (prg == SIZE_64K) { name = "AN1ROM"; id = Type::STD_AN1ROM; break; } } name = "AxROM (non-standard)"; id = Type::UNL_AXROM; break; case 8: name = "FFE F3xxx (b)"; id = Type::CUSTOM_FFE3; break; case 9: if (prg < SIZE_128K || (chr < SIZE_128K && chr != SIZE_8K && chr != SIZE_16K && chr != SIZE_32K && chr != SIZE_64K)) { name = "PxROM (non-standard)"; id = Type::STD_PNROM; } else if (wram && wramBattery) { name = "PNROM PC10"; id = Type::STD_PNROM_PC10; } else { name = "PNROM / PEEOROM"; id = Type::STD_PNROM; } break; case 10: if (chr == SIZE_8K || chr == SIZE_16K || chr == SIZE_32K || chr == SIZE_64K || chr >= SIZE_128K) { if (prg == SIZE_128K) { name = "FJROM"; id = Type::STD_FJROM; break; } else if (prg >= SIZE_256K) { name = "FKROM"; id = Type::STD_FKROM; break; } } name = "FxROM (non-standard)"; id = Type::STD_FKROM; break; case 11: name = "COLORDREAMS 74*377"; id = Type::DISCRETE_74_377; break; case 12: name = "REX DBZ5"; id = Type::REXSOFT_DBZ5; break; case 13: name = "CPROM"; id = Type::STD_CPROM; break; case 14: name = "SOMERITEAM SL-1632"; id = Type::REXSOFT_SL1632; break; case 15: name = "WAIXING / BMC CONTRA 100-IN-1"; if (wram || useWramAuto) { wramAuto = useWramAuto; id = Type::WAIXING_PS2_1; } else { id = Type::WAIXING_PS2_0; } break; case 16: if (!wram && prg <= SIZE_256K) { name = "BANDAI LZ93D50 +24C02"; id = Type::BANDAI_LZ93D50_24C02; break; } case 153: if (prg == SIZE_512K) { name = "BANDAI BA-JUMP2"; id = Type::BANDAI_BAJUMP2; } else { name = "BANDAI FCG-1/FCG-2"; id = Type::BANDAI_FCG1; } break; case 17: name = "FFE F8xxx / SMxxxx"; id = Type::CUSTOM_FFE8; break; case 18: name = "JALECO SS88006"; id = Type::JALECO_SS88006; break; case 19: name = "NAMCOT 163"; if (wram || useWramAuto) { wramAuto = useWramAuto; if (mmcBattery) id = Type::NAMCOT_163_S_1; else id = Type::NAMCOT_163_1; } else { if (mmcBattery) id = Type::NAMCOT_163_S_0; else id = Type::NAMCOT_163_0; } break; case 21: if (submapper == 1) { Chips::Type& chip = chips.Add(L"Konami VRC IV"); chip.Pin(3) = L"PRG A2"; chip.Pin(4) = L"PRG A1"; name = "KONAMI VRC4"; id = Type::KONAMI_VRC4_0; } case 25: if (submapper == 2) { // The correct board is VRC2 but the functionality is implemented in the VRC4 code currently Chips::Type& chip = chips.Add(L"Konami VRC IV"); chip.Pin(3) = L"PRG A0"; chip.Pin(4) = L"PRG A1"; name = "KONAMI VRC2"; id = Type::KONAMI_VRC4_2; break; } if (!this->chips.Has(L"Konami VRC IV")) return false; name = "KONAMI VRC4"; id = Type::KONAMI_VRC4_2; break; case 22: if (!this->chips.Has(L"Konami VRC II")) { Chips::Type& chip = chips.Add(L"Konami VRC II"); chip.Pin(3) = L"PRG A0"; chip.Pin(4) = L"PRG A1"; chip.Pin(21) = (chr >= SIZE_256K ? L"CHR A17" : L"NC"); chip.Pin(22) = L"CHR A15"; chip.Pin(23) = L"CHR A10"; chip.Pin(24) = L"CHR A12"; chip.Pin(25) = L"CHR A13"; chip.Pin(26) = L"CHR A11"; chip.Pin(27) = L"CHR A14"; chip.Pin(28) = L"CHR A16"; } name = "KONAMI VRC2"; id = Type::KONAMI_VRC2; break; case 23: if (submapper == 2) { Chips::Type& chip = chips.Add(L"Konami VRC IV"); chip.Pin(3) = L"PRG A3"; chip.Pin(4) = L"PRG A2"; name = "KONAMI VRC4"; id = Type::KONAMI_VRC4_0; } else if (submapper == 3) { name = "KONAMI VRC2"; id = Type::KONAMI_VRC2; break; } if (prg >= SIZE_512K) { if (!this->chips.Has(L"Konami VRC IV")) { Chips::Type& chip = chips.Add(L"Konami VRC IV"); chip.Pin(3) = L"PRG A3"; chip.Pin(4) = L"PRG A2"; } name = "BMC VRC4"; id = Type::BMC_VRC4; } else if (this->chips.Has(L"Konami VRC II")) { name = "KONAMI VRC2"; id = Type::KONAMI_VRC2; } else if (this->chips.Has(L"Konami VRC IV")) { name = "KONAMI VRC4"; id = Type::KONAMI_VRC4_2; } else { return false; } break; case 24: case 26: if (!this->chips.Has(L"Konami VRC VI")) { Chips::Type& chip = chips.Add(L"Konami VRC VI"); if (mapper == 24) { chip.Pin(9) = L"PRG A1"; chip.Pin(10) = L"PRG A0"; name = "KONAMI VRC6 (a)"; } else { chip.Pin(9) = L"PRG A0"; chip.Pin(10) = L"PRG A1"; name = "KONAMI VRC6 (b)"; } } if (wram || useWramAuto) { wramAuto = useWramAuto; id = Type::KONAMI_VRC6_1; } else { id = Type::KONAMI_VRC6_0; } break; case 27: if (prg >= SIZE_128K) { name = "UNL WORLDHERO"; id = Type::UNL_WORLDHERO; } else { name = "UNL-CC-21"; id = Type::UNL_CC21; } break; case 28: name = "ACTION 53"; id = Type::ACTION53; break; case 30: name = "UNROM 512"; id = Type::STD_UNROM512; break; case 31: name = "INLNSF"; id = Type::INLNSF; break; case 32: name = "IREM G-101"; if (submapper == 1) { id = Type::IREM_G101B_0; break; } if (wram || useWramAuto) { wramAuto = useWramAuto; id = Type::IREM_G101A_1; } else { id = Type::IREM_G101A_0; } break; case 33: name = "TAITO TC0190FMC"; id = Type::TAITO_TC0190FMC; break; case 34: if (chr) { name = "AVE NINA-001"; id = Type::AVE_NINA001; } else if (prg == SIZE_128K && !wram && (nmt == Type::NMT_HORIZONTAL || nmt == Type::NMT_VERTICAL)) { name = "BNROM"; id = Type::STD_BNROM; } else { name = "BxROM (non-standard)"; id = Type::UNL_BXROM; } break; case 36: name = "TXC 01-22000-400"; id = Type::TXC_POLICEMAN; break; case 37: name = "ZZ"; id = Type::CUSTOM_ZZ; break; case 38: name = "BIT CORP 74*161/138"; id = Type::DISCRETE_74_161_138; break; case 39: name = "STUDY & GAME 32-IN-1"; id = Type::SUBOR_STUDYNGAME; break; case 40: name = "BTL SMB2 (a)"; id = Type::BTL_SMB2_A; break; case 41: name = "CALTRON 6-IN-1"; id = Type::CALTRON_6IN1; break; case 42: if (chr) { name = "BTL UPA"; id = Type::BTL_MARIOBABY; } else { name = "BTL AI SENSHI NICOL"; id = Type::BTL_AISENSHINICOL; } break; case 43: name = "BTL SMB2 (c)"; id = Type::BTL_SMB2_C; break; case 44: name = "BMC SUPERBIG 7-IN-1"; id = Type::BMC_SUPERBIG_7IN1; break; case 45: name = "BMC SUPER/HERO X-IN-1"; id = Type::BMC_HERO; break; case 46: name = "RUMBLESTATION 15-IN-1"; id = Type::CUSTOM_RUMBLESTATION; break; case 47: name = "QJ"; id = Type::CUSTOM_QJ; break; case 48: name = "TAITO TC0190FMC +PAL16R4"; id = Type::TAITO_TC0190FMC_PAL16R4; break; case 49: name = "BMC SUPERHIK 4-IN-1"; id = Type::BMC_SUPERHIK_4IN1; break; case 50: name = "BTL SMB2 (b)"; id = Type::BTL_SMB2_B; break; case 51: name = "BMC 11-IN-1 BALLGAMES"; id = Type::BMC_BALLGAMES_11IN1; break; case 52: name = "BMC MARIOPARTY 7-IN-1"; id = Type::BMC_MARIOPARTY_7IN1; break; case 53: name = "BMC SUPERVISION 16-IN-1"; id = Type::BMC_SUPERVISION_16IN1; break; case 54: name = "BMC NOVELDIAMOND 9999999-IN-1"; id = Type::BMC_NOVELDIAMOND; break; case 55: name = "BTL GENIUS MERIO BROS"; id = Type::BTL_GENIUSMERIOBROS; break; case 56: name = "KAISER KS-202"; id = Type::KAISER_KS202; break; case 57: name = "BMC GAMESTAR (a)"; id = Type::BMC_GKA; break; case 58: name = "BMC GAMESTAR (b)"; id = Type::BMC_GKB; break; case 60: if (prg == SIZE_64K && chr == SIZE_32K) { name = "BMC RESETBASED 4-IN-1"; id = Type::BMC_RESETBASED_4IN1; } else { name = "BMC VT5201"; id = Type::BMC_VT5201; } break; case 61: name = "TXC / BMC 20-IN-1"; id = Type::RCM_TETRISFAMILY; break; case 62: name = "BMC SUPER 700-IN-1"; id = Type::BMC_SUPER_700IN1; break; case 63: name = "BMC CH-001"; id = Type::BMC_CH001; break; case 64: name = "TENGEN 800032"; id = Type::TENGEN_800032; break; case 65: name = "IREM H-3001"; id = Type::IREM_H3001; break; case 66: if ((chr == SIZE_8K || chr == SIZE_16K || chr == SIZE_32K) && !wram && (nmt == Type::NMT_HORIZONTAL || nmt == Type::NMT_VERTICAL)) { if (prg == SIZE_64K) { name = "GNROM / MHROM"; id = Type::STD_GNROM; break; } else if (prg == SIZE_32K || prg == SIZE_128K) { name = "GNROM"; id = Type::STD_GNROM; break; } } name = "GxROM (non-standard)"; id = Type::UNL_GXROM; break; case 67: name = "SUNSOFT 3"; id = Type::SUNSOFT_3; break; case 68: if (submapper == 1) { name = "SUNSOFT DCS"; id = Type::SUNSOFT_DCS; break; } if (prg > SIZE_128K) { name = "SUNSOFT DCS"; id = Type::SUNSOFT_DCS; } else { name = "SUNSOFT 4"; if (wram || useWramAuto) { wramAuto = useWramAuto; id = Type::SUNSOFT_4_1; } else { id = Type::SUNSOFT_4_0; } } break; case 69: name = "SUNSOFT 5B/FME7"; if (wram || useWramAuto) { wramAuto = useWramAuto; id = Type::SUNSOFT_5B_1; } else { id = Type::SUNSOFT_5B_0; } break; case 70: name = "74*161/161/32 (a)"; id = Type::DISCRETE_74_161_161_32_A; break; case 71: if (submapper == 1) { name = "CAMERICA BF9097"; id = Type::CAMERICA_BF9097; break; } if (prg >= SIZE_256K) { name = "CAMERICA BF9093"; id = Type::CAMERICA_BF9093; } else { name = "CAMERICA BF9093/BF9097"; id = Type::CAMERICA_BF909X; } break; case 72: name = "JALECO JF-26/28"; id = Type::JALECO_JF26; break; case 73: name = "KONAMI VRC3"; id = Type::KONAMI_VRC3; break; case 74: name = "WAIXING (a)"; id = Type::WAIXING_TYPE_A; break; case 75: name = "KONAMI VRC1 / JALECO JF-22"; id = Type::KONAMI_VRC1; break; case 76: name = "NAMCOT 3446"; id = Type::NAMCOT_3446; break; case 77: name = "IREM 74*161/161/21/138"; id = Type::IREM_LROG017; break; case 78: if (submapper == 1) { name = "JALECO JF-16"; id = Type::JALECO_JF16; break; } if (submapper == 3) { name = "IREM-HOLYDIVER"; id = Type::IREM_HOLYDIVER; break; } name = "JALECO JF-16"; id = Type::JALECO_JF16; break; case 79: name = "AVE NINA-03 / NINA-06 / MB-91"; id = Type::AVE_NINA06; break; case 80: name = "TAITO X1-005 (a)"; id = Type::TAITO_X1005; break; case 82: name = "TAITO X1-017"; id = Type::TAITO_X1017; break; case 83: if (prg >= SIZE_1024K || chr >= SIZE_1024K) { name = "BMC DRAGONBALLPARTY 4-IN-1"; id = Type::BMC_DRAGONBOLLPARTY; } else { name = "CONY"; id = Type::CONY_STD; } break; case 85: name = "KONAMI VRC7"; if (wram || useWramAuto) { wramAuto = useWramAuto; id = Type::KONAMI_VRC7_1; } else { id = Type::KONAMI_VRC7_0; } break; case 86: name = "JALECO JF-13"; id = Type::JALECO_JF13; break; case 87: name = "74*139/74"; id = Type::DISCRETE_74_139_74; break; case 88: if (nmt == Type::NMT_HORIZONTAL) { name = "NAMCOT 3433"; id = Type::NAMCOT_3433; } else { name = "NAMCOT 3443"; id = Type::NAMCOT_3443; } break; case 89: name = "SUNSOFT 2 (b)"; id = Type::SUNSOFT_2B; break; case 90: name = "J.Y.COMPANY (a)"; id = Type::JYCOMPANY_TYPE_A; break; case 91: name = "UNL MK2/SF3/SMKR"; id = Type::UNL_MORTALKOMBAT2; break; case 92: name = "JALECO JF-21"; id = Type::JALECO_JF21; break; case 93: name = "SUNSOFT 2 (a)"; id = Type::SUNSOFT_2A; break; case 94: name = "UN1ROM"; id = Type::STD_UN1ROM; break; case 95: name = "NAMCOT 3425"; id = Type::NAMCOT_3425; break; case 96: name = "BANDAI OEKAKIDS"; id = Type::BANDAI_OEKAKIDS; break; case 97: name = "IREM KAIKETSU"; id = Type::IREM_KAIKETSU; break; case 99: name = "VS.SYSTEM"; if (wram || useWramAuto) { wramAuto = useWramAuto; id = Type::CUSTOM_VSSYSTEM_1; } else { id = Type::CUSTOM_VSSYSTEM_0; } break; case 103: name = "BTL 2708"; id = Type::BTL_2708; break; case 104: name = "BIC PEGASUS GOLDEN FIVE"; id = Type::CAMERICA_GOLDENFIVE; break; case 105: name = "EVENT"; id = Type::CUSTOM_EVENT; break; case 106: name = "BTL SMB3"; id = Type::BTL_SMB3; break; case 107: name = "MAGICSERIES"; id = Type::MAGICSERIES_MAGICDRAGON; break; case 108: name = "WHIRLWIND 2706"; id = Type::WHIRLWIND_2706; break; case 112: name = "NTDEC / ASDER"; if (wram || useWramAuto) { wramAuto = useWramAuto; id = Type::NTDEC_ASDER_1; } else { id = Type::NTDEC_ASDER_0; } break; case 113: name = "HES"; id = Type::HES_STD; break; case 114: name = "SUPERGAME LIONKING"; id = Type::SUPERGAME_LIONKING; break; case 115: name = "KASING"; id = Type::KASING_STD; break; case 116: name = "SOMERITEAM SL-12"; id = Type::SOMERITEAM_SL12; break; case 117: name = "FUTUREMEDIA"; id = Type::FUTUREMEDIA_STD; break; case 118: if (wram || useWramAuto) { wramAuto = useWramAuto; name = "TKSROM"; id = Type::STD_TKSROM; } else { name = "TLSROM"; id = Type::STD_TLSROM; } break; case 119: name = "TQROM"; id = Type::STD_TQROM; break; case 120: name = "BTL TOBIDASE DAISAKUSEN"; id = Type::BTL_TOBIDASEDAISAKUSEN; break; case 121: name = "K PANDAPRINCE"; id = Type::KAY_PANDAPRINCE; break; case 123: name = "K H2288"; id = Type::KAY_H2288; break; case 126: name = "BMC POWERJOY 84-IN-1"; id = Type::BMC_POWERJOY_84IN1; break; case 132: name = "TXC 22211 (a)"; id = Type::TXC_22211A; break; case 133: name = "SACHEN SA72008"; id = Type::SACHEN_SA72008; break; case 134: name = "BMC FAMILY 4646B"; id = Type::BMC_FAMILY_4646B; break; case 136: name = "SACHEN TCU02"; id = Type::SACHEN_TCU02; break; case 137: name = "SACHEN 8259D"; id = Type::SACHEN_8259D; break; case 138: name = "SACHEN 8259B"; id = Type::SACHEN_8259B; break; case 139: name = "SACHEN 8259C"; id = Type::SACHEN_8259C; break; case 140: name = "JALECO JF-11/12/14"; id = Type::JALECO_JF14; break; case 141: name = "SACHEN 8259A"; id = Type::SACHEN_8259A; break; case 142: name = "KAISER KS-7032"; id = Type::KAISER_KS7032; break; case 143: name = "SACHEN TCA01"; id = Type::SACHEN_TCA01; break; case 144: name = "AGCI 50282"; id = Type::AGCI_50282; break; case 145: name = "SACHEN SA72007"; id = Type::SACHEN_SA72007; break; case 146: name = "SACHEN SA0161M"; id = Type::SACHEN_SA0161M; break; case 147: name = "SACHEN TCU01"; id = Type::SACHEN_TCU01; break; case 148: name = "AVE 74*161 / SACHEN SA0037"; id = Type::SACHEN_SA0037; break; case 149: name = "SACHEN SA0036"; id = Type::SACHEN_SA0036; break; case 150: name = "SACHEN 74*374 (b)"; id = Type::SACHEN_74_374B; break; case 151: name = "KONAMI VS.SYSTEM"; id = Type::KONAMI_VSSYSTEM; break; case 152: name = "74*161/161/32 (b)"; id = Type::DISCRETE_74_161_161_32_B; break; case 154: name = "NAMCOT 108/109/118"; id = Type::NAMCOT_34XX; break; case 156: name = "DAOU 306"; id = Type::OPENCORP_DAOU306; break; case 157: name = "BANDAI DATACH JOINT SYSTEM"; id = Type::BANDAI_DATACH; break; case 158: name = "TENGEN 800037"; id = Type::TENGEN_800037; break; case 159: name = "BANDAI LZ93D50 +24C01"; id = Type::BANDAI_LZ93D50_24C01; break; case 162: name = "UNL-FS304"; id = Type::UNL_FS304; break; case 163: name = "NANJING"; id = Type::NANJING_STD; break; case 164: name = "WAIXING FFV"; if (wram || useWramAuto) { wramAuto = useWramAuto; id = Type::WAIXING_FFV_1; } else { id = Type::WAIXING_FFV_0; } break; case 165: name = "WAIXING SH2"; if (wram || useWramAuto) { wramAuto = useWramAuto; id = Type::WAIXING_SH2_1; } else { id = Type::WAIXING_SH2_0; } break; case 166: name = "SUBOR (b)"; id = Type::SUBOR_TYPE1; break; case 167: name = "SUBOR (a)"; id = Type::SUBOR_TYPE0; break; case 170: name = "FUJIYA NROM +SECURITY"; id = Type::FUJIYA_STD; break; case 171: name = "KAISER KS-7058"; id = Type::KAISER_KS7058; break; case 172: name = "IDEA-TEK 22211"; id = Type::TXC_22211B; break; case 173: name = "NEI-HU 22211"; id = Type::TXC_22211C; break; case 175: name = "KAISER KS-7022"; id = Type::KAISER_KS7022; break; case 176: if (prg >= SIZE_2048K) { name = "BMC-SUPER24IN1SC03"; id = Type::BMC_SUPER_24IN1; } else if (prg > SIZE_128K) { name = "BMC-FK23C"; id = Type::BMC_FKC23C; } else { name = "XIAO ZHUAN YUAN"; id = Type::UNL_XZY; } break; case 177: name = "HENGGEDIANZI"; id = Type::HENGEDIANZI_STD; break; case 178: name = "WAIXING SAN GUO ZHONG LIE ZHUAN"; id = Type::WAIXING_SGZLZ; break; case 179: name = "HENGGEDIANZI XING HE ZHAN SHI"; id = Type::HENGEDIANZI_XJZB; break; case 180: if (!chr && !wram && (nmt == Type::NMT_HORIZONTAL || nmt == Type::NMT_VERTICAL) && prg == SIZE_128K) { name = "NIHON UNROM M5"; id = Type::NIHON_UNROM_M5; break; } name = "UxROM-AND (non-standard)"; id = Type::UNL_UXROM_M5; break; case 182: name = "HOSENKAN ELECTRONICS"; id = Type::HOSENKAN_STD; break; case 183: name = "BTL SHUI GUAN PIPE"; id = Type::BTL_SHUIGUANPIPE; break; case 184: name = "SUNSOFT 1"; id = Type::SUNSOFT_1; break; case 186: name = "SBX"; id = Type::FUKUTAKE_SBX; break; case 187: name = "UNL SF3/KOF96"; id = Type::UNL_KINGOFFIGHTERS96; break; case 188: name = "BANDAI KARAOKESTUDIO"; id = Type::BANDAI_KARAOKESTUDIO; break; case 189: name = "YOKOSOFT / TXC"; id = Type::TXC_TW; break; case 190: name = "MAGICKIDGOOGOO"; id = Type::MAGICKIDGOOGOO; break; case 191: name = "WAIXING (b)"; id = Type::WAIXING_TYPE_B; break; case 192: name = "WAIXING (c)"; id = Type::WAIXING_TYPE_C; break; case 193: name = "NTDEC / MEGA SOFT"; id = Type::NTDEC_FIGHTINGHERO; break; case 194: name = "WAIXING (d)"; id = Type::WAIXING_TYPE_D; break; case 195: name = "WAIXING (e)"; id = Type::WAIXING_TYPE_E; break; case 196: name = "BTL SUPER BROS 11"; id = Type::BTL_SUPERBROS11; break; case 197: name = "HD-1047-A/AX5202P"; id = Type::UNL_SUPERFIGHTER3; break; case 198: name = "WAIXING (f)"; id = Type::WAIXING_TYPE_F; break; case 199: name = "WAIXING (g)"; id = Type::WAIXING_TYPE_G; break; case 200: name = "BMC 1200/36-IN-1"; id = Type::BMC_36IN1; break; case 201: name = "BMC 21/8-IN-1"; id = Type::BMC_21IN1; break; case 202: name = "BMC 150-IN-1"; id = Type::BMC_150IN1; break; case 203: name = "BMC 35-IN-1"; id = Type::BMC_35IN1; break; case 204: name = "BMC 64-IN-1"; id = Type::BMC_64IN1; break; case 205: name = "BMC 15/3-IN-1"; id = Type::BMC_15IN1; break; case 206: if (nmt == Type::NMT_FOURSCREEN) { name = "DRROM"; id = Type::STD_DRROM; } else if (prg >= SIZE_128K) { name = "DE1ROM / NAMCOT 34xx"; id = Type::STD_DE1ROM; } else { name = "DEROM / TENGEN MIMIC-1 / NAMCOT 34xx"; id = Type::STD_DEROM; } break; case 207: { Chips::Type& chip = chips.Add(L"X1-005"); chip.Pin(17) = L"CIRAM A10"; chip.Pin(31) = L"NC"; name = "TAITO X1-005 (b)"; id = Type::TAITO_X1005; break; } case 208: name = "GOUDER 37017"; id = Type::GOUDER_37017; break; case 209: name = "J.Y.COMPANY (b)"; id = Type::JYCOMPANY_TYPE_B; break; case 210: if (submapper == 1) { name = "NAMCOT-175"; id = Type::NAMCOT_175; break; } if (submapper == 2) { name = "NAMCOT-340"; id = Type::NAMCOT_340; break; } if (!this->chips.Has(L"175")) { name = "NAMCOT-340"; id = Type::NAMCOT_340; } else { name = "NAMCOT-175"; id = Type::NAMCOT_175; } break; case 211: name = "J.Y.COMPANY (c)"; id = Type::JYCOMPANY_TYPE_C; break; case 212: name = "BMC SUPERHIK 300-IN-1"; id = Type::BMC_SUPERHIK_300IN1; break; case 213: name = "BMC 9999999-IN-1"; id = Type::BMC_9999999IN1; break; case 214: name = "BMC SUPERGUN 20-IN-1"; id = Type::BMC_SUPERGUN_20IN1; break; case 215: if (prg == SIZE_256K && chr == SIZE_512K) { name = "SUPERGAME MK3E"; id = Type::SUPERGAME_MK3E; } else { name = "SUPERGAME BOOGERMAN"; id = Type::SUPERGAME_BOOGERMAN; } break; case 216: name = "RCM GS-2015"; id = Type::RCM_GS2015; break; case 217: name = "BMC SPC009"; id = Type::BMC_GOLDENCARD_6IN1; break; case 219: name = "UNL A9746"; id = Type::UNL_A9746; break; case 221: name = "UNL N625092"; id = Type::UNL_N625092; break; case 222: name = "BTL DRAGON NINJA"; id = Type::BTL_DRAGONNINJA; break; case 223: name = "WAIXING TANG MU LI XIAN JI"; id = Type::WAIXING_TYPE_I; break; case 224: name = "WAIXING YING XIONG CHUAN QI"; id = Type::WAIXING_TYPE_J; break; case 225: name = "BMC 58/64/72-IN-1"; id = Type::BMC_72IN1; break; case 226: if (prg == SIZE_1024K) { name = "BMC SUPER 42-IN-1"; id = Type::BMC_SUPER_42IN1; } else if (prg == SIZE_2048K) { name = "BMC 76-IN-1"; id = Type::BMC_76IN1; } else { name = "BMC-GHOSTBUSTERS63IN1"; id = Type::BMC_CTC65; } break; case 227: name = "BMC 1200-IN-1"; id = Type::BMC_1200IN1; break; case 228: name = "ACTIVE ENTERTAINMENT"; id = Type::AE_STD; break; case 229: name = "BMC 31-IN-1"; id = Type::BMC_31IN1; break; case 230: name = "BMC SUPER 22 GAMES / 20-IN-1"; id = Type::BMC_22GAMES; break; case 231: name = "BMC 20-IN-1"; id = Type::BMC_20IN1; break; case 232: name = "CAMERICA BF9096"; id = Type::CAMERICA_BF9096; break; case 233: name = "BMC SUPER 22 GAMES"; id = Type::BMC_SUPER_22GAMES; break; case 234: name = "AVE D-1012"; id = Type::AVE_D1012; break; case 235: if (prg <= SIZE_2048K) { name = "GOLDENGAME 150-IN-1"; id = Type::BMC_GOLDENGAME_150IN1; } else { name = "GOLDENGAME 260-IN-1"; id = Type::BMC_GOLDENGAME_260IN1; } break; case 236: name = "BMC 70/800-IN-1"; id = Type::BMC_GAME_800IN1; break; case 240: name = "CNE SHLZ"; id = Type::CNE_SHLZ; break; case 241: name = "MXMDHTWO / TXC"; id = Type::TXC_MXMDHTWO; break; case 242: if (nmt == Type::NMT_CONTROLLED) { name = "WAIXING ZS"; id = Type::WAIXING_ZS; } else { name = "WAIXING DQVII"; id = Type::WAIXING_DQVII; } break; case 243: name = "SACHEN 74*374 (a)"; id = Type::SACHEN_74_374A; break; case 244: name = "CNE DECATHLON"; id = Type::CNE_DECATHLON; break; case 245: name = "WAIXING (h)"; id = Type::WAIXING_TYPE_H; break; case 246: name = "CNE PHONE SERM BERM"; id = Type::CNE_PSB; break; case 249: name = "WAIXING +SECURITY"; if (wram || useWramAuto) { wramAuto = useWramAuto; id = Type::WAIXING_SECURITY_1; } else { id = Type::WAIXING_SECURITY_0; } break; case 250: name = "NITRA"; id = Type::NITRA_TDA; break; case 252: name = "WAIXING SAN GUO ZHI"; id = Type::WAIXING_SGZ; break; case 254: name = "BTL PIKACHU Y2K"; id = Type::BTL_PIKACHUY2K; break; case 255: name = "BMC 110/115-IN-1"; id = Type::BMC_110IN1; break; case 262: name = "UNL-SHERO"; id = Type::UNL_SHERO; break; case 263: name = "UNL-KOF97"; id = Type::UNL_KINGOFFIGHTERS97; break; case 265: name = "BMC-T-262"; id = Type::BMC_T262; break; case 283: if (prg > SIZE_256K) { name = "BMC-GS-2013"; id = Type::RCM_GS2013; } else { name = "BMC-GS-2004"; id = Type::RCM_GS2004; } break; case 285: name = "BMC-A65AS"; id = Type::BMC_A65AS; break; case 286: name = "BMC-BS-5"; id = Type::BENSHENG_BS5; break; case 298: name = "UNL-TF1201"; id = Type::UNL_TF1201; break; case 300: name = "BMC-190IN1"; id = Type::BMC_GOLDEN_190IN1; break; case 301: name = "BMC-8157"; id = Type::BMC_8157; break; case 302: name = "UNL-KS7057"; id = Type::KAISER_KS7057; break; case 305: name = "UNL-KS7031"; id = Type::KAISER_KS7031; break; case 306: name = "UNL-KS7016"; id = Type::KAISER_KS7016; break; case 307: name = "UNL-KS7037"; id = Type::KAISER_KS7037; break; case 312: name = "UNL-KS7013B"; id = Type::KAISER_KS7013B; break; case 314: name = "BMC-64IN1NOREPEAT"; id = Type::BMC_Y2K_64IN1; break; case 329: name = "UNL-EDU2000"; id = Type::UNL_EDU2000; break; case 332: name = "BMC-WS"; id = Type::BMC_SUPER_40IN1; break; case 521: name = "DREAMTECH01"; id = Type::DREAMTECH01; break; case 529: name = "UNL-T-230"; id = Type::BTL_T230; break; case 530: name = "UNL-AX5705"; id = Type::BTL_AX5705; break; case 554: name = "UNL-KS7010"; id = Type::KAISER_KS7010; break; default: return false; } type = Type( id, this->prg, this->chr, nmt, wramBattery || mmcBattery, wramAuto ); return true; } Board* Board::Create(const Context& c) { switch (c.type.GetId()) { case Type::STD_NROM : case Type::UNL_NROM : return new NRom(c); case Type::STD_AMROM : case Type::STD_ANROM : case Type::STD_AN1ROM : case Type::STD_AOROM : case Type::UNL_AXROM : return new AxRom(c); case Type::STD_BNROM : case Type::UNL_BXROM : return new BxRom(c); case Type::STD_CNROM : case Type::STD_CXROM : case Type::UNL_CXROM : return new CnRom(c); case Type::STD_CPROM : return new CpRom(c); case Type::STD_DEROM : case Type::STD_DE1ROM : case Type::STD_DRROM : return new DxRom(c); case Type::STD_EKROM : case Type::STD_ELROM : case Type::STD_ETROM : case Type::STD_EWROM : case Type::STD_EXROM_0 : case Type::STD_EXROM_1 : case Type::STD_EXROM_2 : case Type::STD_EXROM_3 : case Type::STD_EXROM_4 : case Type::STD_EXROM_5 : return new ExRom(c); case Type::STD_FJROM : case Type::STD_FKROM : return new FxRom(c); case Type::STD_GNROM : case Type::UNL_GXROM : return new GxRom(c); case Type::STD_MHROM : return new MxRom(c); case Type::STD_HKROM : return new HxRom(c); case Type::STD_JLROM : case Type::STD_JSROM : return new JxRom(c); case Type::STD_NTBROM : return new NxRom(c); case Type::STD_PEEOROM : case Type::STD_PNROM : case Type::STD_PNROM_PC10 : return new PxRom(c); case Type::STD_SAROM : case Type::STD_SBROM : case Type::STD_SCROM : case Type::STD_SEROM : case Type::STD_SFROM : case Type::STD_SGROM : case Type::STD_SHROM : case Type::STD_SJROM : case Type::STD_SKROM : case Type::STD_SLROM : case Type::STD_SNROM : case Type::STD_SOROM : case Type::STD_SUROM : case Type::STD_SXROM : return new SxRom(c); case Type::STD_TBROM : case Type::STD_TEROM : case Type::STD_TFROM : case Type::STD_TGROM : case Type::STD_TKROM : case Type::STD_TLROM : case Type::STD_TNROM : case Type::STD_TR1ROM : case Type::STD_TSROM : case Type::STD_TVROM : case Type::UNL_MMC3BIGCHRRAM : case Type::UNL_TRXROM : return new TxRom (c); case Type::STD_TLSROM : return new TlsRom (c); case Type::STD_TKSROM : return new TksRom (c); case Type::STD_TQROM : return new TqRom (c); case Type::STD_UNROM : case Type::STD_UN1ROM : case Type::STD_UOROM : case Type::STD_UXROM : case Type::STD_UNROM512 : case Type::UNL_UXROM : return new UxRom(c); case Type::DISCRETE_74_377 : return new Discrete::Ic74x377(c); case Type::DISCRETE_74_139_74 : return new Discrete::Ic74x139x74(c); case Type::DISCRETE_74_161_138 : return new Discrete::Ic74x161x138(c); case Type::DISCRETE_74_161_161_32_A : case Type::DISCRETE_74_161_161_32_B : return new Discrete::Ic74x161x161x32(c); case Type::CUSTOM_B4 : return new TxRom(c); case Type::CUSTOM_BTR : return new JxRom(c); case Type::CUSTOM_EVENT : return new Boards::Event(c); case Type::CUSTOM_FFE3 : case Type::CUSTOM_FFE4 : case Type::CUSTOM_FFE8 : return new Ffe(c); case Type::CUSTOM_FB02 : case Type::CUSTOM_FB04 : return new Fb(c); case Type::CUSTOM_RUMBLESTATION : return new RumbleStation(c); case Type::CUSTOM_QJ : return new Qj(c); case Type::CUSTOM_VSSYSTEM_0 : case Type::CUSTOM_VSSYSTEM_1 : return new VsSystem(c); case Type::CUSTOM_WH : return new SxRom(c); case Type::CUSTOM_X79B : return new CnRom(c); case Type::CUSTOM_ZZ : return new Zz(c); case Type::ACCLAIM_MCACC : return new Acclaim::McAcc(c); case Type::ACTION53 : return new Action53(c); case Type::AE_STD : return new Ae::Standard(c); case Type::AGCI_50282 : return new Agci::A50282(c); case Type::AVE_MB_91 : return new Ave::Mb91(c); case Type::AVE_NINA001 : return new Ave::Nina001(c); case Type::AVE_NINA002 : return new Ave::Nina002(c); case Type::AVE_NINA03 : return new Ave::Nina03(c); case Type::AVE_NINA06 : return new Ave::Nina06(c); case Type::AVE_NINA07 : return new Ave::Nina07(c); case Type::AVE_D1012 : return new Ave::D1012(c); case Type::BANDAI_FCG1 : return new Bandai::Fcg1(c); case Type::BANDAI_FCG2 : return new Bandai::Fcg2(c); case Type::BANDAI_BAJUMP2 : return new Bandai::Lz93d50(c); case Type::BANDAI_LZ93D50_24C01 : case Type::BANDAI_LZ93D50_24C02 : return new Bandai::Lz93d50Ex(c); case Type::BANDAI_DATACH : return new Bandai::Datach(c); case Type::BANDAI_KARAOKESTUDIO : return new Bandai::KaraokeStudio(c); case Type::BANDAI_AEROBICSSTUDIO : return new Bandai::AerobicsStudio(c); case Type::BANDAI_OEKAKIDS : return new Bandai::OekaKids(c); case Type::BMC_BALLGAMES_11IN1 : return new Bmc::Ballgames11in1(c); case Type::BMC_A65AS : return new Bmc::A65as(c); case Type::BMC_CTC65 : return new Bmc::Ctc65(c); case Type::BMC_DRAGONBOLLPARTY : return new Cony::Standard(c); case Type::BMC_110IN1 : return new Bmc::B110in1(c); case Type::BMC_1200IN1 : return new Bmc::B1200in1(c); case Type::BMC_150IN1 : return new Bmc::B150in1(c); case Type::BMC_15IN1 : return new Bmc::B15in1(c); case Type::BMC_20IN1 : return new Bmc::B20in1(c); case Type::BMC_21IN1 : return new Bmc::B21in1(c); case Type::BMC_22GAMES : return new Bmc::B22Games(c); case Type::BMC_31IN1 : return new Bmc::B31in1(c); case Type::BMC_35IN1 : return new Bmc::B35in1(c); case Type::BMC_36IN1 : return new Bmc::B36in1(c); case Type::BMC_64IN1 : return new Bmc::B64in1(c); case Type::BMC_72IN1 : return new Bmc::B72in1(c); case Type::BMC_76IN1 : case Type::BMC_SUPER_42IN1 : return new Bmc::B76in1(c); case Type::BMC_8157 : return new Bmc::B8157(c); case Type::BMC_9999999IN1 : return new Bmc::B9999999in1(c); case Type::BMC_FAMILY_4646B : return new Bmc::Family4646B(c); case Type::BMC_FKC23C : return new Bmc::Fk23c(c); case Type::BMC_GAME_800IN1 : return new Bmc::Game800in1(c); case Type::BMC_GOLDEN_190IN1 : return new Bmc::Golden190in1(c); case Type::BMC_GOLDENGAME_150IN1 : case Type::BMC_GOLDENGAME_260IN1 : return new Bmc::GoldenGame260in1(c); case Type::BMC_GOLDENCARD_6IN1 : return new Bmc::GoldenCard6in1(c); case Type::BMC_GKA : return new Bmc::GamestarA(c); case Type::BMC_GKB : return new Bmc::GamestarB(c); case Type::BMC_HERO : return new Bmc::Hero(c); case Type::BMC_MARIOPARTY_7IN1 : return new Bmc::MarioParty7in1(c); case Type::BMC_NOVELDIAMOND : return new Bmc::NovelDiamond(c); case Type::BMC_CH001 : return new Bmc::Ch001(c); case Type::BMC_POWERJOY_84IN1 : return new Bmc::Powerjoy84in1(c); case Type::BMC_RESETBASED_4IN1 : return new Bmc::ResetBased4in1(c); case Type::BMC_VT5201 : return new Bmc::Vt5201(c); case Type::BMC_SUPER_24IN1 : return new Bmc::Super24in1(c); case Type::BMC_SUPER_22GAMES : return new Bmc::Super22Games(c); case Type::BMC_SUPER_40IN1 : return new Bmc::Super40in1(c); case Type::BMC_SUPER_700IN1 : return new Bmc::Super700in1(c); case Type::BMC_SUPERBIG_7IN1 : return new Bmc::SuperBig7in1(c); case Type::BMC_SUPERGUN_20IN1 : return new Bmc::SuperGun20in1(c); case Type::BMC_SUPERHIK_4IN1 : return new Bmc::SuperHiK4in1(c); case Type::BMC_SUPERHIK_300IN1 : return new Bmc::SuperHiK300in1(c); case Type::BMC_SUPERVISION_16IN1 : return new Bmc::SuperVision16in1(c); case Type::BMC_T262 : return new Bmc::T262(c); case Type::BMC_VRC4 : return new Bmc::Vrc4(c); case Type::BMC_Y2K_64IN1 : return new Bmc::Y2k64in1(c); case Type::BTL_AISENSHINICOL : case Type::BTL_MARIOBABY : return new Btl::MarioBaby(c); case Type::BTL_2708 : return new Btl::B2708(c); case Type::BTL_AX5705 : return new Btl::Ax5705(c); case Type::BTL_6035052 : return new Btl::B6035052(c); case Type::BTL_DRAGONNINJA : return new Btl::DragonNinja(c); case Type::BTL_GENIUSMERIOBROS : return new Btl::GeniusMerioBros(c); case Type::BTL_SHUIGUANPIPE : return new Btl::ShuiGuanPipe(c); case Type::BTL_PIKACHUY2K : return new Btl::PikachuY2k(c); case Type::BTL_SMB2_A : return new Btl::Smb2a(c); case Type::BTL_SMB2_B : return new Btl::Smb2b(c); case Type::BTL_SMB2_C : return new Btl::Smb2c(c); case Type::BTL_SMB3 : return new Btl::Smb3(c); case Type::BTL_SUPERBROS11 : return new Btl::SuperBros11(c); case Type::BTL_T230 : return new Btl::T230(c); case Type::BTL_TOBIDASEDAISAKUSEN : return new Btl::TobidaseDaisakusen(c); case Type::CAMERICA_BF9093 : return new Camerica::Bf9093(c); case Type::CAMERICA_BF9096 : return new Camerica::Bf9096(c); case Type::CAMERICA_BF9097 : case Type::CAMERICA_BF909X : return new Camerica::Bf9097(c); case Type::CAMERICA_ALGNV11 : return new Camerica::Algnv11(c); case Type::CAMERICA_ALGQV11 : return new Camerica::Algqv11(c); case Type::CAMERICA_GOLDENFIVE : return new Camerica::GoldenFive(c); case Type::CALTRON_6IN1 : return new Caltron::Mc6in1(c); case Type::CNE_SHLZ : return new Cne::Shlz(c); case Type::CNE_DECATHLON : return new Cne::Decathlon(c); case Type::CNE_PSB : return new Cne::Psb(c); case Type::CONY_STD : return new Cony::Standard(c); case Type::DREAMTECH01 : return new DreamTech::D01(c); case Type::FUTUREMEDIA_STD : return new FutureMedia::Standard(c); case Type::FUJIYA_STD : return new Fujiya::Standard(c); case Type::FUKUTAKE_SBX : return new Fukutake::Sbx(c); case Type::GOUDER_37017 : return new Gouder::G37017(c); case Type::HES_STD : return new Hes::Standard(c); case Type::BENSHENG_BS5 : return new Bensheng::Bs5(c); case Type::HENGEDIANZI_STD : return new Hengedianzi::Standard(c); case Type::HENGEDIANZI_XJZB : return new Hengedianzi::Xjzb(c); case Type::HOSENKAN_STD : return new Hosenkan::Standard(c); case Type::INLNSF : return new InlNsf(c); case Type::IREM_G101A_0 : case Type::IREM_G101A_1 : case Type::IREM_G101B_0 : case Type::IREM_G101B_1 : return new Irem::G101(c); case Type::IREM_H3001 : return new Irem::H3001(c); case Type::IREM_LROG017 : return new Irem::Lrog017(c); case Type::IREM_HOLYDIVER : return new Irem::HolyDiver(c); case Type::IREM_KAIKETSU : return new Irem::Kaiketsu(c); case Type::JALECO_JF01 : return new Jaleco::Jf01(c); case Type::JALECO_JF02 : return new Jaleco::Jf02(c); case Type::JALECO_JF03 : return new Jaleco::Jf03(c); case Type::JALECO_JF04 : return new Jaleco::Jf04(c); case Type::JALECO_JF05 : return new Jaleco::Jf05(c); case Type::JALECO_JF06 : return new Jaleco::Jf06(c); case Type::JALECO_JF07 : return new Jaleco::Jf07(c); case Type::JALECO_JF08 : return new Jaleco::Jf08(c); case Type::JALECO_JF09 : return new Jaleco::Jf09(c); case Type::JALECO_JF10 : return new Jaleco::Jf10(c); case Type::JALECO_JF11 : return new Jaleco::Jf11(c); case Type::JALECO_JF12 : return new Jaleco::Jf12(c); case Type::JALECO_JF13 : return new Jaleco::Jf13(c); case Type::JALECO_JF14 : return new Jaleco::Jf14(c); case Type::JALECO_JF15 : return new Jaleco::Jf15(c); case Type::JALECO_JF16 : return new Jaleco::Jf16(c); case Type::JALECO_JF17 : return new Jaleco::Jf17(c); case Type::JALECO_JF18 : return new Jaleco::Jf18(c); case Type::JALECO_JF19 : return new Jaleco::Jf19(c); case Type::JALECO_JF20 : return new Jaleco::Jf20(c); case Type::JALECO_JF21 : return new Jaleco::Jf21(c); case Type::JALECO_JF22 : return new Jaleco::Jf22(c); case Type::JALECO_JF23 : return new Jaleco::Jf23(c); case Type::JALECO_JF24 : return new Jaleco::Jf24(c); case Type::JALECO_JF25 : return new Jaleco::Jf25(c); case Type::JALECO_JF26 : return new Jaleco::Jf26(c); case Type::JALECO_JF27 : return new Jaleco::Jf27(c); case Type::JALECO_JF28 : return new Jaleco::Jf28(c); case Type::JALECO_JF29 : return new Jaleco::Jf29(c); case Type::JALECO_JF30 : return new Jaleco::Jf30(c); case Type::JALECO_JF31 : return new Jaleco::Jf31(c); case Type::JALECO_JF32 : return new Jaleco::Jf32(c); case Type::JALECO_JF33 : return new Jaleco::Jf33(c); case Type::JALECO_JF34 : return new Jaleco::Jf34(c); case Type::JALECO_JF35 : return new Jaleco::Jf35(c); case Type::JALECO_JF36 : return new Jaleco::Jf36(c); case Type::JALECO_JF37 : return new Jaleco::Jf37(c); case Type::JALECO_JF38 : return new Jaleco::Jf38(c); case Type::JALECO_JF39 : return new Jaleco::Jf39(c); case Type::JALECO_JF40 : return new Jaleco::Jf40(c); case Type::JALECO_JF41 : return new Jaleco::Jf41(c); case Type::JALECO_SS88006 : return new Jaleco::Ss88006(c); case Type::JYCOMPANY_TYPE_A : case Type::JYCOMPANY_TYPE_B : case Type::JYCOMPANY_TYPE_C : return new JyCompany::Standard(c); case Type::KAISER_KS202 : return new Kaiser::Ks202(c); case Type::KAISER_KS7010 : return new Kaiser::Ks7010(c); case Type::KAISER_KS7013B : return new Kaiser::Ks7013b(c); case Type::KAISER_KS7016 : return new Kaiser::Ks7016(c); case Type::KAISER_KS7022 : return new Kaiser::Ks7022(c); case Type::KAISER_KS7031 : return new Kaiser::Ks7031(c); case Type::KAISER_KS7032 : return new Kaiser::Ks7032(c); case Type::KAISER_KS7037 : return new Kaiser::Ks7037(c); case Type::KAISER_KS7057 : return new Kaiser::Ks7057(c); case Type::KAISER_KS7058 : return new Kaiser::Ks7058(c); case Type::KASING_STD : return new Kasing::Standard(c); case Type::KAY_H2288 : return new Kay::H2288(c); case Type::KAY_PANDAPRINCE : return new Kay::PandaPrince(c); case Type::KONAMI_VRC1 : return new Konami::Vrc1(c); case Type::KONAMI_VRC2 : return new Konami::Vrc2(c); case Type::KONAMI_VRC3 : return new Konami::Vrc3(c); case Type::KONAMI_VRC4_0 : case Type::KONAMI_VRC4_1 : case Type::KONAMI_VRC4_2 : return new Konami::Vrc4(c); case Type::KONAMI_VRC6_0 : case Type::KONAMI_VRC6_1 : return new Konami::Vrc6(c); case Type::KONAMI_VRC7_0 : case Type::KONAMI_VRC7_1 : return new Konami::Vrc7(c); case Type::KONAMI_VSSYSTEM : return new Konami::VsSystem(c); case Type::MAGICKIDGOOGOO : return new MagicKidGoogoo(c); case Type::MAGICSERIES_MAGICDRAGON : return new MagicSeries::MagicDragon(c); case Type::NAMCOT_3425 : return new Namcot::N3425(c); case Type::NAMCOT_3433 : return new Namcot::N3433(c); case Type::NAMCOT_3443 : return new Namcot::N3443(c); case Type::NAMCOT_3446 : return new Namcot::N3446(c); case Type::NAMCOT_34XX : return new Namcot::N34xx(c); case Type::NAMCOT_163_0 : case Type::NAMCOT_163_1 : case Type::NAMCOT_163_S_0 : case Type::NAMCOT_163_S_1 : return new Namcot::N163(c); case Type::NAMCOT_175 : return new Namcot::N175(c); case Type::NAMCOT_340 : return new Namcot::N340(c); case Type::NANJING_STD : return new Nanjing::Standard(c); case Type::UNL_UXROM_M5 : case Type::NIHON_UNROM_M5 : return new Nihon::UnRomM5(c); case Type::NITRA_TDA : return new Nitra::Tda(c); case Type::NTDEC_N715062 : return new Ntdec::N715062(c); case Type::NTDEC_ASDER_0 : case Type::NTDEC_ASDER_1 : return new Ntdec::Asder(c); case Type::NTDEC_FIGHTINGHERO : return new Ntdec::FightingHero(c); case Type::OPENCORP_DAOU306 : return new OpenCorp::Daou306(c); case Type::REXSOFT_SL1632 : return new RexSoft::Sl1632(c); case Type::REXSOFT_DBZ5 : return new RexSoft::Dbz5(c); case Type::RCM_GS2013 : return new Rcm::Gs2013(c); case Type::RCM_GS2015 : return new Rcm::Gs2015(c); case Type::RCM_GS2004 : return new Rcm::Gs2004(c); case Type::RCM_TETRISFAMILY : return new Rcm::TetrisFamily(c); case Type::SACHEN_8259A : case Type::SACHEN_8259B : case Type::SACHEN_8259C : case Type::SACHEN_8259D : return new Sachen::S8259(c); case Type::SACHEN_TCA01 : return new Sachen::Tca01(c); case Type::SACHEN_TCU01 : return new Sachen::Tcu01(c); case Type::SACHEN_TCU02 : return new Sachen::Tcu02(c); case Type::SACHEN_SA0036 : return new Sachen::Sa0036(c); case Type::SACHEN_SA0037 : return new Sachen::Sa0037(c); case Type::SACHEN_SA0161M : return new Sachen::Sa0161m(c); case Type::SACHEN_SA72007 : return new Sachen::Sa72007(c); case Type::SACHEN_SA72008 : return new Sachen::Sa72008(c); case Type::SACHEN_74_374A : return new Sachen::S74x374a(c); case Type::SACHEN_74_374B : return new Sachen::S74x374b(c); case Type::SOMERITEAM_SL12 : return new SomeriTeam::Sl12(c); case Type::SUBOR_TYPE0 : return new Subor::Type0(c); case Type::SUBOR_TYPE1 : return new Subor::Type1(c); case Type::SUBOR_STUDYNGAME : return new Subor::StudyNGame(c); case Type::SUNSOFT_1 : return new Sunsoft::S1(c); case Type::SUNSOFT_2A : return new Sunsoft::S2a(c); case Type::SUNSOFT_2B : return new Sunsoft::S2b(c); case Type::SUNSOFT_3 : return new Sunsoft::S3(c); case Type::SUNSOFT_4_0 : case Type::SUNSOFT_4_1 : return new Sunsoft::S4(c); case Type::SUNSOFT_5B_0 : case Type::SUNSOFT_5B_1 : return new Sunsoft::S5b(c); case Type::SUNSOFT_DCS : return new Sunsoft::Dcs(c); case Type::SUNSOFT_FME7_0 : case Type::SUNSOFT_FME7_1 : return new Sunsoft::Fme7(c); case Type::SUPERGAME_LIONKING : return new SuperGame::LionKing(c); case Type::SUPERGAME_BOOGERMAN : return new SuperGame::Boogerman(c); case Type::SUPERGAME_MK3E : return new SuperGame::Mk3e(c); case Type::SUPERGAME_POCAHONTAS2 : return new SuperGame::Pocahontas2(c); case Type::TAITO_TC0190FMC : return new Taito::Tc0190fmc(c); case Type::TAITO_TC0190FMC_PAL16R4 : return new Taito::Tc0190fmcPal16r4(c); case Type::TAITO_X1005 : return new Taito::X1005(c); case Type::TAITO_X1017 : return new Taito::X1017(c); case Type::TENGEN_800002 : return new Tengen::T800002(c); case Type::TENGEN_800004 : return new Tengen::T800004(c); case Type::TENGEN_800008 : return new Tengen::T800008(c); case Type::TENGEN_800030 : return new Tengen::T800030(c); case Type::TENGEN_800032 : return new Tengen::T800032(c); case Type::TENGEN_800037 : return new Tengen::T800037(c); case Type::TENGEN_800042 : return new Tengen::T800042(c); case Type::TXC_22211A : return new Txc::T22211A(c); case Type::TXC_22211B : return new Txc::T22211B(c); case Type::TXC_22211C : return new Txc::T22211C(c); case Type::TXC_MXMDHTWO : return new Txc::Mxmdhtwo(c); case Type::TXC_POLICEMAN : return new Txc::Policeman(c); case Type::TXC_TW : return new Txc::Tw(c); case Type::UNL_A9746 : return new Unlicensed::A9746(c); case Type::UNL_CC21 : return new Unlicensed::Cc21(c); case Type::UNL_EDU2000 : return new Unlicensed::Edu2000(c); case Type::UNL_FS304 : return new Waixing::Fs304(c); case Type::UNL_KINGOFFIGHTERS96 : return new Unlicensed::KingOfFighters96(c); case Type::UNL_KINGOFFIGHTERS97 : return new Unlicensed::KingOfFighters97(c); case Type::UNL_MORTALKOMBAT2 : return new Unlicensed::MortalKombat2(c); case Type::UNL_N625092 : return new Unlicensed::N625092(c); case Type::UNL_SUPERFIGHTER3 : return new Unlicensed::SuperFighter3(c); case Type::UNL_SHERO : return new Sachen::StreetHeroes(c); case Type::UNL_TF1201 : return new Unlicensed::Tf1201(c); case Type::UNL_WORLDHERO : return new Unlicensed::WorldHero(c); case Type::UNL_XZY : return new Unlicensed::Xzy(c); case Type::WAIXING_PS2_0 : case Type::WAIXING_PS2_1 : return new Waixing::Ps2(c); case Type::WAIXING_TYPE_A : return new Waixing::TypeA(c); case Type::WAIXING_TYPE_B : return new Waixing::TypeB(c); case Type::WAIXING_TYPE_C : return new Waixing::TypeC(c); case Type::WAIXING_TYPE_D : return new Waixing::TypeD(c); case Type::WAIXING_TYPE_E : return new Waixing::TypeE(c); case Type::WAIXING_TYPE_F : return new Waixing::TypeF(c); case Type::WAIXING_TYPE_G : return new Waixing::TypeG(c); case Type::WAIXING_TYPE_H : return new Waixing::TypeH(c); case Type::WAIXING_TYPE_I : return new Waixing::TypeI(c); case Type::WAIXING_TYPE_J : return new Waixing::TypeJ(c); case Type::WAIXING_FFV_0 : case Type::WAIXING_FFV_1 : return new Waixing::Ffv(c); case Type::WAIXING_SH2_0 : case Type::WAIXING_SH2_1 : return new Waixing::Sh2(c); case Type::WAIXING_ZS : return new Waixing::Zs(c); case Type::WAIXING_DQVII : return new Waixing::Dqv7(c); case Type::WAIXING_SGZ : return new Waixing::Sgz(c); case Type::WAIXING_SGZLZ : return new Waixing::Sgzlz(c); case Type::WAIXING_SECURITY_0 : case Type::WAIXING_SECURITY_1 : return new Waixing::Security(c); case Type::WHIRLWIND_2706 : return new Whirlwind::W2706(c); case Type::UNKNOWN : default: break; } return NULL; } void Board::Destroy(Board* board) { delete board; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } } nestopia-1.51.1/source/core/board/NstBoard.hpp000066400000000000000000001406761411157722000212030ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_H #define NST_BOARD_H #include "../NstCpu.hpp" #include "../NstPpu.hpp" #include "../NstChips.hpp" #include "../NstState.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class File; namespace Input { class Controllers; } namespace Boards { class NST_NO_VTABLE Board { public: class Type { public: enum Nmt { NMT_HORIZONTAL, NMT_VERTICAL, NMT_FOURSCREEN, NMT_SINGLESCREEN, NMT_CONTROLLED }; enum { NMPR = 100 }; private: enum NmtInit { NMT_X, NMT_H, NMT_V, NMT_Z, NMT_1, NMT_2, NMT_4 }; enum Cram { CRM_0, CRM_1, CRM_2, CRM_4, CRM_6, CRM_8, CRM_16, CRM_32 }; template struct MakeId { NST_COMPILE_ASSERT ( ( PROM >= 8 && PROM <= 4096 && !(PROM & (PROM-1U)) ) && ( !CROM || (CROM >= 8 && CROM <= 4096 && !(CROM & (CROM-1U))) ) && ( NVWRAM <= 64 && !(NVWRAM & (NVWRAM-1U)) ) && ( WRAM <= 64 && !(WRAM & (WRAM-1U))) && ( NVWRAM + WRAM <= 64 ) && ( CROM || CRAM >= CRM_8 ) && ( UNIQUE < 16 ) ); enum { ID = ( dword( MPR ) << 24 | dword( ValueBits< (PROM >> 4) >::VALUE ) << 20 | dword( ValueBits< (CROM >> 3) >::VALUE ) << 16 | dword( ValueBits< (NVWRAM >> 0) >::VALUE ) << 13 | dword( ValueBits< (WRAM >> 0) >::VALUE ) << 10 | dword( CRAM ) << 7 | dword( NMT ) << 4 | dword( UNIQUE ) << 0 ) }; }; public: enum Id { // NROM STD_NROM = MakeId< 0, 32, 8, 0, 0, CRM_0, NMT_X, 0 >::ID, // AxROM STD_AMROM = MakeId< 7, 128, 0, 0, 0, CRM_8, NMT_Z, 0 >::ID, STD_ANROM = MakeId< 7, 128, 0, 0, 0, CRM_8, NMT_Z, 1 >::ID, STD_AN1ROM = MakeId< 7, 64, 0, 0, 0, CRM_8, NMT_Z, 0 >::ID, STD_AOROM = MakeId< 7, 256, 0, 0, 0, CRM_8, NMT_Z, 0 >::ID, // BxROM STD_BNROM = MakeId< 34, 128, 0, 0, 0, CRM_8, NMT_X, 0 >::ID, // CxROM STD_CNROM = MakeId< 3, 32, 32, 0, 0, CRM_0, NMT_X, 0 >::ID, STD_CXROM = MakeId< 3, 32, 32, 0, 0, CRM_0, NMT_X, 1 >::ID, STD_CPROM = MakeId< 13, 32, 0, 0, 0, CRM_16, NMT_X, 0 >::ID, // DxROM STD_DEROM = MakeId< 206, 64, 64, 0, 0, CRM_0, NMT_X, 0 >::ID, STD_DE1ROM = MakeId< 206, 128, 64, 0, 0, CRM_0, NMT_X, 0 >::ID, STD_DRROM = MakeId< 206, 128, 64, 0, 0, CRM_0, NMT_2, 0 >::ID, // ExROM STD_ELROM = MakeId< 5, 512, 512, 0, 0, CRM_0, NMT_X, 0 >::ID, STD_EKROM = MakeId< 5, 512, 512, 8, 0, CRM_0, NMT_X, 0 >::ID, STD_ETROM = MakeId< 5, 512, 512, 8, 8, CRM_0, NMT_X, 0 >::ID, STD_EWROM = MakeId< 5, 512, 512, 32, 0, CRM_0, NMT_X, 0 >::ID, STD_EXROM_0 = MakeId< 5, 1024, 1024, 0, 0, CRM_0, NMT_X, 0 >::ID, STD_EXROM_1 = MakeId< 5, 1024, 1024, 8, 0, CRM_0, NMT_X, 0 >::ID, STD_EXROM_2 = MakeId< 5, 1024, 1024, 8, 8, CRM_0, NMT_X, 0 >::ID, STD_EXROM_3 = MakeId< 5, 1024, 1024, 32, 0, CRM_0, NMT_X, 0 >::ID, STD_EXROM_4 = MakeId< 5, 1024, 1024, 32, 8, CRM_0, NMT_X, 0 >::ID, STD_EXROM_5 = MakeId< 5, 1024, 1024, 32, 32, CRM_0, NMT_X, 0 >::ID, // FxROM STD_FJROM = MakeId< 10, 128, 128, 8, 0, CRM_0, NMT_V, 0 >::ID, STD_FKROM = MakeId< 10, 256, 128, 8, 0, CRM_0, NMT_V, 0 >::ID, // GxROM STD_GNROM = MakeId< 66, 128, 32, 0, 0, CRM_0, NMT_X, 0 >::ID, // MxROM STD_MHROM = MakeId< 66, 64, 32, 0, 0, CRM_0, NMT_X, 0 >::ID, // HxROM STD_HKROM = MakeId< 4, 512, 256, 0, 0, CRM_0, NMT_V, 0 >::ID, // JxROM STD_JLROM = MakeId< 69, 256, 256, 0, 0, CRM_0, NMT_V, 1 >::ID, STD_JSROM = MakeId< 69, 256, 256, 8, 0, CRM_0, NMT_V, 1 >::ID, // NxROM STD_NTBROM = MakeId< 68, 256, 128, 8, 0, CRM_0, NMT_V, 0 >::ID, // PxROM STD_PNROM = MakeId< 9, 128, 128, 0, 0, CRM_0, NMT_V, 0 >::ID, STD_PNROM_PC10 = MakeId< 9, 128, 128, 8, 0, CRM_0, NMT_V, 0 >::ID, STD_PEEOROM = MakeId< 9, 128, 128, 0, 0, CRM_0, NMT_V, 1 >::ID, // SxROM STD_SAROM = MakeId< 1, 64, 64, 8, 0, CRM_0, NMT_H, 0 >::ID, STD_SBROM = MakeId< 1, 64, 64, 0, 0, CRM_0, NMT_H, 0 >::ID, STD_SCROM = MakeId< 1, 64, 128, 0, 0, CRM_0, NMT_H, 0 >::ID, STD_SEROM = MakeId< 1, 32, 64, 0, 0, CRM_0, NMT_H, 0 >::ID, STD_SFROM = MakeId< 1, 256, 64, 0, 0, CRM_0, NMT_H, 0 >::ID, STD_SGROM = MakeId< 1, 256, 0, 0, 0, CRM_8, NMT_H, 0 >::ID, STD_SHROM = MakeId< 1, 32, 128, 0, 0, CRM_0, NMT_H, 0 >::ID, STD_SJROM = MakeId< 1, 256, 64, 8, 0, CRM_0, NMT_H, 0 >::ID, STD_SKROM = MakeId< 1, 256, 128, 8, 0, CRM_0, NMT_H, 0 >::ID, STD_SLROM = MakeId< 1, 256, 128, 0, 0, CRM_0, NMT_H, 0 >::ID, STD_SNROM = MakeId< 1, 256, 0, 8, 0, CRM_8, NMT_H, 0 >::ID, STD_SOROM = MakeId< 1, 256, 0, 8, 8, CRM_8, NMT_H, 0 >::ID, STD_SUROM = MakeId< 1, 512, 0, 8, 0, CRM_8, NMT_H, 0 >::ID, STD_SXROM = MakeId< 1, 512, 0, 32, 0, CRM_8, NMT_H, 0 >::ID, // TxROM STD_TEROM = MakeId< 4, 32, 64, 0, 0, CRM_0, NMT_X, 0 >::ID, STD_TBROM = MakeId< 4, 64, 64, 0, 0, CRM_0, NMT_X, 0 >::ID, STD_TFROM = MakeId< 4, 512, 64, 0, 0, CRM_0, NMT_X, 0 >::ID, STD_TGROM = MakeId< 4, 512, 0, 0, 0, CRM_8, NMT_X, 0 >::ID, STD_TKROM = MakeId< 4, 512, 256, 8, 0, CRM_0, NMT_X, 0 >::ID, STD_TKSROM = MakeId< 118, 512, 128, 8, 0, CRM_0, NMT_Z, 0 >::ID, STD_TLROM = MakeId< 4, 512, 256, 0, 0, CRM_0, NMT_X, 0 >::ID, STD_TLSROM = MakeId< 118, 512, 128, 0, 0, CRM_0, NMT_Z, 0 >::ID, STD_TNROM = MakeId< 4, 512, 0, 8, 0, CRM_8, NMT_X, 0 >::ID, STD_TQROM = MakeId< 119, 128, 64, 0, 0, CRM_8, NMT_V, 0 >::ID, STD_TR1ROM = MakeId< 4, 512, 64, 0, 0, CRM_0, NMT_4, 0 >::ID, STD_TSROM = MakeId< 4, 512, 256, 0, 8, CRM_0, NMT_X, 0 >::ID, STD_TVROM = MakeId< 4, 64, 64, 0, 0, CRM_0, NMT_4, 0 >::ID, // UxROM STD_UNROM = MakeId< 2, 128, 0, 0, 0, CRM_8, NMT_X, 0 >::ID, STD_UN1ROM = MakeId< 94, 128, 0, 0, 0, CRM_8, NMT_X, 0 >::ID, STD_UOROM = MakeId< 2, 256, 0, 0, 0, CRM_8, NMT_X, 0 >::ID, STD_UXROM = MakeId< 2, 256, 0, 0, 0, CRM_8, NMT_X, 1 >::ID, STD_UNROM512 = MakeId< 30, 512, 0, 0, 0, CRM_32, NMT_X, 0 >::ID, // Discrete Logic DISCRETE_74_377 = MakeId< 11, 128, 128, 0, 0, CRM_0, NMT_X, 0 >::ID, DISCRETE_74_139_74 = MakeId< 87, 32, 32, 0, 0, CRM_0, NMT_X, 4 >::ID, DISCRETE_74_161_138 = MakeId< 38, 128, 32, 0, 0, CRM_0, NMT_X, 0 >::ID, DISCRETE_74_161_161_32_A = MakeId< 70, 128, 128, 0, 0, CRM_0, NMT_X, 0 >::ID, DISCRETE_74_161_161_32_B = MakeId< 152, 128, 128, 0, 0, CRM_0, NMT_Z, 0 >::ID, // Other CUSTOM_B4 = MakeId< 4, 128, 128, 0, 0, CRM_0, NMT_V, 0 >::ID, CUSTOM_BTR = MakeId< 69, 512, 256, 8, 0, CRM_0, NMT_V, 0 >::ID, CUSTOM_EVENT = MakeId< 105, 256, 0, 8, 0, CRM_8, NMT_H, 0 >::ID, CUSTOM_FFE3 = MakeId< 8, 256, 256, 8, 0, CRM_0, NMT_X, 0 >::ID, CUSTOM_FFE4 = MakeId< 6, 256, 256, 8, 0, CRM_32, NMT_X, 0 >::ID, CUSTOM_FFE8 = MakeId< 17, 256, 256, 8, 0, CRM_0, NMT_X, 0 >::ID, CUSTOM_FB02 = MakeId< 0, 32, 8, 2, 0, CRM_0, NMT_X, 0 >::ID, CUSTOM_FB04 = MakeId< 0, 32, 8, 4, 0, CRM_0, NMT_X, 0 >::ID, CUSTOM_RUMBLESTATION = MakeId< 46, 1024, 1024, 0, 0, CRM_0, NMT_X, 0 >::ID, CUSTOM_QJ = MakeId< 47, 256, 256, 0, 0, CRM_0, NMT_V, 0 >::ID, CUSTOM_VSSYSTEM_0 = MakeId< 99, 64, 16, 0, 0, CRM_0, NMT_4, 0 >::ID, CUSTOM_VSSYSTEM_1 = MakeId< 99, 64, 16, 8, 0, CRM_0, NMT_4, 0 >::ID, CUSTOM_WH = MakeId< 1, 128, 64, 0, 0, CRM_0, NMT_H, 0 >::ID, CUSTOM_X79B = MakeId< 3, 32, 32, 8, 0, CRM_0, NMT_X, 0 >::ID, CUSTOM_ZZ = MakeId< 37, 256, 256, 0, 0, CRM_0, NMT_V, 0 >::ID, // Acclaim ACCLAIM_MCACC = MakeId< 4, 512, 256, 0, 0, CRM_0, NMT_X, 1 >::ID, // Action 53 ACTION53 = MakeId< 28, 1024, 0, 0, 0, CRM_32, NMT_X, 0 >::ID, // Active Enterprises AE_STD = MakeId< 228, 2048, 512, 0, 0, CRM_0, NMT_V, 0 >::ID, // AGCI AGCI_50282 = MakeId< 144, 64, 64, 0, 0, CRM_0, NMT_X, 0 >::ID, // AVE AVE_NINA001 = MakeId< 34, 64, 64, 8, 0, CRM_0, NMT_X, 0 >::ID, AVE_NINA002 = MakeId< 34, 64, 64, 8, 0, CRM_0, NMT_X, 1 >::ID, AVE_NINA03 = MakeId< 79, 32, 32, 0, 0, CRM_0, NMT_X, 0 >::ID, AVE_NINA06 = MakeId< 79, 64, 64, 0, 0, CRM_0, NMT_X, 0 >::ID, AVE_NINA07 = MakeId< 11, 128, 128, 0, 0, CRM_0, NMT_X, 1 >::ID, AVE_MB_91 = MakeId< 79, 64, 64, 0, 0, CRM_0, NMT_X, 1 >::ID, AVE_D1012 = MakeId< 234, 1024, 1024, 0, 0, CRM_0, NMT_V, 0 >::ID, // Bandai BANDAI_FCG1 = MakeId< 153, 256, 256, 0, 0, CRM_0, NMT_V, 0 >::ID, BANDAI_FCG2 = MakeId< 153, 256, 256, 0, 0, CRM_0, NMT_V, 1 >::ID, BANDAI_BAJUMP2 = MakeId< 153, 512, 0, 8, 0, CRM_8, NMT_V, 0 >::ID, BANDAI_LZ93D50_24C01 = MakeId< 159, 256, 256, 0, 0, CRM_0, NMT_V, 0 >::ID, BANDAI_LZ93D50_24C02 = MakeId< 16, 256, 256, 0, 0, CRM_0, NMT_V, 0 >::ID, BANDAI_DATACH = MakeId< 157, 256, 0, 0, 0, CRM_8, NMT_V, 0 >::ID, BANDAI_KARAOKESTUDIO = MakeId< 188, 256, 0, 0, 0, CRM_8, NMT_X, 0 >::ID, BANDAI_AEROBICSSTUDIO = MakeId< 3, 32, 32, 0, 0, CRM_0, NMT_X, 2 >::ID, BANDAI_OEKAKIDS = MakeId< 96, 128, 0, 0, 0, CRM_32, NMT_1, 0 >::ID, // Bensheng BENSHENG_BS5 = MakeId< 286, 128, 64, 0, 0, CRM_0, NMT_V, 2 >::ID, // Bootleg multicarts BMC_110IN1 = MakeId< 255, 2048, 1024, 0, 0, CRM_0, NMT_V, 0 >::ID, BMC_150IN1 = MakeId< 202, 128, 64, 0, 0, CRM_0, NMT_V, 0 >::ID, BMC_15IN1 = MakeId< 205, 512, 512, 0, 0, CRM_0, NMT_X, 0 >::ID, BMC_1200IN1 = MakeId< 227, 512, 0, 0, 0, CRM_8, NMT_V, 0 >::ID, BMC_20IN1 = MakeId< 231, 512, 0, 0, 0, CRM_8, NMT_V, 0 >::ID, BMC_21IN1 = MakeId< 201, 128, 32, 0, 0, CRM_0, NMT_V, 0 >::ID, BMC_22GAMES = MakeId< 230, 1024, 0, 0, 0, CRM_8, NMT_V, 0 >::ID, BMC_31IN1 = MakeId< 229, 512, 256, 0, 0, CRM_0, NMT_V, 0 >::ID, BMC_35IN1 = MakeId< 203, 128, 64, 0, 0, CRM_0, NMT_V, 0 >::ID, BMC_36IN1 = MakeId< 200, 128, 64, 0, 0, CRM_0, NMT_V, 0 >::ID, BMC_64IN1 = MakeId< 204, 128, 64, 0, 0, CRM_0, NMT_V, 0 >::ID, BMC_72IN1 = MakeId< 225, 1024, 512, 0, 0, CRM_0, NMT_V, 0 >::ID, BMC_76IN1 = MakeId< 226, 2048, 0, 0, 0, CRM_8, NMT_H, 0 >::ID, BMC_8157 = MakeId< 301, 512, 0, 0, 0, CRM_8, NMT_V, 0 >::ID, BMC_9999999IN1 = MakeId< 213, 128, 64, 0, 0, CRM_0, NMT_X, 0 >::ID, BMC_A65AS = MakeId< 285, 512, 0, 0, 0, CRM_8, NMT_V, 1 >::ID, BMC_BALLGAMES_11IN1 = MakeId< 51, 512, 0, 0, 0, CRM_8, NMT_V, 0 >::ID, BMC_CTC65 = MakeId< 226, 2048, 0, 0, 0, CRM_8, NMT_H, 1 >::ID, BMC_DRAGONBOLLPARTY = MakeId< 83, 1024, 1024, 8, 0, CRM_0, NMT_V, 0 >::ID, BMC_FAMILY_4646B = MakeId< 134, 512, 512, 0, 0, CRM_0, NMT_X, 0 >::ID, BMC_FKC23C = MakeId< 176, 1024, 1024, 0, 0, CRM_0, NMT_X, 0 >::ID, BMC_GAME_800IN1 = MakeId< 236, 512, 64, 0, 0, CRM_8, NMT_V, 0 >::ID, BMC_GOLDEN_190IN1 = MakeId< 300, 128, 64, 0, 0, CRM_0, NMT_V, 0 >::ID, BMC_GOLDENGAME_150IN1 = MakeId< 235, 2048, 0, 0, 0, CRM_8, NMT_V, 0 >::ID, BMC_GOLDENGAME_260IN1 = MakeId< 235, 4096, 0, 0, 0, CRM_8, NMT_V, 0 >::ID, BMC_GKA = MakeId< 57, 128, 128, 0, 0, CRM_0, NMT_V, 0 >::ID, BMC_GKB = MakeId< 58, 128, 64, 0, 0, CRM_0, NMT_V, 0 >::ID, BMC_GOLDENCARD_6IN1 = MakeId< 217, 1024, 1024, 0, 0, CRM_0, NMT_V, 0 >::ID, BMC_HERO = MakeId< 45, 4096, 2048, 8, 0, CRM_0, NMT_X, 0 >::ID, BMC_MARIOPARTY_7IN1 = MakeId< 52, 1024, 1024, 8, 0, CRM_0, NMT_V, 0 >::ID, BMC_NOVELDIAMOND = MakeId< 54, 128, 64, 0, 0, CRM_0, NMT_X, 0 >::ID, BMC_CH001 = MakeId< 63, 4096, 0, 0, 0, CRM_8, NMT_V, 0 >::ID, BMC_POWERJOY_84IN1 = MakeId< 126, 2048, 1024, 0, 0, CRM_0, NMT_X, 0 >::ID, BMC_RESETBASED_4IN1 = MakeId< 60, 64, 32, 0, 0, CRM_0, NMT_X, 0 >::ID, BMC_SUPER_24IN1 = MakeId< 176, 4096, 2048, 0, 0, CRM_8, NMT_X, 0 >::ID, BMC_SUPER_22GAMES = MakeId< 233, 1024, 0, 0, 0, CRM_8, NMT_Z, 0 >::ID, BMC_SUPER_40IN1 = MakeId< 332, 128, 64, 0, 0, CRM_0, NMT_V, 1 >::ID, BMC_SUPER_42IN1 = MakeId< 226, 1024, 0, 0, 0, CRM_8, NMT_H, 0 >::ID, BMC_SUPER_700IN1 = MakeId< 62, 2048, 1024, 0, 0, CRM_0, NMT_V, 0 >::ID, BMC_SUPERBIG_7IN1 = MakeId< 44, 1024, 1024, 0, 0, CRM_0, NMT_X, 0 >::ID, BMC_SUPERGUN_20IN1 = MakeId< 214, 64, 32, 0, 0, CRM_0, NMT_X, 0 >::ID, BMC_SUPERHIK_4IN1 = MakeId< 49, 512, 512, 0, 0, CRM_0, NMT_X, 0 >::ID, BMC_SUPERHIK_300IN1 = MakeId< 212, 128, 64, 0, 0, CRM_0, NMT_V, 0 >::ID, BMC_SUPERVISION_16IN1 = MakeId< 53, 4096, 0, 0, 0, CRM_8, NMT_V, 0 >::ID, BMC_T262 = MakeId< 265, 1024, 0, 0, 0, CRM_8, NMT_V, 0 >::ID, BMC_VRC4 = MakeId< 23, 512, 0, 8, 0, CRM_8, NMT_V, 0 >::ID, BMC_VT5201 = MakeId< 60, 128, 64, 0, 0, CRM_0, NMT_V, 0 >::ID, BMC_Y2K_64IN1 = MakeId< 314, 1024, 512, 0, 0, CRM_0, NMT_V, 0 >::ID, // Bootlegs BTL_2708 = MakeId< 103, 128, 0, 0, 16, CRM_8, NMT_V, 0 >::ID, BTL_6035052 = MakeId< 238, 512, 256, 0, 0, CRM_0, NMT_X, 0 >::ID, BTL_AISENSHINICOL = MakeId< 42, 128, 0, 0, 0, CRM_8, NMT_X, 0 >::ID, BTL_AX5705 = MakeId< 530, 128, 256, 0, 0, CRM_0, NMT_X, 0 >::ID, BTL_DRAGONNINJA = MakeId< 222, 128, 256, 0, 0, CRM_0, NMT_X, 0 >::ID, BTL_GENIUSMERIOBROS = MakeId< 55, 64, 8, 2, 0, CRM_0, NMT_X, 0 >::ID, BTL_MARIOBABY = MakeId< 42, 128, 128, 0, 0, CRM_0, NMT_X, 0 >::ID, BTL_PIKACHUY2K = MakeId< 254, 512, 256, 8, 0, CRM_0, NMT_X, 0 >::ID, BTL_SHUIGUANPIPE = MakeId< 183, 256, 128, 0, 0, CRM_0, NMT_X, 0 >::ID, BTL_SMB2_A = MakeId< 40, 64, 8, 0, 0, CRM_0, NMT_X, 0 >::ID, BTL_SMB2_B = MakeId< 50, 128, 0, 0, 0, CRM_8, NMT_X, 0 >::ID, BTL_SMB2_C = MakeId< 43, 128, 8, 0, 0, CRM_0, NMT_X, 0 >::ID, BTL_SMB3 = MakeId< 106, 256, 128, 8, 0, CRM_0, NMT_H, 0 >::ID, BTL_SUPERBROS11 = MakeId< 196, 512, 128, 0, 0, CRM_0, NMT_V, 0 >::ID, BTL_T230 = MakeId< 529, 256, 0, 0, 0, CRM_8, NMT_V, 0 >::ID, BTL_TOBIDASEDAISAKUSEN = MakeId< 120, 128, 8, 0, 0, CRM_0, NMT_X, 0 >::ID, // Camerica CAMERICA_BF9093 = MakeId< 71, 256, 0, 0, 0, CRM_8, NMT_X, 0 >::ID, CAMERICA_BF9096 = MakeId< 232, 256, 0, 0, 0, CRM_8, NMT_X, 0 >::ID, CAMERICA_BF9097 = MakeId< 71, 128, 0, 0, 0, CRM_8, NMT_Z, 0 >::ID, CAMERICA_BF909X = MakeId< 71, 256, 0, 0, 0, CRM_8, NMT_X, 1 >::ID, CAMERICA_ALGNV11 = MakeId< 71, 256, 0, 0, 0, CRM_8, NMT_X, 2 >::ID, CAMERICA_ALGQV11 = MakeId< 232, 256, 0, 0, 0, CRM_8, NMT_X, 1 >::ID, CAMERICA_GOLDENFIVE = MakeId< 104, 2048, 0, 0, 0, CRM_8, NMT_X, 0 >::ID, // Caltron CALTRON_6IN1 = MakeId< 41, 256, 128, 0, 0, CRM_0, NMT_V, 0 >::ID, // C&E CNE_SHLZ = MakeId< 240, 512, 128, 8, 0, CRM_0, NMT_X, 0 >::ID, CNE_DECATHLON = MakeId< 244, 128, 64, 0, 0, CRM_0, NMT_X, 0 >::ID, CNE_PSB = MakeId< 246, 512, 512, 8, 0, CRM_0, NMT_X, 0 >::ID, // Cony CONY_STD = MakeId< 83, 256, 512, 0, 0, CRM_0, NMT_V, 0 >::ID, // Dreamtech DREAMTECH01 = MakeId< 521, 256, 0, 0, 0, CRM_8, NMT_X, 0 >::ID, // Fujiya FUJIYA_STD = MakeId< 170, 32, 8, 0, 0, CRM_0, NMT_X, 0 >::ID, // Fukutake FUKUTAKE_SBX = MakeId< 186, 256, 0, 4, 0, CRM_8, NMT_X, 0 >::ID, // Future Media FUTUREMEDIA_STD = MakeId< 117, 256, 256, 0, 0, CRM_0, NMT_X, 0 >::ID, // Gouder GOUDER_37017 = MakeId< 208, 128, 256, 0, 0, CRM_0, NMT_X, 0 >::ID, // Henggedianzi HENGEDIANZI_STD = MakeId< 177, 1024, 8, 8, 0, CRM_0, NMT_V, 0 >::ID, HENGEDIANZI_XJZB = MakeId< 179, 512, 8, 8, 0, CRM_0, NMT_V, 0 >::ID, // HES HES_STD = MakeId< 113, 256, 128, 0, 0, CRM_0, NMT_H, 0 >::ID, // Hosenkan HOSENKAN_STD = MakeId< 182, 512, 256, 0, 0, CRM_0, NMT_X, 0 >::ID, // Infinite NES Lives INLNSF = MakeId< 31, 1024, 8, 0, 0, CRM_0, NMT_X, 0 >::ID, // Irem IREM_G101A_0 = MakeId< 32, 256, 128, 0, 0, CRM_0, NMT_V, 0 >::ID, IREM_G101A_1 = MakeId< 32, 256, 128, 8, 0, CRM_0, NMT_V, 0 >::ID, IREM_G101B_0 = MakeId< 32, 256, 128, 0, 0, CRM_0, NMT_Z, 0 >::ID, IREM_G101B_1 = MakeId< 32, 256, 128, 8, 0, CRM_0, NMT_Z, 0 >::ID, IREM_H3001 = MakeId< 65, 256, 256, 0, 0, CRM_0, NMT_X, 0 >::ID, IREM_LROG017 = MakeId< 77, 128, 32, 0, 0, CRM_6, NMT_2, 0 >::ID, IREM_HOLYDIVER = MakeId< 78, 128, 128, 0, 0, CRM_0, NMT_H, 0 >::ID, IREM_KAIKETSU = MakeId< 97, 256, 0, 0, 0, CRM_8, NMT_H, 0 >::ID, // Jaleco JALECO_JF01 = MakeId< 0, 16, 8, 0, 0, CRM_0, NMT_X, 1 >::ID, JALECO_JF02 = MakeId< 0, 16, 8, 0, 0, CRM_0, NMT_X, 2 >::ID, JALECO_JF03 = MakeId< 0, 16, 8, 0, 0, CRM_0, NMT_X, 3 >::ID, JALECO_JF04 = MakeId< 0, 16, 8, 0, 0, CRM_0, NMT_X, 4 >::ID, JALECO_JF05 = MakeId< 87, 16, 16, 0, 0, CRM_0, NMT_X, 0 >::ID, JALECO_JF06 = MakeId< 87, 16, 16, 0, 0, CRM_0, NMT_X, 1 >::ID, JALECO_JF07 = MakeId< 87, 32, 16, 0, 0, CRM_0, NMT_X, 0 >::ID, JALECO_JF08 = MakeId< 87, 32, 32, 0, 0, CRM_0, NMT_X, 1 >::ID, JALECO_JF09 = MakeId< 87, 32, 32, 0, 0, CRM_0, NMT_X, 2 >::ID, JALECO_JF10 = MakeId< 87, 32, 32, 0, 0, CRM_0, NMT_X, 3 >::ID, JALECO_JF11 = MakeId< 140, 128, 32, 0, 0, CRM_0, NMT_X, 0 >::ID, JALECO_JF12 = MakeId< 140, 128, 32, 0, 0, CRM_0, NMT_X, 1 >::ID, JALECO_JF13 = MakeId< 86, 128, 64, 0, 0, CRM_0, NMT_X, 0 >::ID, JALECO_JF14 = MakeId< 140, 128, 128, 0, 0, CRM_0, NMT_X, 0 >::ID, JALECO_JF15 = MakeId< 2, 256, 0, 0, 0, CRM_8, NMT_X, 2 >::ID, JALECO_JF16 = MakeId< 78, 128, 128, 0, 0, CRM_0, NMT_Z, 1 >::ID, JALECO_JF17 = MakeId< 72, 128, 128, 0, 0, CRM_0, NMT_X, 0 >::ID, JALECO_JF18 = MakeId< 2, 256, 0, 0, 0, CRM_8, NMT_X, 3 >::ID, JALECO_JF19 = MakeId< 92, 256, 128, 0, 0, CRM_0, NMT_X, 0 >::ID, JALECO_JF20 = MakeId< 75, 128, 128, 0, 0, CRM_0, NMT_V, 1 >::ID, JALECO_JF21 = MakeId< 92, 256, 128, 0, 0, CRM_0, NMT_X, 1 >::ID, JALECO_JF22 = MakeId< 75, 128, 128, 0, 0, CRM_0, NMT_V, 2 >::ID, JALECO_JF23 = MakeId< 18, 256, 128, 0, 0, CRM_0, NMT_H, 0 >::ID, JALECO_JF24 = MakeId< 18, 128, 128, 0, 0, CRM_0, NMT_H, 0 >::ID, JALECO_JF25 = MakeId< 18, 128, 128, 0, 0, CRM_0, NMT_H, 1 >::ID, JALECO_JF26 = MakeId< 72, 128, 128, 0, 0, CRM_0, NMT_X, 1 >::ID, JALECO_JF27 = MakeId< 18, 128, 128, 8, 0, CRM_0, NMT_H, 0 >::ID, JALECO_JF28 = MakeId< 72, 128, 128, 0, 0, CRM_0, NMT_X, 2 >::ID, JALECO_JF29 = MakeId< 18, 256, 128, 0, 0, CRM_0, NMT_H, 1 >::ID, JALECO_JF30 = MakeId< 18, 128, 128, 0, 0, CRM_0, NMT_H, 2 >::ID, JALECO_JF31 = MakeId< 18, 128, 128, 0, 0, CRM_0, NMT_H, 3 >::ID, JALECO_JF32 = MakeId< 18, 128, 128, 0, 0, CRM_0, NMT_H, 4 >::ID, JALECO_JF33 = MakeId< 18, 256, 128, 0, 0, CRM_0, NMT_H, 2 >::ID, JALECO_JF34 = MakeId< 18, 128, 128, 0, 0, CRM_0, NMT_H, 5 >::ID, JALECO_JF35 = MakeId< 18, 128, 128, 0, 0, CRM_0, NMT_H, 6 >::ID, JALECO_JF36 = MakeId< 18, 128, 128, 0, 0, CRM_0, NMT_H, 7 >::ID, JALECO_JF37 = MakeId< 18, 128, 256, 0, 0, CRM_0, NMT_H, 0 >::ID, JALECO_JF38 = MakeId< 18, 128, 128, 0, 0, CRM_0, NMT_H, 8 >::ID, JALECO_JF39 = MakeId< 2, 128, 0, 0, 0, CRM_8, NMT_X, 1 >::ID, JALECO_JF40 = MakeId< 18, 128, 128, 0, 0, CRM_0, NMT_H, 9 >::ID, JALECO_JF41 = MakeId< 18, 256, 128, 8, 0, CRM_0, NMT_H, 3 >::ID, JALECO_SS88006 = MakeId< 18, 256, 256, 8, 0, CRM_0, NMT_H, 4 >::ID, // J.Y.Company JYCOMPANY_TYPE_A = MakeId< 90, 2048, 2048, 0, 0, CRM_0, NMT_X, 0 >::ID, JYCOMPANY_TYPE_B = MakeId< 209, 2048, 2048, 0, 0, CRM_0, NMT_X, 0 >::ID, JYCOMPANY_TYPE_C = MakeId< 211, 2048, 2048, 0, 0, CRM_0, NMT_X, 0 >::ID, // Kaiser KAISER_KS202 = MakeId< 56, 256, 128, 8, 0, CRM_0, NMT_V, 0 >::ID, KAISER_KS7010 = MakeId< 554, 128, 128, 0, 0, CRM_0, NMT_V, 1 >::ID, KAISER_KS7013B = MakeId< 312, 128, 0, 0, 0, CRM_8, NMT_X, 0 >::ID, KAISER_KS7016 = MakeId< 306, 128, 0, 0, 0, CRM_8, NMT_V, 0 >::ID, KAISER_KS7022 = MakeId< 175, 256, 128, 0, 0, CRM_0, NMT_V, 0 >::ID, KAISER_KS7031 = MakeId< 305, 128, 0, 0, 0, CRM_8, NMT_V, 0 >::ID, KAISER_KS7032 = MakeId< 142, 128, 0, 0, 0, CRM_8, NMT_X, 0 >::ID, KAISER_KS7037 = MakeId< 307, 128, 0, 0, 8, CRM_8, NMT_X, 0 >::ID, KAISER_KS7057 = MakeId< 302, 128, 0, 0, 0, CRM_8, NMT_X, 0 >::ID, KAISER_KS7058 = MakeId< 171, 32, 32, 0, 0, CRM_0, NMT_X, 0 >::ID, // Kasing KASING_STD = MakeId< 115, 512, 512, 0, 0, CRM_0, NMT_V, 0 >::ID, // K KAY_H2288 = MakeId< 123, 512, 256, 8, 0, CRM_0, NMT_V, 0 >::ID, KAY_PANDAPRINCE = MakeId< 121, 256, 256, 0, 0, CRM_0, NMT_V, 0 >::ID, // Konami KONAMI_VRC1 = MakeId< 75, 128, 128, 0, 0, CRM_0, NMT_V, 0 >::ID, KONAMI_VRC2 = MakeId< 22, 128, 256, 0, 0, CRM_0, NMT_V, 0 >::ID, KONAMI_VRC3 = MakeId< 73, 128, 0, 8, 0, CRM_8, NMT_X, 0 >::ID, KONAMI_VRC4_0 = MakeId< 21, 256, 256, 0, 0, CRM_0, NMT_V, 0 >::ID, KONAMI_VRC4_1 = MakeId< 21, 256, 256, 2, 0, CRM_0, NMT_V, 0 >::ID, KONAMI_VRC4_2 = MakeId< 21, 256, 256, 8, 0, CRM_0, NMT_V, 0 >::ID, KONAMI_VRC6_0 = MakeId< 24, 256, 256, 0, 0, CRM_0, NMT_V, 0 >::ID, KONAMI_VRC6_1 = MakeId< 24, 256, 256, 8, 0, CRM_0, NMT_V, 0 >::ID, KONAMI_VRC7_0 = MakeId< 85, 512, 256, 0, 0, CRM_0, NMT_V, 0 >::ID, KONAMI_VRC7_1 = MakeId< 85, 512, 256, 8, 0, CRM_0, NMT_V, 0 >::ID, KONAMI_VSSYSTEM = MakeId< 151, 64, 64, 0, 0, CRM_0, NMT_4, 0 >::ID, //Magic Kid Googoo MAGICKIDGOOGOO = MakeId< 190, 256, 128, 8, 0, CRM_0, NMT_V, 0 >::ID, // Magic Series MAGICSERIES_MAGICDRAGON = MakeId< 107, 128, 64, 0, 0, CRM_0, NMT_X, 0 >::ID, // Namcot NAMCOT_3433 = MakeId< 88, 128, 128, 0, 0, CRM_0, NMT_H, 0 >::ID, NAMCOT_3443 = MakeId< 88, 128, 128, 0, 0, CRM_0, NMT_V, 0 >::ID, NAMCOT_3446 = MakeId< 76, 128, 128, 0, 0, CRM_0, NMT_X, 0 >::ID, NAMCOT_3425 = MakeId< 95, 128, 128, 0, 0, CRM_0, NMT_Z, 0 >::ID, NAMCOT_34XX = MakeId< 154, 128, 128, 0, 0, CRM_0, NMT_Z, 0 >::ID, NAMCOT_163_0 = MakeId< 19, 512, 256, 0, 0, CRM_0, NMT_X, 0 >::ID, NAMCOT_163_1 = MakeId< 19, 512, 256, 8, 0, CRM_0, NMT_X, 0 >::ID, NAMCOT_163_S_0 = MakeId< 19, 512, 256, 0, 0, CRM_0, NMT_X, 1 >::ID, NAMCOT_163_S_1 = MakeId< 19, 512, 256, 8, 0, CRM_0, NMT_X, 1 >::ID, NAMCOT_175 = MakeId< 210, 512, 128, 8, 0, CRM_0, NMT_V, 0 >::ID, NAMCOT_340 = MakeId< 210, 256, 256, 0, 0, CRM_0, NMT_X, 0 >::ID, // Nitra NITRA_TDA = MakeId< 250, 512, 256, 0, 0, CRM_0, NMT_V, 0 >::ID, // NTDEC NTDEC_N715062 = MakeId< 3, 32, 32, 0, 0, CRM_0, NMT_X, 3 >::ID, NTDEC_ASDER_0 = MakeId< 112, 256, 512, 0, 0, CRM_0, NMT_X, 0 >::ID, NTDEC_ASDER_1 = MakeId< 112, 256, 512, 8, 0, CRM_0, NMT_X, 0 >::ID, NTDEC_FIGHTINGHERO = MakeId< 193, 128, 256, 0, 0, CRM_0, NMT_X, 0 >::ID, // Nanjing NANJING_STD = MakeId< 163, 2048, 0, 8, 0, CRM_8, NMT_X, 0 >::ID, // Nihon Bussan NIHON_UNROM_M5 = MakeId< 180, 128, 0, 0, 0, CRM_8, NMT_X, 0 >::ID, // Open Corp OPENCORP_DAOU306 = MakeId< 156, 256, 512, 8, 0, CRM_0, NMT_1, 0 >::ID, // RCM RCM_GS2004 = MakeId< 283, 256, 0, 0, 0, CRM_8, NMT_X, 0 >::ID, RCM_GS2013 = MakeId< 283, 512, 0, 0, 0, CRM_8, NMT_X, 1 >::ID, RCM_GS2015 = MakeId< 216, 64, 64, 0, 0, CRM_0, NMT_X, 0 >::ID, RCM_TETRISFAMILY = MakeId< 61, 512, 0, 0, 0, CRM_8, NMT_V, 0 >::ID, // Rex Soft REXSOFT_DBZ5 = MakeId< 12, 256, 512, 0, 0, CRM_0, NMT_V, 0 >::ID, REXSOFT_SL1632 = MakeId< 14, 256, 512, 0, 0, CRM_0, NMT_V, 0 >::ID, // Sachen SACHEN_8259A = MakeId< 141, 256, 256, 0, 0, CRM_0, NMT_X, 0 >::ID, SACHEN_8259B = MakeId< 138, 256, 256, 0, 0, CRM_0, NMT_X, 0 >::ID, SACHEN_8259C = MakeId< 139, 256, 256, 0, 0, CRM_0, NMT_X, 0 >::ID, SACHEN_8259D = MakeId< 137, 256, 256, 0, 0, CRM_0, NMT_X, 0 >::ID, SACHEN_TCA01 = MakeId< 143, 32, 8, 0, 0, CRM_0, NMT_X, 0 >::ID, SACHEN_TCU01 = MakeId< 147, 128, 128, 0, 0, CRM_0, NMT_X, 0 >::ID, SACHEN_TCU02 = MakeId< 136, 32, 32, 0, 0, CRM_0, NMT_X, 0 >::ID, SACHEN_SA0036 = MakeId< 149, 32, 16, 0, 0, CRM_0, NMT_X, 0 >::ID, SACHEN_SA0037 = MakeId< 148, 64, 64, 0, 0, CRM_0, NMT_X, 0 >::ID, SACHEN_SA0161M = MakeId< 146, 64, 64, 0, 0, CRM_0, NMT_X, 0 >::ID, SACHEN_SA72007 = MakeId< 145, 16, 16, 0, 0, CRM_0, NMT_X, 0 >::ID, SACHEN_SA72008 = MakeId< 133, 64, 32, 0, 0, CRM_0, NMT_X, 0 >::ID, SACHEN_74_374A = MakeId< 243, 64, 128, 0, 0, CRM_0, NMT_V, 0 >::ID, SACHEN_74_374B = MakeId< 150, 64, 128, 0, 0, CRM_0, NMT_X, 0 >::ID, // Someri Team SOMERITEAM_SL12 = MakeId< 116, 256, 512, 0, 0, CRM_0, NMT_X, 0 >::ID, // Subor SUBOR_TYPE0 = MakeId< 167, 1024, 0, 8, 0, CRM_8, NMT_X, 0 >::ID, SUBOR_TYPE1 = MakeId< 166, 1024, 0, 8, 0, CRM_8, NMT_X, 0 >::ID, SUBOR_STUDYNGAME = MakeId< 39, 1024, 0, 8, 0, CRM_8, NMT_X, 0 >::ID, // Sunsoft SUNSOFT_1 = MakeId< 184, 32, 32, 0, 0, CRM_0, NMT_X, 0 >::ID, SUNSOFT_2A = MakeId< 93, 128, 128, 0, 0, CRM_0, NMT_X, 0 >::ID, SUNSOFT_2B = MakeId< 89, 128, 128, 0, 0, CRM_0, NMT_Z, 0 >::ID, SUNSOFT_3 = MakeId< 67, 128, 128, 0, 0, CRM_0, NMT_V, 0 >::ID, SUNSOFT_4_0 = MakeId< 68, 128, 256, 0, 0, CRM_0, NMT_V, 0 >::ID, SUNSOFT_4_1 = MakeId< 68, 128, 256, 8, 0, CRM_0, NMT_V, 0 >::ID, SUNSOFT_5B_0 = MakeId< 69, 256, 256, 0, 0, CRM_0, NMT_V, 2 >::ID, SUNSOFT_5B_1 = MakeId< 69, 256, 256, 8, 0, CRM_0, NMT_V, 2 >::ID, SUNSOFT_DCS = MakeId< 68, 256, 256, 8, 0, CRM_0, NMT_V, 0 >::ID, SUNSOFT_FME7_0 = MakeId< 69, 256, 256, 0, 0, CRM_0, NMT_V, 0 >::ID, SUNSOFT_FME7_1 = MakeId< 69, 256, 256, 8, 0, CRM_0, NMT_V, 0 >::ID, // Super Game SUPERGAME_LIONKING = MakeId< 114, 256, 512, 0, 0, CRM_0, NMT_V, 0 >::ID, SUPERGAME_BOOGERMAN = MakeId< 215, 512, 512, 0, 0, CRM_0, NMT_X, 0 >::ID, SUPERGAME_MK3E = MakeId< 215, 256, 512, 0, 0, CRM_0, NMT_X, 0 >::ID, SUPERGAME_POCAHONTAS2 = MakeId< NMPR, 512, 512, 0, 0, CRM_0, NMT_X, 0 >::ID, // Taito TAITO_TC0190FMC = MakeId< 33, 256, 256, 0, 0, CRM_0, NMT_V, 0 >::ID, TAITO_TC0190FMC_PAL16R4 = MakeId< 48, 256, 256, 0, 0, CRM_0, NMT_V, 0 >::ID, TAITO_X1005 = MakeId< 80, 256, 256, 0, 0, CRM_0, NMT_X, 0 >::ID, TAITO_X1017 = MakeId< 82, 256, 256, 0, 0, CRM_0, NMT_H, 0 >::ID, // Tengen TENGEN_800002 = MakeId< 206, 64, 64, 0, 0, CRM_0, NMT_X, 1 >::ID, TENGEN_800004 = MakeId< 206, 128, 64, 0, 0, CRM_0, NMT_2, 1 >::ID, TENGEN_800008 = MakeId< 3, 64, 64, 0, 0, CRM_0, NMT_X, 0 >::ID, TENGEN_800030 = MakeId< 206, 128, 64, 0, 0, CRM_0, NMT_X, 1 >::ID, TENGEN_800032 = MakeId< 64, 128, 256, 0, 0, CRM_0, NMT_V, 0 >::ID, TENGEN_800037 = MakeId< 158, 128, 128, 0, 0, CRM_0, NMT_Z, 0 >::ID, TENGEN_800042 = MakeId< 68, 128, 256, 0, 0, CRM_0, NMT_V, 1 >::ID, // TXC TXC_22211A = MakeId< 132, 64, 32, 0, 0, CRM_0, NMT_X, 0 >::ID, TXC_22211B = MakeId< 172, 64, 32, 0, 0, CRM_0, NMT_X, 0 >::ID, TXC_22211C = MakeId< 173, 64, 32, 0, 0, CRM_0, NMT_X, 0 >::ID, TXC_MXMDHTWO = MakeId< 241, 1024, 0, 8, 0, CRM_8, NMT_X, 0 >::ID, TXC_POLICEMAN = MakeId< 36, 512, 128, 0, 0, CRM_0, NMT_X, 0 >::ID, TXC_TW = MakeId< 189, 128, 256, 0, 0, CRM_0, NMT_X, 0 >::ID, // Unlicensed UNL_A9746 = MakeId< 219, 128, 256, 0, 0, CRM_0, NMT_X, 0 >::ID, UNL_CC21 = MakeId< 27, 32, 8, 0, 0, CRM_0, NMT_Z, 0 >::ID, UNL_EDU2000 = MakeId< 329, 1024, 0, 0, 32, CRM_8, NMT_Z, 0 >::ID, UNL_FS304 = MakeId< 162, 2048, 0, 8, 0, CRM_8, NMT_X, 0 >::ID, UNL_KINGOFFIGHTERS96 = MakeId< 187, 512, 512, 0, 0, CRM_0, NMT_X, 0 >::ID, UNL_KINGOFFIGHTERS97 = MakeId< 263, 256, 256, 0, 0, CRM_0, NMT_X, 0 >::ID, UNL_MORTALKOMBAT2 = MakeId< 91, 256, 512, 0, 0, CRM_0, NMT_X, 0 >::ID, UNL_N625092 = MakeId< 221, 1024, 8, 0, 0, CRM_0, NMT_V, 0 >::ID, UNL_SUPERFIGHTER3 = MakeId< 197, 512, 512, 0, 0, CRM_0, NMT_X, 0 >::ID, UNL_SHERO = MakeId< 262, 512, 512, 0, 0, CRM_8, NMT_4, 0 >::ID, UNL_TF1201 = MakeId< 298, 128, 128, 0, 0, CRM_0, NMT_V, 0 >::ID, UNL_WORLDHERO = MakeId< 27, 128, 512, 0, 0, CRM_0, NMT_X, 0 >::ID, UNL_AXROM = MakeId< 7, 512, 8, 8, 0, CRM_0, NMT_Z, 0 >::ID, UNL_BXROM = MakeId< 34, 4096, 8, 8, 0, CRM_8, NMT_X, 0 >::ID, UNL_CXROM = MakeId< 3, 32, 2048, 8, 0, CRM_0, NMT_X, 0 >::ID, UNL_GXROM = MakeId< 66, 512, 128, 8, 0, CRM_0, NMT_X, 0 >::ID, UNL_NROM = MakeId< 0, 32, 8, 8, 0, CRM_8, NMT_X, 0 >::ID, UNL_UXROM = MakeId< 2, 4096, 8, 8, 0, CRM_0, NMT_X, 0 >::ID, UNL_UXROM_M5 = MakeId< 180, 4096, 8, 8, 0, CRM_0, NMT_X, 0 >::ID, UNL_TRXROM = MakeId< 4, 512, 256, 8, 0, CRM_0, NMT_4, 0 >::ID, UNL_XZY = MakeId< 176, 1024, 256, 8, 0, CRM_0, NMT_X, 0 >::ID, UNL_MMC3BIGCHRRAM = MakeId< 4, 512, 0, 0, 0, CRM_32, NMT_X, 0 >::ID, // Waixing WAIXING_PS2_0 = MakeId< 15, 1024, 0, 0, 0, CRM_8, NMT_V, 0 >::ID, WAIXING_PS2_1 = MakeId< 15, 1024, 0, 8, 0, CRM_8, NMT_V, 0 >::ID, WAIXING_TYPE_A = MakeId< 74, 1024, 256, 8, 1, CRM_2, NMT_X, 0 >::ID, WAIXING_TYPE_B = MakeId< 191, 512, 256, 8, 1, CRM_2, NMT_X, 0 >::ID, WAIXING_TYPE_C = MakeId< 192, 512, 256, 8, 1, CRM_4, NMT_X, 0 >::ID, WAIXING_TYPE_D = MakeId< 194, 512, 256, 8, 1, CRM_2, NMT_X, 0 >::ID, WAIXING_TYPE_E = MakeId< 195, 512, 256, 8, 1, CRM_4, NMT_X, 0 >::ID, WAIXING_TYPE_F = MakeId< 198, 1024, 0, 8, 1, CRM_8, NMT_X, 0 >::ID, WAIXING_TYPE_G = MakeId< 199, 512, 256, 8, 1, CRM_8, NMT_X, 0 >::ID, WAIXING_TYPE_H = MakeId< 245, 1024, 256, 8, 0, CRM_0, NMT_X, 0 >::ID, WAIXING_TYPE_I = MakeId< 223, 512, 256, 8, 1, CRM_0, NMT_X, 0 >::ID, WAIXING_TYPE_J = MakeId< 224, 1024, 256, 8, 1, CRM_0, NMT_X, 0 >::ID, WAIXING_FFV_0 = MakeId< 164, 1024, 32, 0, 0, CRM_8, NMT_X, 0 >::ID, WAIXING_FFV_1 = MakeId< 164, 1024, 32, 8, 0, CRM_8, NMT_X, 0 >::ID, WAIXING_SH2_0 = MakeId< 165, 512, 256, 0, 0, CRM_4, NMT_X, 0 >::ID, WAIXING_SH2_1 = MakeId< 165, 512, 256, 8, 0, CRM_4, NMT_X, 0 >::ID, WAIXING_SGZLZ = MakeId< 178, 1024, 0, 8, 0, CRM_8, NMT_X, 0 >::ID, WAIXING_ZS = MakeId< 242, 512, 0, 8, 0, CRM_8, NMT_V, 0 >::ID, WAIXING_DQVII = MakeId< 242, 512, 0, 8, 0, CRM_8, NMT_X, 0 >::ID, WAIXING_SGZ = MakeId< 252, 512, 256, 8, 0, CRM_0, NMT_X, 0 >::ID, WAIXING_SECURITY_0 = MakeId< 249, 512, 256, 0, 0, CRM_0, NMT_V, 0 >::ID, WAIXING_SECURITY_1 = MakeId< 249, 512, 256, 8, 0, CRM_0, NMT_V, 0 >::ID, // Whirlwind WHIRLWIND_2706 = MakeId< 108, 128, 0, 0, 0, CRM_8, NMT_X, 0 >::ID, // Unknown UNKNOWN = 0 }; Type(); Type(Id,Ram&,Ram&,Nmt,bool,bool); uint GetMapper() const; dword GetMaxPrg() const; dword GetMaxChr() const; uint GetWram() const; uint GetSavableWram() const; uint GetNonSavableWram() const; uint GetChrRam() const; uint GetNmtRam() const; uint GetVram() const; uint GetSavableVram() const; uint GetNonSavableVram() const; Nmt GetStartupNmt() const; private: Id id; byte nmt; byte chrRam; bool battery; bool wramAuto; public: Id GetId() const { return id; } bool operator == (Id i) const { return id == i; } bool operator != (Id i) const { return id != i; } Nmt GetNmt() const { return static_cast(nmt); } bool HasBattery() const { return battery; } bool IsAutoWram() const { return wramAuto; } }; class Context { struct Element; public: Context(Cpu*,Apu*,Ppu*,Ram&,Ram&,const Ram&,Type::Nmt,bool,bool,Chips&); bool DetectBoard(wcstring,dword); bool DetectBoard(word,byte,dword,dword,bool); cstring name; Type type; Cpu* const cpu; Apu* const apu; Ppu* const ppu; Ram& prg; Ram& chr; const Ram& trainer; const Type::Nmt nmt; Chips& chips; const bool wramBattery; const bool mmcBattery; }; static Board* Create(const Context&); static void Destroy(Board*); void Reset(bool); virtual void Load(File&); virtual void Save(File&) const; void SaveState(State::Saver&,dword) const; void LoadState(State::Loader&); enum Event { EVENT_END_FRAME, EVENT_BEGIN_FRAME, EVENT_POWER_OFF }; virtual void Sync(Event,Input::Controllers*) {}; typedef void* Device; enum DeviceType { DEVICE_DIP_SWITCHES = 1, DEVICE_BARCODE_READER }; virtual Device QueryDevice(DeviceType) { return NULL; } protected: explicit Board(const Context&); virtual ~Board() {} typedef Memory Prg; typedef Memory Wrk; typedef Ppu::ChrMem Chr; typedef Ppu::NmtMem Nmt; typedef Ram Vram; Prg prg; Cpu& cpu; Ppu& ppu; Chr& chr; Nmt& nmt; Wrk wrk; const Vram vram; const Type board; private: virtual void SubReset(bool) = 0; virtual void SubSave(State::Saver&) const {} virtual void SubLoad(State::Loader&,dword) {} NES_DECL_PEEK( Prg_8 ); NES_DECL_PEEK( Prg_A ); NES_DECL_PEEK( Prg_C ); NES_DECL_PEEK( Prg_E ); NES_DECL_POKE( Prg_8k_0 ); NES_DECL_POKE( Prg_8k_0_bc ); NES_DECL_POKE( Prg_8k_1 ); NES_DECL_POKE( Prg_8k_2 ); NES_DECL_POKE( Prg_8k_3 ); NES_DECL_POKE( Prg_16k_0 ); NES_DECL_POKE( Prg_16k_0_bc ); NES_DECL_POKE( Prg_16k_1 ); NES_DECL_POKE( Prg_32k ); NES_DECL_POKE( Prg_32k_bc ); NES_DECL_POKE( Chr_1k_0 ); NES_DECL_POKE( Chr_1k_1 ); NES_DECL_POKE( Chr_1k_2 ); NES_DECL_POKE( Chr_1k_3 ); NES_DECL_POKE( Chr_1k_4 ); NES_DECL_POKE( Chr_1k_5 ); NES_DECL_POKE( Chr_1k_6 ); NES_DECL_POKE( Chr_1k_7 ); NES_DECL_POKE( Chr_2k_0 ); NES_DECL_POKE( Chr_2k_1 ); NES_DECL_POKE( Chr_2k_2 ); NES_DECL_POKE( Chr_2k_3 ); NES_DECL_POKE( Chr_4k_0 ); NES_DECL_POKE( Chr_4k_1 ); NES_DECL_POKE( Chr_4k_1_bc ); NES_DECL_POKE( Chr_8k ); NES_DECL_POKE( Chr_8k_bc ); NES_DECL_PEEK( Wram_6 ); NES_DECL_POKE( Wram_6 ); NES_DECL_POKE( Nmt_Hv ); NES_DECL_POKE( Nmt_Vh ); NES_DECL_POKE( Nmt_Vh01 ); NES_DECL_POKE( Nmt_Hv01 ); NES_DECL_PEEK( Nop ); NES_DECL_POKE( Nop ); protected: enum PrgSwap8k0 { PRG_SWAP_8K_0 }; enum PrgSwap8k0Bc { PRG_SWAP_8K_0_BC }; enum PrgSwap8k1 { PRG_SWAP_8K_1 }; enum PrgSwap8k2 { PRG_SWAP_8K_2 }; enum PrgSwap8k3 { PRG_SWAP_8K_3 }; enum PrgSwap16k0 { PRG_SWAP_16K_0 }; enum PrgSwap16k0Bc { PRG_SWAP_16K_0_BC }; enum PrgSwap16k1 { PRG_SWAP_16K_1 }; enum PrgSwap32k { PRG_SWAP_32K }; enum PrgSwap32kBc { PRG_SWAP_32K_BC }; enum ChrSwap1k0 { CHR_SWAP_1K_0 }; enum ChrSwap1k1 { CHR_SWAP_1K_1 }; enum ChrSwap1k2 { CHR_SWAP_1K_2 }; enum ChrSwap1k3 { CHR_SWAP_1K_3 }; enum ChrSwap1k4 { CHR_SWAP_1K_4 }; enum ChrSwap1k5 { CHR_SWAP_1K_5 }; enum ChrSwap1k6 { CHR_SWAP_1K_6 }; enum ChrSwap1k7 { CHR_SWAP_1K_7 }; enum ChrSwap2k0 { CHR_SWAP_2K_0 }; enum ChrSwap2k1 { CHR_SWAP_2K_1 }; enum ChrSwap2k2 { CHR_SWAP_2K_2 }; enum ChrSwap2k3 { CHR_SWAP_2K_3 }; enum ChrSwap4k0 { CHR_SWAP_4K_0 }; enum ChrSwap4k1 { CHR_SWAP_4K_1 }; enum ChrSwap4k1Bc { CHR_SWAP_4K_1_BC }; enum ChrSwap8k { CHR_SWAP_8K }; enum ChrSwap8kBc { CHR_SWAP_8K_BC }; enum NmtSwapHv { NMT_SWAP_HV }; enum NmtSwapVh { NMT_SWAP_VH }; enum NmtSwapVh01 { NMT_SWAP_VH01 }; enum NmtSwapHv01 { NMT_SWAP_HV01 }; enum NopPeek { NOP_PEEK }; enum NopPoke { NOP_POKE }; enum NopPeekPoke { NOP_PEEK_POKE }; uint GetBusData(uint,uint=0xFF) const; void SetMirroringHV(uint data) { NES_DO_POKE(Nmt_Hv,0,data); } void SetMirroringVH(uint data) { NES_DO_POKE(Nmt_Vh,0,data); } void SetMirroringVH01(uint data) { NES_DO_POKE(Nmt_Vh01,0,data); } void SetMirroringHV01(uint data) { NES_DO_POKE(Nmt_Hv01,0,data); } void Map( uint,uint,PrgSwap8k0 ) const; void Map( uint,uint,PrgSwap8k1 ) const; void Map( uint,uint,PrgSwap8k2 ) const; void Map( uint,uint,PrgSwap8k3 ) const; void Map( uint,uint,PrgSwap16k0 ) const; void Map( uint,uint,PrgSwap16k1 ) const; void Map( uint,uint,PrgSwap32k ) const; void Map( uint,uint,ChrSwap1k0 ) const; void Map( uint,uint,ChrSwap1k1 ) const; void Map( uint,uint,ChrSwap1k2 ) const; void Map( uint,uint,ChrSwap1k3 ) const; void Map( uint,uint,ChrSwap1k4 ) const; void Map( uint,uint,ChrSwap1k5 ) const; void Map( uint,uint,ChrSwap1k6 ) const; void Map( uint,uint,ChrSwap1k7 ) const; void Map( uint,uint,ChrSwap2k0 ) const; void Map( uint,uint,ChrSwap2k1 ) const; void Map( uint,uint,ChrSwap2k2 ) const; void Map( uint,uint,ChrSwap2k3 ) const; void Map( uint,uint,ChrSwap4k0 ) const; void Map( uint,uint,ChrSwap4k1 ) const; void Map( uint,uint,ChrSwap8k ) const; void Map( uint,uint,NmtSwapHv ) const; void Map( uint,uint,NmtSwapVh ) const; void Map( uint,uint,NmtSwapVh01 ) const; void Map( uint,uint,NmtSwapHv01 ) const; void Map( uint,uint,NopPeek ) const; void Map( uint,uint,NopPoke ) const; void Map( uint,uint,NopPeekPoke ) const; void Map( PrgSwap8k0Bc ) const; void Map( PrgSwap16k0Bc ) const; void Map( PrgSwap32kBc ) const; void Map( ChrSwap4k1Bc ) const; void Map( ChrSwap8kBc ) const; template void Map(uint first,uint last,T t) const { cpu.Map( first, last ).Set( t ); } template void Map(uint first,uint last,T t,U u) const { cpu.Map( first, last ).Set( t, u ); } template void Map(uint address,T t) const { Map( address, address, t ); } template void Map(uint address,T t,U u) const { cpu.Map( address ).Set( t, u ); } }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardAcclaim.hpp000066400000000000000000000023111411157722000224340ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_ACCLAIM_H #define NST_BOARD_ACCLAIM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "../NstFile.hpp" #include "NstBoardAcclaimMcAcc.hpp" #endif nestopia-1.51.1/source/core/board/NstBoardAcclaimMcAcc.cpp000066400000000000000000000147551411157722000233350ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstLog.hpp" #include "NstBoard.hpp" #include "NstBoardAcclaimMcAcc.hpp" namespace Nes { namespace Core { namespace Boards { namespace Acclaim { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif McAcc::McAcc(const Context& c) : Board (c), irq (*c.cpu,*c.ppu,true) { } void McAcc::SubReset(const bool hard) { if (hard) { regs.ctrl0 = 0; regs.ctrl1 = 0; banks.prg[0] = 0x00; banks.prg[1] = 0x01; banks.prg[2] = 0x3E; banks.prg[3] = 0x3F; for (uint i=0; i < 8; ++i) banks.chr[i] = i; wrk.Source().SetSecurity( false, false ); } irq.Reset( hard ); for (uint i=0x0000; i < 0x2000; i += 0x2) { Map( 0x8000 + i, &McAcc::Poke_8000 ); Map( 0x8001 + i, &McAcc::Poke_8001 ); Map( 0xA001 + i, &McAcc::Poke_A001 ); Map( 0xC000 + i, &McAcc::Poke_C000 ); Map( 0xC001 + i, &McAcc::Poke_C001 ); Map( 0xE000 + i, &McAcc::Poke_E000 ); Map( 0xE001 + i, &McAcc::Poke_E001 ); } if (board.GetNmt() != Type::NMT_FOURSCREEN) { for (uint i=0x0000; i < 0x2000; i += 0x2) Map( 0xA000 + i, NMT_SWAP_HV ); } UpdatePrg(); UpdateChr(); } void McAcc::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'M','A','C'>::V) ); if (baseChunk == AsciiId<'M','A','C'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: { State::Loader::Data<12> data( state ); regs.ctrl0 = data[0]; regs.ctrl1 = data[1]; banks.prg[0] = data[2] & 0x3FU; banks.prg[1] = data[3] & 0x3FU; banks.chr[0] = (data[6] & 0x7FU) << 1; banks.chr[1] = banks.chr[0] | 0x01U; banks.chr[2] = (data[7] & 0x7FU) << 1; banks.chr[3] = banks.chr[2] | 0x01U; banks.chr[4] = data[8]; banks.chr[5] = data[9]; banks.chr[6] = data[10]; banks.chr[7] = data[11]; break; } case AsciiId<'I','R','Q'>::V: irq.unit.LoadState( state ); break; } state.End(); } } } void McAcc::SubSave(State::Saver& state) const { state.Begin( AsciiId<'M','A','C'>::V ); const byte data[12] = { regs.ctrl0, regs.ctrl1, banks.prg[0], banks.prg[1], 0x3E, 0x3F, banks.chr[0] >> 1, banks.chr[2] >> 1, banks.chr[4], banks.chr[5], banks.chr[6], banks.chr[7] }; state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End(); irq.unit.SaveState( state, AsciiId<'I','R','Q'>::V ); state.End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(McAcc,8000) { const uint diff = regs.ctrl0 ^ data; regs.ctrl0 = data; if (diff & 0x40) { const uint v[2] = { banks.prg[(data >> 5 & 0x2) ^ 0], banks.prg[(data >> 5 & 0x2) ^ 2] }; UpdatePrg( 0x0000, v[0] ); UpdatePrg( 0x4000, v[1] ); } if (diff & 0x80) UpdateChr(); } NES_POKE_D(McAcc,8001) { uint address = regs.ctrl0 & 0x7; if (address < 6) { ppu.Update(); uint base = regs.ctrl0 << 5 & 0x1000; if (address < 2) { address <<= 1; base |= address << 10; UpdateChr( base | 0x0000, (banks.chr[address+0] = data & 0xFE) ); UpdateChr( base | 0x0400, (banks.chr[address+1] = data | 0x01) ); } else { UpdateChr( (base ^ 0x1000) | (address-2) << 10, (banks.chr[address+2] = data) ); } } else { UpdatePrg( (address == 6) ? (regs.ctrl0 << 8 & 0x4000) : 0x2000, (banks.prg[address-6] = data & 0x3F) ); } } NES_POKE_D(McAcc,A001) { regs.ctrl1 = data; wrk.Source().SetSecurity ( (data & CTRL1_WRAM_ENABLED), (data & CTRL1_WRAM) == CTRL1_WRAM_ENABLED && board.GetWram() ); } NES_POKE_D(McAcc,C000) { irq.Update(); irq.unit.SetLatch( data ); } NES_POKE(McAcc,C001) { irq.Update(); irq.unit.Reload(); } NES_POKE(McAcc,E000) { irq.Update(); irq.unit.Disable( cpu ); } NES_POKE(McAcc,E001) { irq.Update(); irq.unit.Enable(); } void NST_FASTCALL McAcc::UpdatePrg(uint address,uint bank) { prg.SwapBank( address, bank ); } void NST_FASTCALL McAcc::UpdateChr(uint address,uint bank) const { chr.SwapBank( address, bank ); } void McAcc::UpdatePrg() { const uint x = regs.ctrl0 >> 5 & 0x2; UpdatePrg( 0x0000, banks.prg[0^x] ); UpdatePrg( 0x2000, banks.prg[1^0] ); UpdatePrg( 0x4000, banks.prg[2^x] ); UpdatePrg( 0x6000, banks.prg[3^0] ); } void McAcc::UpdateChr() const { ppu.Update(); const uint x = regs.ctrl0 >> 5 & 0x4; for (uint i=0; i < 8; ++i) UpdateChr( i * SIZE_1K, banks.chr[i^x] ); } void McAcc::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardAcclaimMcAcc.hpp000066400000000000000000000047061411157722000233350ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_ACCLAIM_MCACC_H #define NST_BOARD_ACCLAIM_MCACC_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "../NstTimer.hpp" #include "NstBoardMmc3.hpp" namespace Nes { namespace Core { namespace Boards { namespace Acclaim { class McAcc : public Board { public: explicit McAcc(const Context&); protected: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Sync(Event,Input::Controllers*); void UpdatePrg(); void UpdateChr() const; virtual void NST_FASTCALL UpdatePrg(uint,uint); virtual void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_POKE( 8000 ); NES_DECL_POKE( 8001 ); NES_DECL_POKE( A001 ); NES_DECL_POKE( C000 ); NES_DECL_POKE( C001 ); NES_DECL_POKE( E000 ); NES_DECL_POKE( E001 ); enum { CTRL1_WRAM_READONLY = 0x40, CTRL1_WRAM_ENABLED = 0x80, CTRL1_WRAM = CTRL1_WRAM_ENABLED|CTRL1_WRAM_READONLY }; struct Regs { uint ctrl0; uint ctrl1; } regs; struct { byte prg[4]; byte chr[8]; } banks; private: enum { A12_FILTER = 39, IRQ_DELAY = 0, }; // FIXME: IRQ_DELAY should be 4 ppu clocks Mmc3::Irq irq; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardAction53.cpp000066400000000000000000000126011411157722000224660ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardAction53.hpp" namespace Nes { namespace Core { namespace Boards { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Action53::SubReset(const bool hard) { Map( 0x5000U, 0x5FFFU, &Action53::Poke_5000 ); Map( 0x8000U, 0xFFFFU, &Action53::Poke_8000 ); if (hard) { preg[1] = 0xf; preg[3] = 0x3f; } } void Action53::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'A','5','3'>::V) ); if (baseChunk == AsciiId<'A','5','3'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<6> data( state ); preg[0] = data[0]; preg[1] = data[1]; preg[2] = data[2]; preg[3] = data[3]; mirroring = data[4]; index = data[5]; } state.End(); } } } void Action53::SubSave(State::Saver& state) const { const byte data[] = { preg[0], preg[1], preg[2], preg[3], mirroring, index }; state.Begin( AsciiId<'A','5','3'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Action53, 5000) { index = ((data >> 6) & 0x2) | (data & 0x1); } NES_POKE_D(Action53, 8000) { switch (index) { case 0: if (!(mirroring & 2)) { mirroring = (mirroring & 0x2) | (data >> 4) & 0x1; set_nmt_mirroring(); } chr.SwapBank( data & 0x3 ); break; case 1: if (!(mirroring & 2)) { mirroring = (mirroring & 0x2) | (data >> 4) & 0x1; set_nmt_mirroring(); } preg[1] = data & 0xf; set_prg(); break; case 2: preg[2] = data & 0x3c; mirroring = (data & 3); set_prg(); set_nmt_mirroring(); break; case 3: preg[3] = data & 0x3f; set_prg(); break; } } void Action53::set_prg(void) { byte prglo, prghi; byte prg_inner_b = preg[1]; byte prg_outer_b = (preg[3] << 1); /* this can probably be rolled up, but i have no motivation to do so * until it's been tested */ switch (preg[2] & 0x3c) { /* 32K modes */ case 0x00: case 0x04: prglo = prg_outer_b; prghi = prg_outer_b | 0x1; break; case 0x10: case 0x14: prglo = (prg_outer_b & ~0x2) | ((prg_inner_b << 1) & 0x2); prghi = (prg_outer_b & ~0x2) | ((prg_inner_b << 1) & 0x2) | 0x1; break; case 0x20: case 0x24: prglo = (prg_outer_b & ~0x6) | ((prg_inner_b << 1) & 0x6); prghi = (prg_outer_b & ~0x6) | ((prg_inner_b << 1) & 0x6) | 0x1; break; case 0x30: case 0x34: prglo = (prg_outer_b & ~0xe) | ((prg_inner_b << 1) & 0xe); prghi = (prg_outer_b & ~0xe) | ((prg_inner_b << 1) & 0xe) | 0x1; break; /* bottom fixed modes */ case 0x08: prglo = prg_outer_b; prghi = prg_outer_b | (prg_inner_b & 0x1); break; case 0x18: prglo = prg_outer_b; prghi = (prg_outer_b & ~0x2) | (prg_inner_b & 0x3); break; case 0x28: prglo = prg_outer_b; prghi = (prg_outer_b & ~0x6) | (prg_inner_b & 0x7); break; case 0x38: prglo = prg_outer_b; prghi = (prg_outer_b & ~0xe) | (prg_inner_b & 0xf); break; /* top fixed modes */ case 0x0c: prglo = prg_outer_b | (prg_inner_b & 0x1); prghi = prg_outer_b | 0x1; break; case 0x1c: prglo = (prg_outer_b & ~0x2) | (prg_inner_b & 0x3); prghi = prg_outer_b | 0x1; break; case 0x2c: prglo = (prg_outer_b & ~0x6) | (prg_inner_b & 0x7); prghi = prg_outer_b | 0x1; break; case 0x3c: prglo = (prg_outer_b & ~0xe) | (prg_inner_b & 0xf); prghi = prg_outer_b | 0x1; break; } prg.SwapBank( prglo ); prg.SwapBank( prghi ); } void Action53::set_nmt_mirroring(void) { switch (mirroring) { case 0: ppu.SetMirroring( Ppu::NMT_0 ); break; case 1: ppu.SetMirroring( Ppu::NMT_1 ); break; case 2: ppu.SetMirroring( Ppu::NMT_V ); break; case 3: ppu.SetMirroring( Ppu::NMT_H ); break; } } } } } nestopia-1.51.1/source/core/board/NstBoardAction53.hpp000066400000000000000000000032171411157722000224760ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_ACTION_53_H #define NST_BOARD_ACTION_53_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { class Action53 : public Board { public: explicit Action53(const Context& c) : Board(c) {} private: void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void SubReset(bool); void set_prg(void); void set_nmt_mirroring(void); NES_DECL_POKE( 5000 ); NES_DECL_POKE( 8000 ); protected: byte preg[4]; byte mirroring; byte index; }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardAe.cpp000066400000000000000000000037461411157722000214400ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardAe.hpp" namespace Nes { namespace Core { namespace Boards { namespace Ae { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Standard::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &Standard::Poke_8000 ); if (hard) prg.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(Standard,8000) { uint bank = (address >> 7 & 0x1F) + (address >> 7 & address >> 8 & 0x10); if (address & 0x20) { bank = (bank << 2) | (address >> 5 & 0x2); prg.SwapBanks( bank, bank ); } else { prg.SwapBank( bank ); } ppu.SetMirroring( (address & 0x2000) ? Ppu::NMT_H : Ppu::NMT_V ); chr.SwapBank( (address << 2 & 0x3C) | (data & 0x03) ); } } } } } nestopia-1.51.1/source/core/board/NstBoardAe.hpp000066400000000000000000000026631411157722000214420ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_AE_H #define NST_BOARD_AE_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Ae { class Standard : public Board { public: explicit Standard(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardAgci.cpp000066400000000000000000000033521411157722000217470ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardAgci.hpp" namespace Nes { namespace Core { namespace Boards { namespace Agci { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void A50282::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &A50282::Poke_8000 ); if (hard) prg.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(A50282,8000) { ppu.Update(); address = GetBusData(address); data = (data & address) | (address & 0x01); prg.SwapBank( data ); chr.SwapBank( data >> 4 ); } } } } } nestopia-1.51.1/source/core/board/NstBoardAgci.hpp000066400000000000000000000026651411157722000217620ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_AGCI_H #define NST_BOARD_AGCI_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Agci { class A50282 : public Board { public: explicit A50282(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardAve.hpp000066400000000000000000000023021411157722000216160ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_AVE_H #define NST_BOARD_AVE_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardAveNina.hpp" #include "NstBoardAveD1012.hpp" #endif nestopia-1.51.1/source/core/board/NstBoardAveD1012.cpp000066400000000000000000000060631411157722000222310ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardAveD1012.hpp" namespace Nes { namespace Core { namespace Boards { namespace Ave { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void D1012::SubReset(const bool hard) { Map( 0xFF80U, 0xFF9FU, &D1012::Peek_FF80, &D1012::Poke_FF80 ); Map( 0xFFE8U, 0xFFF7U, &D1012::Peek_FFE8, &D1012::Poke_FFE8 ); if (hard) { regs[0] = 0; regs[1] = 0; Update(); } } void D1012::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'A','D','1'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<2> data( state ); regs[0] = data[0]; regs[1] = data[1]; } state.End(); } } } void D1012::SubSave(State::Saver& state) const { state.Begin( AsciiId<'A','D','1'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write16( regs[0] | uint(regs[1]) << 8 ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void D1012::Update() { prg.SwapBank( (regs[0] & 0xE) | (regs[regs[0] >> 6 & 0x1] & 0x1) ); chr.SwapBank( (regs[0] << 2 & ((regs[0] >> 4 & 0x4) ^ 0x3C)) | (regs[1] >> 4 & ((regs[0] >> 4 & 0x4) | 0x3)) ); } NES_POKE_D(D1012,FF80) { if (!(regs[0] & 0x3F)) { regs[0] = data; ppu.SetMirroring( (data & 0x80) ? Ppu::NMT_H : Ppu::NMT_V ); Update(); } } NES_PEEK_A(D1012,FF80) { const uint data = prg[3][address - 0xE000]; NES_DO_POKE(FF80,address,data); return data; } NES_POKE_D(D1012,FFE8) { regs[1] = data; ppu.Update(); Update(); } NES_PEEK_A(D1012,FFE8) { const uint data = prg[3][address - 0xE000]; NES_DO_POKE(FFE8,address,data); return data; } } } } } nestopia-1.51.1/source/core/board/NstBoardAveD1012.hpp000066400000000000000000000032211411157722000222270ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_AVE_D1012_H #define NST_BOARD_AVE_D1012_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Ave { class D1012 : public Board { public: explicit D1012(const Context& c) : Board(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Update(); NES_DECL_POKE( FF80 ); NES_DECL_PEEK( FF80 ); NES_DECL_POKE( FFE8 ); NES_DECL_PEEK( FFE8 ); uint regs[2]; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardAveNina.cpp000066400000000000000000000036541411157722000224320ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardAveNina.hpp" namespace Nes { namespace Core { namespace Boards { namespace Ave { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Nina001::SubReset(const bool hard) { Map( 0x7FFDU, PRG_SWAP_32K ); Map( 0x7FFEU, CHR_SWAP_4K_0 ); Map( 0x7FFFU, CHR_SWAP_4K_1 ); if (hard) prg.SwapBank(0); } void Nina06::SubReset(const bool hard) { for (uint i=0x4100; i < 0x6000; i += 0x200) Map( i+0x00, i+0xFF, &Nina06::Poke_4100 ); if (hard) prg.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Nina06,4100) { ppu.Update(); chr.SwapBank( data ); prg.SwapBank( data >> 3 ); } } } } } nestopia-1.51.1/source/core/board/NstBoardAveNina.hpp000066400000000000000000000034431411157722000224330ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_AVE_NINA001_H #define NST_BOARD_AVE_NINA001_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardDiscrete.hpp" namespace Nes { namespace Core { namespace Boards { namespace Ave { class Nina001 : public Board { public: explicit Nina001(const Context& c) : Board(c) {} private: void SubReset(bool); }; typedef Nina001 Nina002; class Nina06 : public Board { public: explicit Nina06(const Context& c) : Board(c) {} protected: NES_DECL_POKE( 4100 ); private: void SubReset(bool); }; typedef Nina06 Nina03; typedef Discrete::Ic74x377 Nina07; typedef Nina06 Mb91; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardAxRom.cpp000066400000000000000000000034531411157722000221340ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardAxRom.hpp" namespace Nes { namespace Core { namespace Boards { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void AxRom::SubReset(const bool hard) { if (board == Type::STD_AMROM) Map( 0x8000U, 0xFFFFU, &AxRom::Poke_8000_1 ); else Map( 0x8000U, 0xFFFFU, &AxRom::Poke_8000_0 ); if (hard) prg.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(AxRom,8000_0) { prg.SwapBank( data ); ppu.SetMirroring( (data & 0x10) ? Ppu::NMT_1 : Ppu::NMT_0 ); } NES_POKE_AD(AxRom,8000_1) { NES_DO_POKE(8000_0,address,GetBusData(address,data)); } } } } nestopia-1.51.1/source/core/board/NstBoardAxRom.hpp000066400000000000000000000026551411157722000221440ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_AXROM_H #define NST_BOARD_AXROM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { class AxRom : public Board { public: explicit AxRom(const Context& c) : Board(c) {} private: NES_DECL_POKE( 8000_0 ); NES_DECL_POKE( 8000_1 ); void SubReset(bool); }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardBandai.hpp000066400000000000000000000031361411157722000222670ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BANDAI_H #define NST_BOARD_BANDAI_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "../NstFile.hpp" #include "NstBoardBandai24c0x.hpp" #include "NstBoardBandaiLz93d50.hpp" #include "NstBoardBandaiLz93d50ex.hpp" #include "NstBoardBandaiDatach.hpp" #include "NstBoardBandaiKaraokeStudio.hpp" #include "NstBoardBandaiAerobicsStudio.hpp" #include "NstBoardBandaiOekaKids.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bandai { typedef Lz93d50 Fcg1; typedef Lz93d50 Fcg2; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBandai24c0x.cpp000066400000000000000000000174671411157722000230570ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBandai24c0x.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bandai { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void X24C0X<0>::Reset() { line.scl = 0; line.sda = 0; mode = MODE_IDLE; next = MODE_IDLE; latch.bit = 0; latch.address = 0; latch.data = 0; rw = false; output = 0x10; } void X24C0X<0>::SaveState ( State::Saver& state, const dword baseChunk, const byte* const mem, const uint size ) const { state.Begin( baseChunk ); const byte data[6] = { line.scl | line.sda, uint(mode << 0) | uint(next << 4), latch.address, latch.data, latch.bit, output | (rw ? 0x80 : 0x00) }; state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End(); state.Begin( AsciiId<'R','A','M'>::V ).Compress( mem, size ).End(); state.End(); } void X24C0X<0>::LoadState(State::Loader& state,byte* const mem,const uint size) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: { State::Loader::Data<6> data( state ); line.scl = data[0] & 0x20; line.sda = data[0] & 0x40; if ((data[1] & 0xF) < MODE_MAX) mode = static_cast(data[1] & 0xF); if ((data[1] >> 4) < MODE_MAX) next = static_cast(data[1] >> 4); latch.address = data[2] & (size-1); latch.data = data[3]; latch.bit = NST_MAX(data[4],8); rw = data[5] & 0x80; output = data[5] & 0x10; break; } case AsciiId<'R','A','M'>::V: state.Uncompress( mem, size ); break; } state.End(); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void X24C0X<0>::Stop() { mode = MODE_IDLE; output = 0x10; } template<> void X24C0X<128>::Start() { mode = MODE_ADDRESS; latch.bit = 0; latch.address = 0; output = 0x10; } template<> void X24C0X<256>::Start() { mode = MODE_DATA; latch.bit = 0; output = 0x10; } template<> void X24C0X<128>::Rise(const uint bit) { NST_ASSERT( bit <= 1 ); if (mode == MODE_ADDRESS) { if (latch.bit < 7) { latch.address &= ~(1U << latch.bit); latch.address |= bit << latch.bit++; } else if (latch.bit < 8) { latch.bit = 8; if (bit) { next = MODE_READ; latch.data = mem[latch.address]; } else { next = MODE_WRITE; } } } else if (mode == MODE_ACK) { output = 0x00; } else if (mode == MODE_READ && (latch.bit < 8)) { output = (latch.data & 1U << latch.bit++) ? 0x10 : 0x00; } else if (mode == MODE_WRITE && (latch.bit < 8)) { latch.data &= ~(1U << latch.bit); latch.data |= bit << latch.bit++; } else if (mode == MODE_ACK_WAIT && (bit == 0)) { next = MODE_IDLE; } } template<> void X24C0X<128>::Fall() { if (mode == MODE_ADDRESS && (latch.bit == 8)) { mode = MODE_ACK; output = 0x10; } else if (mode == MODE_ACK) { mode = next; latch.bit = 0; output = 0x10; } else if (mode == MODE_READ && (latch.bit == 8)) { mode = MODE_ACK_WAIT; latch.address = (latch.address+1) & 0x7F; } else if (mode == MODE_WRITE && (latch.bit == 8)) { mode = MODE_ACK; next = MODE_IDLE; mem[latch.address] = latch.data; latch.address = (latch.address+1) & 0x7F; } } template<> void X24C0X<256>::Rise(const uint bit) { NST_ASSERT( bit <= 1 ); switch (mode) { case MODE_DATA: if (latch.bit < 8) { latch.data &= ~(1U << (7-latch.bit)); latch.data |= bit << (7-latch.bit++); } break; case MODE_ADDRESS: if (latch.bit < 8) { latch.address &= ~(1U << (7-latch.bit)); latch.address |= bit << (7-latch.bit++); } break; case MODE_READ: if (latch.bit < 8) output = (latch.data & 1U << (7-latch.bit++)) ? 0x10 : 0x00; break; case MODE_WRITE: if (latch.bit < 8) { latch.data &= ~(1U << (7-latch.bit)); latch.data |= bit << (7-latch.bit++); } break; case MODE_NOT_ACK: output = 0x10; break; case MODE_ACK: output = 0x00; break; case MODE_ACK_WAIT: if (bit == 0) { next = MODE_READ; latch.data = mem[latch.address]; } break; case MODE_IDLE: case MODE_MAX: default: break; } } template<> void X24C0X<256>::Fall() { switch (mode) { case MODE_DATA: if (latch.bit == 8) { if ((latch.data & 0xA0) == 0xA0) { latch.bit = 0; mode = MODE_ACK; rw = latch.data & 0x01; output = 0x10; if (rw) { next = MODE_READ; latch.data = mem[latch.address]; } else { next = MODE_ADDRESS; } } else { mode = MODE_NOT_ACK; next = MODE_IDLE; output = 0x10; } } break; case MODE_ADDRESS: if (latch.bit == 8) { latch.bit = 0; mode = MODE_ACK; next = (rw ? MODE_IDLE : MODE_WRITE); output = 0x10; } break; case MODE_READ: if (latch.bit == 8) { mode = MODE_ACK_WAIT; latch.address = (latch.address+1) & 0xFF; } break; case MODE_WRITE: if (latch.bit == 8) { latch.bit = 0; mode = MODE_ACK; next = MODE_WRITE; mem[latch.address] = latch.data; latch.address = (latch.address+1) & 0xFF; } break; case MODE_NOT_ACK: mode = MODE_IDLE; latch.bit = 0; output = 0x10; break; case MODE_ACK: case MODE_ACK_WAIT: mode = next; latch.bit = 0; output = 0x10; break; case MODE_IDLE: case MODE_MAX: default: break; } } } } } } nestopia-1.51.1/source/core/board/NstBoardBandai24c0x.hpp000066400000000000000000000066341411157722000230560ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BANDAI_24C0X_H #define NST_BOARD_BANDAI_24C0X_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include namespace Nes { namespace Core { namespace Boards { namespace Bandai { template class X24C0X; template<> class X24C0X<0> { public: void Stop(); void Reset(); protected: void LoadState(State::Loader&,byte*,uint); void SaveState(State::Saver&,dword,const byte*,uint) const; enum Mode { MODE_IDLE, MODE_DATA, MODE_ADDRESS, MODE_READ, MODE_WRITE, MODE_ACK, MODE_NOT_ACK, MODE_ACK_WAIT, MODE_MAX }; struct { uint scl; uint sda; } line; Mode mode; Mode next; struct { uint bit; uint address; uint data; } latch; ibool rw; uint output; public: uint Read() const { return output; } }; template class X24C0X : public X24C0X<0> { public: enum { SIZE = N }; void Set(uint,uint); private: void Start(); void Rise(uint); void Fall(); byte mem[SIZE]; public: X24C0X() { std::memset( mem, 0, SIZE ); } byte* GetData() { return mem; } const byte* GetData() const { return mem; } void LoadState(State::Loader& loader) { X24C0X<0>::LoadState( loader, mem, SIZE ); } void SaveState(State::Saver& saver,dword baseChunk) const { X24C0X<0>::SaveState( saver, baseChunk, mem, SIZE ); } void SetScl(uint scl) { Set( scl, line.sda ); } void SetSda(uint sda) { Set( line.scl, sda ); } }; template void X24C0X::Set(const uint scl,const uint sda) { if (line.scl && sda < line.sda) { Start(); } else if (line.scl && sda > line.sda) { Stop(); } else if (scl > line.scl) { Rise( sda >> 6 ); } else if (scl < line.scl) { Fall(); } line.scl = scl; line.sda = sda; } typedef X24C0X<128> X24C01; typedef X24C0X<256> X24C02; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBandaiAerobicsStudio.cpp000066400000000000000000000037171411157722000251270ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "../NstSoundPlayer.hpp" #include "NstBoardBandaiAerobicsStudio.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bandai { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif AerobicsStudio::AerobicsStudio(const Context& c) : CnRom (c), sound (Sound::Player::Create(*c.apu,c.chips,NULL,Sound::Player::GAME_AEROBICS_STUDIO,8)) {} AerobicsStudio::~AerobicsStudio() { Sound::Player::Destroy( sound ); } void AerobicsStudio::SubReset(const bool hard) { CnRom::SubReset( hard ); if (sound) Map( 0x6000U, &AerobicsStudio::Poke_6000 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(AerobicsStudio,6000) { NST_ASSERT( sound ); if ((data & 0x40) == 0x00) sound->Play( data & 0x07 ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBandaiAerobicsStudio.hpp000066400000000000000000000031441411157722000251260ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BANDAI_AEROBICSSTUDIO_H #define NST_BOARD_BANDAI_AEROBICSSTUDIO_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardCxRom.hpp" namespace Nes { namespace Core { namespace Sound { class Player; } namespace Boards { namespace Bandai { class AerobicsStudio : public CnRom { public: explicit AerobicsStudio(const Context&); private: ~AerobicsStudio(); void SubReset(bool); NES_DECL_POKE( 6000 ); Sound::Player* const sound; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBandaiDatach.cpp000066400000000000000000000212651411157722000233720ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "../NstTimer.hpp" #include "NstBoard.hpp" #include "NstBoardBandai.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bandai { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Datach::Datach(const Context& c) : Lz93d50Ex (c), barcodeReader (*c.cpu) { } Datach::Reader::Reader(Cpu& c) : cpu(c) { Reset( false ); } Datach::Device Datach::QueryDevice(DeviceType devType) { if (devType == DEVICE_BARCODE_READER) return static_cast(&barcodeReader); else return Lz93d50Ex::QueryDevice( devType ); } void Datach::SubReset(const bool hard) { Lz93d50Ex::SubReset( hard ); barcodeReader.Reset(); p6000 = cpu.Map( 0x6000 ); for (uint i=0x6000; i < 0x8000; i += 0x100) Map( i, &Datach::Peek_6000 ); } void Datach::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'B','D','A'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'B','R','C'>::V) barcodeReader.LoadState( state ); state.End(); } } else { Lz93d50Ex::SubLoad( state, baseChunk ); } } void Datach::SubSave(State::Saver& state) const { Lz93d50Ex::SubSave( state ); state.Begin( AsciiId<'B','D','A'>::V ); barcodeReader.SaveState( state, AsciiId<'B','R','C'>::V ); state.End(); } void Datach::Reader::Reset(bool initHook) { cycles = Cpu::CYCLE_MAX; output = 0x00; stream = data; std::memset( data, END, MAX_DATA_LENGTH ); if (initHook) cpu.AddHook( Hook(this,&Reader::Hook_Fetcher) ); } bool Datach::Reader::IsTransferring() const { return *stream != END; } bool Datach::Reader::IsDigitsSupported(uint count) const { return count == MIN_DIGITS || count == MAX_DIGITS; } void Datach::Reader::LoadState(State::Loader& state) { Reset( false ); while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'P','T','R'>::V: stream = data + (state.Read8() & (MAX_DATA_LENGTH-1)); break; case AsciiId<'D','A','T'>::V: state.Uncompress( data ); data[MAX_DATA_LENGTH-1] = END; break; case AsciiId<'C','Y','C'>::V: cycles = state.Read16(); break; } state.End(); } if (Reader::IsTransferring()) { output = (stream != data) ? stream[-1] : 0x00; if (cycles > CC_INTERVAL) cycles = CC_INTERVAL; cycles = cpu.GetCycles() + cpu.GetClock() * cycles; } else { cycles = Cpu::CYCLE_MAX; output = 0x00; } } void Datach::Reader::SaveState(State::Saver& state,const dword baseChunk) const { if (Reader::IsTransferring()) { NST_ASSERT( cycles != Cpu::CYCLE_MAX ); state.Begin( baseChunk ); state.Begin( AsciiId<'P','T','R'>::V ).Write8( stream - data ).End(); state.Begin( AsciiId<'D','A','T'>::V ).Compress( data ).End(); uint next; if (cycles > cpu.GetCycles()) next = (cycles - cpu.GetCycles()) / cpu.GetClock(); else next = 0; state.Begin( AsciiId<'C','Y','C'>::V ).Write16( next ).End(); state.End(); } } bool Datach::Reader::Transfer(cstring const string,const uint length) { Reset( false ); if (!string || (length != MAX_DIGITS && length != MIN_DIGITS)) return false; static const byte prefixParityType[10][6] = { {8,8,8,8,8,8}, {8,8,0,8,0,0}, {8,8,0,0,8,0}, {8,8,0,0,0,8}, {8,0,8,8,0,0}, {8,0,0,8,8,0}, {8,0,0,0,8,8}, {8,0,8,0,8,0}, {8,0,8,0,0,8}, {8,0,0,8,0,8} }; static const byte dataLeftOdd[10][7] = { {8,8,8,0,0,8,0}, {8,8,0,0,8,8,0}, {8,8,0,8,8,0,0}, {8,0,0,0,0,8,0}, {8,0,8,8,8,0,0}, {8,0,0,8,8,8,0}, {8,0,8,0,0,0,0}, {8,0,0,0,8,0,0}, {8,0,0,8,0,0,0}, {8,8,8,0,8,0,0} }; static const byte dataLeftEven[10][7] = { {8,0,8,8,0,0,0}, {8,0,0,8,8,0,0}, {8,8,0,0,8,0,0}, {8,0,8,8,8,8,0}, {8,8,0,0,0,8,0}, {8,0,0,0,8,8,0}, {8,8,8,8,0,8,0}, {8,8,0,8,8,8,0}, {8,8,8,0,8,8,0}, {8,8,0,8,0,0,0} }; static const byte dataRight[10][7] = { {0,0,0,8,8,0,8}, {0,0,8,8,0,0,8}, {0,0,8,0,0,8,8}, {0,8,8,8,8,0,8}, {0,8,0,0,0,8,8}, {0,8,8,0,0,0,8}, {0,8,0,8,8,8,8}, {0,8,8,8,0,8,8}, {0,8,8,0,8,8,8}, {0,0,0,8,0,8,8} }; byte code[16]; for (uint i=0; i < length; ++i) { if (string[i] >= '0' && string[i] <= '9') code[i] = string[i] - '0'; else return false; } byte* NST_RESTRICT output = data; for (uint i=0; i < 1+32; ++i) *output++ = 8; *output++ = 0; *output++ = 8; *output++ = 0; uint sum = 0; if (length == MAX_DIGITS) { for (uint i=0; i < 6; ++i) { if (prefixParityType[code[0]][i]) { for (uint j=0; j < 7; ++j) *output++ = dataLeftOdd[code[i+1]][j]; } else { for (uint j=0; j < 7; ++j) *output++ = dataLeftEven[code[i+1]][j]; } } *output++ = 8; *output++ = 0; *output++ = 8; *output++ = 0; *output++ = 8; for (uint i=7; i < 12; ++i) { for (uint j=0; j < 7; ++j) *output++ = dataRight[code[i]][j]; } for (uint i=0; i < 12; ++i) sum += (i & 1) ? (code[i] * 3) : (code[i] * 1); } else { for (uint i=0; i < 4; ++i) { for (uint j=0; j < 7; ++j) *output++ = dataLeftOdd[code[i]][j]; } *output++ = 8; *output++ = 0; *output++ = 8; *output++ = 0; *output++ = 8; for (uint i=4; i < 7; ++i) { for (uint j=0; j < 7; ++j) *output++ = dataRight[code[i]][j]; } for (uint i=0; i < 7; ++i) sum += (i & 1) ? (code[i] * 1) : (code[i] * 3); } sum = (10 - (sum % 10)) % 10; for (uint i=0; i < 7; ++i) *output++ = dataRight[sum][i]; *output++ = 0; *output++ = 8; *output++ = 0; for (uint i=0; i < 32; ++i) *output++ = 8; cycles = cpu.GetCycles() + cpu.GetClock() * CC_INTERVAL; return true; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_HOOK(Datach::Reader,Fetcher) { while (cycles <= cpu.GetCycles()) { output = *stream; stream += (output != END); if (output != END) { cycles += cpu.GetClock() * CC_INTERVAL; } else { output = 0x00; cycles = Cpu::CYCLE_MAX; break; } } } inline uint Datach::Reader::GetOutput() const { return output; } NES_PEEK_A(Datach,6000) { return barcodeReader.GetOutput() | p6000.Peek( address ); } inline void Datach::Reader::Sync() { if (cycles != Cpu::CYCLE_MAX) { if (cycles >= cpu.GetFrameCycles()) cycles -= cpu.GetFrameCycles(); else cycles = 0; } } void Datach::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) barcodeReader.Sync(); Lz93d50Ex::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBandaiDatach.hpp000066400000000000000000000046431411157722000234000ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BANDAI_DATACH_H #define NST_BOARD_BANDAI_DATACH_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "../NstBarcodeReader.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bandai { class Datach : public Lz93d50Ex { public: explicit Datach(const Context&); private: class Reader : public BarcodeReader { public: explicit Reader(Cpu&); void Reset(bool=true); void SaveState(State::Saver&,dword) const; void LoadState(State::Loader&); inline void Sync(); inline uint GetOutput() const; private: enum { MIN_DIGITS = 8, MAX_DIGITS = 13, MAX_DATA_LENGTH = 0x100, END = 0xFF, CC_INTERVAL = 1000 }; bool Transfer(cstring,uint); bool IsTransferring() const; bool IsDigitsSupported(uint) const; NES_DECL_HOOK( Fetcher ); Cpu& cpu; Cycle cycles; uint output; const byte* stream; byte data[MAX_DATA_LENGTH]; }; void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Sync(Event,Input::Controllers*); Device QueryDevice(DeviceType); NES_DECL_PEEK( 6000 ); Reader barcodeReader; Io::Port p6000; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBandaiKaraokeStudio.cpp000066400000000000000000000044341411157722000247520ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBandaiKaraokeStudio.hpp" #include "../api/NstApiInput.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bandai { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void KaraokeStudio::SubReset(const bool hard) { Map( 0x6000U, 0x7FFFU, &KaraokeStudio::Peek_6000 ); Map( 0x8000U, 0xFFFFU, &KaraokeStudio::Poke_8000 ); if (hard) prg.SwapBank(0x7); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(KaraokeStudio,8000) { prg.SwapBank ( data ? (data & 0x7) | (~data >> 1 & 0x8) : (prg.Source().Size() >> 18) + 0x7 ); } NES_PEEK(KaraokeStudio,6000) { return mic; } void KaraokeStudio::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_BEGIN_FRAME) { if (controllers) { Input::Controllers::KaraokeStudio::callback( controllers->karaokeStudio ); mic = (controllers->karaokeStudio.buttons & 0x7) ^ 0x3; } else { mic = 0x3; } } Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBandaiKaraokeStudio.hpp000066400000000000000000000031001411157722000247440ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BANDAI_KARAOKESTUDIO_H #define NST_BOARD_BANDAI_KARAOKESTUDIO_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bandai { class KaraokeStudio : public Board { public: explicit KaraokeStudio(const Context& c) : Board(c) {} private: void SubReset(bool); void Sync(Event,Input::Controllers*); NES_DECL_PEEK( 6000 ); NES_DECL_POKE( 8000 ); uint mic; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBandaiLz93d50.cpp000066400000000000000000000130321411157722000232510ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "../NstTimer.hpp" #include "NstBoard.hpp" #include "NstBoardBandaiLz93d50.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bandai { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Lz93d50::Lz93d50(const Context& c) : Board(c), irq(*c.cpu) { if (board.GetWram()) wrk.Source().Fill(0xFF); } void Lz93d50::Irq::Reset(const bool hard) { if (hard) { latch = 0; count = 0; } } void Lz93d50::SubReset(const bool hard) { irq.Reset( hard, hard ? false : irq.Connected() ); for (uint i=0; i < 8; ++i) regs[i] = 0; if (hard) { for (uint i=board.GetSavableWram(), n=board.GetWram(); i < n; ++i) *wrk.Source().Mem(i) = 0xFF; } const uint offset = (board.GetWram() ? 0x8000 : 0x6000); for (dword i=offset; i <= 0xFFFF; i += 0x10) { Map( i + 0x9, NMT_SWAP_VH01 ); Map( i + 0xA, &Lz93d50::Poke_800A ); Map( i + 0xB, &Lz93d50::Poke_800B ); Map( i + 0xC, &Lz93d50::Poke_800C ); } if (prg.Source().Size() < SIZE_512K) { for (dword i=offset; i <= 0xFFFF; i += 0x10) Map( i + 0x8, PRG_SWAP_16K_0 ); } else { for (dword i=offset; i <= 0xFFFF; i += 0x10) { Map( uint(i + 0x0), uint(i + 0x7), &Lz93d50::Poke_8000 ); Map( uint(i + 0x8), &Lz93d50::Poke_8008 ); } if (hard) prg.SwapBank( 0xF ); } if (chr.Source().Size() > SIZE_8K) { for (dword i=offset; i <= 0xFFFF; i += 0x10) { Map( i + 0x0, CHR_SWAP_1K_0 ); Map( i + 0x1, CHR_SWAP_1K_1 ); Map( i + 0x2, CHR_SWAP_1K_2 ); Map( i + 0x3, CHR_SWAP_1K_3 ); Map( i + 0x4, CHR_SWAP_1K_4 ); Map( i + 0x5, CHR_SWAP_1K_5 ); Map( i + 0x6, CHR_SWAP_1K_6 ); Map( i + 0x7, CHR_SWAP_1K_7 ); } } } void Lz93d50::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'B','L','Z'>::V) ); if (baseChunk == AsciiId<'B','L','Z'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: NST_VERIFY( prg.Source().Size() >= SIZE_512K ); if (prg.Source().Size() >= SIZE_512K) state.Read( regs ); break; case AsciiId<'I','R','Q'>::V: { State::Loader::Data<5> data( state ); irq.Connect( data[0] & 0x1 ); irq.unit.latch = data[1] | data[2] << 8; irq.unit.count = data[3] | data[4] << 8; break; } } state.End(); } } } void Lz93d50::SubSave(State::Saver& state) const { state.Begin( AsciiId<'B','L','Z'>::V ); if (prg.Source().Size() >= SIZE_512K) state.Begin( AsciiId<'R','E','G'>::V ).Write( regs ).End(); const byte data[5] = { irq.Connected() ? 0x1 : 0x0, irq.unit.latch >> 0 & 0xFF, irq.unit.latch >> 8 & 0xFF, irq.unit.count >> 0 & 0xFF, irq.unit.count >> 8 & 0xFF }; state.Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End(); state.End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(Lz93d50,8000) { regs[address & 0x7] = data; data = 0; for (uint i=0; i < 8; ++i) data |= regs[i] << 4 & 0x10U; prg.SwapBanks( data | (prg.GetBank() & 0x0F), data | 0xF ); } NES_POKE_D(Lz93d50,8008) { prg.SwapBank( (prg.GetBank() & 0x10) | (data & 0x0F) ); } NES_POKE_D(Lz93d50,800A) { irq.Update(); irq.unit.count = irq.unit.latch; irq.Connect( data & 0x1 ); irq.ClearIRQ(); } NES_POKE_D(Lz93d50,800B) { irq.Update(); irq.unit.latch = (irq.unit.latch & 0xFF00) | data << 0; } NES_POKE_D(Lz93d50,800C) { irq.Update(); irq.unit.latch = (irq.unit.latch & 0x00FF) | data << 8; } bool Lz93d50::Irq::Clock() { return (count-- & 0xFFFF) == 0; } void Lz93d50::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBandaiLz93d50.hpp000066400000000000000000000035471411157722000232700ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BANDAI_LZ93D50_H #define NST_BOARD_BANDAI_LZ93D50_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bandai { class Lz93d50 : public Board { public: explicit Lz93d50(const Context&); protected: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Sync(Event,Input::Controllers*); private: NES_DECL_POKE( 8000 ); NES_DECL_POKE( 8008 ); NES_DECL_POKE( 800A ); NES_DECL_POKE( 800B ); NES_DECL_POKE( 800C ); struct Irq { void Reset(bool); bool Clock(); uint count; uint latch; }; byte regs[8]; Timer::M2 irq; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBandaiLz93d50ex.cpp000066400000000000000000000116771411157722000236230ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "../NstTimer.hpp" #include "NstBoard.hpp" #include "NstBoardBandai.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bandai { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Lz93d50Ex::Lz93d50Ex(const Context& c) : Lz93d50 (c), x24c01 (board == Type::BANDAI_DATACH || board == Type::BANDAI_LZ93D50_24C01 ? new X24C01 : NULL), x24c02 (board == Type::BANDAI_DATACH || board == Type::BANDAI_LZ93D50_24C02 ? new X24C02 : NULL) { } void Lz93d50Ex::SubReset(const bool hard) { Lz93d50::SubReset( hard ); if (x24c01) x24c01->Reset(); if (x24c02) x24c02->Reset(); if (x24c01 && x24c02) { for (uint i=0x6000; i < 0x8000; i += 0x100) Map( i, &Lz93d50Ex::Peek_6000_24c01_24c02 ); for (dword i=0x6000; i < 0x10000; i += 0x10) { Map( uint(i + 0x0), uint(i + 0x7), &Lz93d50Ex::Poke_8000_24c01_24c02 ); Map( uint(i + 0xD), &Lz93d50Ex::Poke_800D_24c01_24c02 ); } } else if (x24c01) { for (uint i=0x6000; i < 0x8000; i += 0x100) Map( i, &Lz93d50Ex::Peek_6000_24c01 ); for (dword i=0x600D; i < 0x10000; i += 0x10) Map( uint(i), &Lz93d50Ex::Poke_800D_24c01 ); } else { for (uint i=0x6000; i < 0x8000; i += 0x100) Map( i, &Lz93d50Ex::Peek_6000_24c02 ); for (dword i=0x600D; i < 0x10000; i += 0x10) Map( uint(i), &Lz93d50Ex::Poke_800D_24c02 ); } } void Lz93d50Ex::Load(File& file) { const File::LoadBlock block[] = { { x24c02 ? x24c02->GetData() : NULL, x24c02 ? X24C02::SIZE : 0 }, { x24c01 ? x24c01->GetData() : NULL, x24c01 ? X24C01::SIZE : 0 } }; file.Load( File::EEPROM, block ); } void Lz93d50Ex::Save(File& file) const { const File::SaveBlock block[] = { { x24c02 ? x24c02->GetData() : NULL, x24c02 ? X24C02::SIZE : 0 }, { x24c01 ? x24c01->GetData() : NULL, x24c01 ? X24C01::SIZE : 0 } }; file.Save( File::EEPROM, block ); } void Lz93d50Ex::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'B','L','E'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'C','0','1'>::V: NST_VERIFY( x24c01 ); if (x24c01) x24c01->LoadState( state ); break; case AsciiId<'C','0','2'>::V: NST_VERIFY( x24c02 ); if (x24c02) x24c02->LoadState( state ); break; } state.End(); } } else { Lz93d50::SubLoad( state, baseChunk ); } } void Lz93d50Ex::SubSave(State::Saver& state) const { Lz93d50::SubSave( state ); state.Begin( AsciiId<'B','L','E'>::V ); if (x24c01) x24c01->SaveState( state, AsciiId<'C','0','1'>::V ); if (x24c02) x24c02->SaveState( state, AsciiId<'C','0','2'>::V ); state.End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK(Lz93d50Ex,6000_24c01) { return x24c01->Read(); } NES_PEEK(Lz93d50Ex,6000_24c02) { return x24c02->Read(); } NES_PEEK(Lz93d50Ex,6000_24c01_24c02) { return x24c01->Read() & x24c02->Read(); } NES_POKE_D(Lz93d50Ex,8000_24c01_24c02) { x24c01->SetScl( data << 2 & 0x20 ); } NES_POKE_D(Lz93d50Ex,800D_24c01) { x24c01->Set( data & 0x20, data & 0x40 ); } NES_POKE_D(Lz93d50Ex,800D_24c02) { x24c02->Set( data & 0x20, data & 0x40 ); } NES_POKE_D(Lz93d50Ex,800D_24c01_24c02) { x24c01->SetSda( data & 0x40 ); x24c02->Set( data & 0x20, data & 0x40 ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBandaiLz93d50ex.hpp000066400000000000000000000036371411157722000236250ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BANDAI_LZ93D50EX_H #define NST_BOARD_BANDAI_LZ93D50EX_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bandai { class Lz93d50Ex : public Lz93d50 { public: explicit Lz93d50Ex(const Context&); protected: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); private: void Save(File&) const; void Load(File&); NES_DECL_PEEK( 6000_24c01 ); NES_DECL_PEEK( 6000_24c02 ); NES_DECL_PEEK( 6000_24c01_24c02 ); NES_DECL_POKE( 8000_24c01_24c02 ); NES_DECL_POKE( 800D_24c01 ); NES_DECL_POKE( 800D_24c02 ); NES_DECL_POKE( 800D_24c01_24c02 ); Pointer x24c01; Pointer x24c02; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBandaiOekaKids.cpp000066400000000000000000000040401411157722000236700ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBandaiOekaKids.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bandai { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void OekaKids::SubReset(const bool hard) { ppu.SetAddressLineHook( Core::Io::Line(this,&OekaKids::Line_Nmt) ); Map( 0x8000U, 0xFFFFU, &OekaKids::Poke_8000 ); if (hard) NES_DO_POKE(8000,0x8000,0x00); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_LINE(OekaKids,Nmt) { if (address >= 0x2000 && (address & 0x3FF) < 0x3C0) chr.SwapBank( (chr.GetBank() & 0x4) | (address >> 8 & 0x3) ); } NES_POKE_AD(OekaKids,8000) { ppu.Update(); data = GetBusData(address,data); prg.SwapBank( data ); chr.SwapBanks( (data & 0x4) | (chr.GetBank() & 0x3), (data & 0x4) | 0x3 ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBandaiOekaKids.hpp000066400000000000000000000027561411157722000237110ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BANDAI_OEKAKIDS_H #define NST_BOARD_BANDAI_OEKAKIDS_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bandai { class OekaKids : public Board { public: explicit OekaKids(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_LINE( Nmt ); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBenshengBs5.cpp000066400000000000000000000115551411157722000232130ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBenshengBs5.hpp" #include "../NstCrc32.hpp" #include "../NstDipSwitches.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bensheng { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif class Bs5::CartSwitches : public DipSwitches { enum Type { CRC_4_IN_1_A = 0x01E54556, CRC_4_IN_1_B = 0x6DCE148C, CRC_4_IN_1_C = 0x13E55C4C }; uint mode; const Type type; explicit CartSwitches(Type t) : mode(0), type(t) {} public: static CartSwitches* Create(const Context& c) { switch (const dword crc = Crc32::Compute(c.prg.Mem(),c.prg.Size())) { case CRC_4_IN_1_A: case CRC_4_IN_1_B: case CRC_4_IN_1_C: return new CartSwitches( static_cast(crc) ); } return NULL; } void SetMode(uint value) { mode = value & 0x3; } uint GetMode() const { return mode; } private: uint GetValue(uint) const { return mode; } void SetValue(uint,uint value) { mode = value; } uint NumValues(uint) const { return 4; } uint NumDips() const { return 1; } cstring GetDipName(uint) const { return "Mode"; } cstring GetValueName(uint,uint i) const { switch (type) { case CRC_4_IN_1_A: { static const char names[4][9] = { "4-in-1", "23-in-1", "53-in-1", "163-in-1" }; return names[i]; } case CRC_4_IN_1_B: { static const char names[4][9] = { "4-in-1", "32-in-1", "64-in-1", "128-in-1" }; return names[i]; } case CRC_4_IN_1_C: { static const char names[4][9] = { "4-in-1", "21-in-1", "81-in-1", "151-in-1" }; return names[i]; } } return NULL; } }; Bs5::Bs5(const Context& c) : Board(c), cartSwitches(CartSwitches::Create(c)) {} Bs5::~Bs5() { delete cartSwitches; } void Bs5::SubReset(const bool hard) { if (hard) prg.SwapBanks( ~0U, ~0U, ~0U, ~0U ); Map( 0x8000U, 0x8FFFU, &Bs5::Poke_8000 ); Map( 0xA000U, 0xAFFFU, &Bs5::Poke_A000 ); } Bs5::Device Bs5::QueryDevice(DeviceType type) { if (type == DEVICE_DIP_SWITCHES) return cartSwitches; else return Board::QueryDevice( type ); } void Bs5::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( (baseChunk == AsciiId<'B','S','5'>::V) ); if (baseChunk == AsciiId<'B','S','5'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'D','I','P'>::V) { NST_VERIFY( cartSwitches ); if (cartSwitches) cartSwitches->SetMode( state.Read8() ); } state.End(); } } } void Bs5::SubSave(State::Saver& state) const { if (cartSwitches) state.Begin( AsciiId<'B','S','5'>::V ).Begin( AsciiId<'D','I','P'>::V ).Write8( cartSwitches->GetMode() ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_A(Bs5,8000) { ppu.Update(); chr.SwapBank( address << 1 & 0x1800, address & 0x1F ); } NES_POKE_A(Bs5,A000) { if (address & (0x10U << (cartSwitches ? cartSwitches->GetMode() : 0))) prg.SwapBank( address << 3 & 0x6000, address & 0xF ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBenshengBs5.hpp000066400000000000000000000032321411157722000232110ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BENSHENG_BS5_H #define NST_BOARD_BENSHENG_BS5_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bensheng { class Bs5 : public Board { public: explicit Bs5(const Context&); private: ~Bs5(); class CartSwitches; void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); Device QueryDevice(DeviceType); NES_DECL_POKE( 8000 ); NES_DECL_POKE( A000 ); CartSwitches* const cartSwitches; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmc110in1.cpp000066400000000000000000000035721411157722000224430ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmc110in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void B110in1::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &B110in1::Poke_8000 ); if (hard) NES_DO_POKE(8000,0x8000,0x00); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_A(B110in1,8000) { const uint mode = (~address >> 12 & 0x1); const uint bank = (address >> 8 & 0x40) | (address >> 6 & 0x3F); prg.SwapBanks( bank & ~mode, bank | mode ); ppu.SetMirroring( (address & 0x2000) ? Ppu::NMT_H : Ppu::NMT_V ); chr.SwapBank( (address >> 8 & 0x40) | (address & 0x3F) ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmc110in1.hpp000066400000000000000000000026721411157722000224500ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_110IN1_H #define NST_BOARD_110IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class B110in1 : public Board { public: explicit B110in1(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmc1200in1.cpp000066400000000000000000000040011411157722000225100ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmc1200in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void B1200in1::SubReset(bool) { Map( 0x8000U, 0xFFFFU, &B1200in1::Poke_8000 ); NES_DO_POKE(8000,0x8000,0x00); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_A(B1200in1,8000) { const uint bank = (address >> 4 & 0x10) | (address >> 3 & 0x0F); if (address & 0x1) { prg.SwapBank( bank ); } else { const uint offset = (bank << 1) | (address >> 2 & 0x1); prg.SwapBanks( offset, offset ); } if (!(address & 0x80)) prg.SwapBank( ((address & 0x200) ? 0x7 : 0x0) | (bank << 1 & 0x38) ); ppu.SetMirroring( (address & 0x2) ? Ppu::NMT_H : Ppu::NMT_V ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmc1200in1.hpp000066400000000000000000000027061411157722000225270ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_1200IN1_H #define NST_BOARD_BMC_1200IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class B1200in1 : public Board { public: explicit B1200in1(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmc150in1.cpp000066400000000000000000000034221411157722000224410ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmc150in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void B150in1::SubReset(const bool hard) { Map( 0x4020U, 0xFFFFU, &B150in1::Poke_8000 ); if (hard) NES_DO_POKE(8000,0x8000,0x00); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_A(B150in1,8000) { ppu.SetMirroring( (address & 0x1) ? Ppu::NMT_H : Ppu::NMT_V ); const uint bank = address >> 1 & 0x7; prg.SwapBanks( bank, bank + ((address & 0xC) == 0xC) ); chr.SwapBank( bank ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmc150in1.hpp000066400000000000000000000027021411157722000224460ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_150IN1_H #define NST_BOARD_BMC_150IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class B150in1 : public Board { public: explicit B150in1(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmc15in1.cpp000066400000000000000000000052561411157722000223700ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardBmc15in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void B15in1::SubReset(const bool hard) { if (hard) exReg = 0; Mmc3::SubReset( hard ); Map( 0x6800U, 0x6FFFU, &B15in1::Poke_6800 ); Map( 0x7800U, 0x7FFFU, &B15in1::Poke_6800 ); } void B15in1::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'B','1','5'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) exReg = (state.Read8() & 0x3) << 4; state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void B15in1::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); state.Begin( AsciiId<'B','1','5'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( exReg >> 4 ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(B15in1,6800) { data = data << 4 & 0x30; if (exReg != data) { exReg = data; Mmc3::UpdatePrg(); Mmc3::UpdateChr(); } } void NST_FASTCALL B15in1::UpdatePrg(uint address,uint bank) { prg.SwapBank( address, exReg | (bank & ((exReg & 0x20) ? 0x0F : 0x1F)) ); } void NST_FASTCALL B15in1::UpdateChr(uint address,uint bank) const { chr.SwapBank( address, exReg << 3 | bank ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmc15in1.hpp000066400000000000000000000032071411157722000223670ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_15IN1_H #define NST_BOARD_BMC_15IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class B15in1 : public Mmc3 { public: explicit B15in1(const Context& c) : Mmc3(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void NST_FASTCALL UpdatePrg(uint,uint); void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_POKE( 6800 ); uint exReg; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmc20in1.cpp000066400000000000000000000033071411157722000223570ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmc20in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void B20in1::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &B20in1::Poke_8000 ); if (hard) NES_DO_POKE(8000,0x8000,0x00); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_A(B20in1,8000) { prg.SwapBanks( address & 0x1E, (address & 0x1E) | (address >> 5 & 0x1) ); ppu.SetMirroring( (address & 0x80) ? Ppu::NMT_H : Ppu::NMT_V ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmc20in1.hpp000066400000000000000000000026761411157722000223740ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_20IN1_H #define NST_BOARD_BMC_20IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class B20in1 : public Board { public: explicit B20in1(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmc21in1.cpp000066400000000000000000000032231411157722000223550ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmc21in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void B21in1::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &B21in1::Poke_8000 ); if (hard) NES_DO_POKE(8000,0x8000,0x00); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_A(B21in1,8000) { ppu.Update(); prg.SwapBank( address ); chr.SwapBank( address ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmc21in1.hpp000066400000000000000000000026761411157722000223750ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_21IN1_H #define NST_BOARD_BMC_21IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class B21in1 : public Board { public: explicit B21in1(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmc22Games.cpp000066400000000000000000000051361411157722000227300ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmc22Games.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void B22Games::SubReset(const bool hard) { if (hard) romSwitch = 0; else romSwitch ^= 1; if (romSwitch) { prg.SwapBanks( 0, 7 ); ppu.SetMirroring( Ppu::NMT_V ); } else { prg.SwapBanks( 8, 39 ); } Map( 0x8000U, 0xFFFFU, &B22Games::Poke_8000 ); } void B22Games::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'B','2','G'>::V) ); if (baseChunk == AsciiId<'B','2','G'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) romSwitch = state.Read8() & 0x1; state.End(); } } } void B22Games::SubSave(State::Saver& state) const { state.Begin( AsciiId<'B','2','G'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( romSwitch ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(B22Games,8000) { if (romSwitch) { prg.SwapBank( data & 0x7 ); } else { prg.SwapBanks( 8 + (data & 0x1F), (8 + (data & 0x1F)) | (~data >> 5 & 0x1) ); ppu.SetMirroring( (data & 0x40) ? Ppu::NMT_V : Ppu::NMT_H ); } } } } } } nestopia-1.51.1/source/core/board/NstBoardBmc22Games.hpp000066400000000000000000000030611411157722000227300ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_22GAMES_H #define NST_BOARD_BMC_22GAMES_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class B22Games : public Board { public: explicit B22Games(const Context& c) : Board(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); NES_DECL_POKE( 8000 ); uint romSwitch; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmc31in1.cpp000066400000000000000000000034151411157722000223610ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmc31in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void B31in1::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &B31in1::Poke_8000 ); if (hard) NES_DO_POKE(8000,0x8000,0x00); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_A(B31in1,8000) { ppu.SetMirroring( (address & 0x20) ? Ppu::NMT_H : Ppu::NMT_V ); prg.SwapBanks( (address & 0x1E) ? (address & 0x1F) : 0, (address & 0x1E) ? (address & 0x1F) : 1 ); chr.SwapBank(address); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmc31in1.hpp000066400000000000000000000026761411157722000223760ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_31IN1_H #define NST_BOARD_BMC_31IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class B31in1 : public Board { public: explicit B31in1(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmc35in1.cpp000066400000000000000000000032361411157722000223660ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmc35in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void B35in1::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &B35in1::Poke_8000 ); if (hard) NES_DO_POKE(8000,0x8000,0x00); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(B35in1,8000) { ppu.Update(); prg.SwapBanks( data >> 2, data >> 2 ); chr.SwapBank( data ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmc35in1.hpp000066400000000000000000000026761411157722000224020ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_35IN1_H #define NST_BOARD_BMC_35IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class B35in1 : public Board { public: explicit B35in1(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmc36in1.cpp000066400000000000000000000033161411157722000223660ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmc36in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void B36in1::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &B36in1::Poke_8000 ); if (hard) NES_DO_POKE(8000,0x8000,0x00); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_A(B36in1,8000) { ppu.SetMirroring( (address & 0x8) ? Ppu::NMT_H : Ppu::NMT_V ); prg.SwapBanks( address, address ); chr.SwapBank( address ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmc36in1.hpp000066400000000000000000000026761411157722000224030ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_36IN1_H #define NST_BOARD_BMC_36IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class B36in1 : public Board { public: explicit B36in1(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmc64in1.cpp000066400000000000000000000034451411157722000223720ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmc64in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void B64in1::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &B64in1::Poke_8000 ); if (hard) NES_DO_POKE(8000,0x8000,0x00); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_A(B64in1,8000) { ppu.SetMirroring( (address & 0x10) ? Ppu::NMT_H : Ppu::NMT_V ); const uint data = address >> 1 & address >> 2 & 0x1; chr.SwapBank( address & ~data ); prg.SwapBanks( address & ~data, address | data ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmc64in1.hpp000066400000000000000000000026761411157722000224040ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_64IN1_H #define NST_BOARD_BMC_64IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class B64in1 : public Board { public: explicit B64in1(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmc72in1.cpp000066400000000000000000000036361411157722000223730ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmc72in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void B72in1::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &B72in1::Poke_8000 ); if (hard) NES_DO_POKE(8000,0x8000,0x00); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_A(B72in1,8000) { ppu.SetMirroring( (address & 0x2000) ? Ppu::NMT_H : Ppu::NMT_V ); chr.SwapBank( address ); uint bank = address >> 7 & 0x1F; if (address & 0x1000) { bank = (bank << 1) | (address >> 6 & 0x1); prg.SwapBanks( bank, bank ); } else { prg.SwapBank( bank ); } } } } } } nestopia-1.51.1/source/core/board/NstBoardBmc72in1.hpp000066400000000000000000000026771411157722000224040ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_72IN1_H #define NST_BOARD_BMC_72IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class B72in1 : public Board { public: explicit B72in1(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmc76in1.cpp000066400000000000000000000052751411157722000224000ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmc76in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void B76in1::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &B76in1::Poke_8000 ); if (hard) { regs[0] = 0; regs[1] = 0; NES_DO_POKE(8000,0x8000,0x00); } } void B76in1::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'B','7','6'>::V) ); if (baseChunk == AsciiId<'B','7','6'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<2> data( state ); regs[0] = data[0]; regs[1] = data[1]; } state.End(); } } } void B76in1::SubSave(State::Saver& state) const { state.Begin( AsciiId<'B','7','6'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write16( regs[0] | uint(regs[1]) << 8 ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(B76in1,8000) { regs[address & 0x1] = data; uint bank = ( (regs[0] >> 1 & 0x0F) | (regs[0] >> 3 & 0x10) | (regs[1] << 5 & 0x20) ); if (regs[0] & 0x20) { bank = (bank << 1) | (regs[0] & 0x1); prg.SwapBanks( bank, bank ); } else { prg.SwapBank( bank ); } ppu.SetMirroring( (regs[0] & 0x40) ? Ppu::NMT_V : Ppu::NMT_H ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmc76in1.hpp000066400000000000000000000030471411157722000224000ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_76IN1_H #define NST_BOARD_BMC_76IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class B76in1 : public Board { public: explicit B76in1(const Context& c) : Board(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); NES_DECL_POKE( 8000 ); uint regs[2]; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmc800in1.cpp000066400000000000000000000134411411157722000224450ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "../NstDipSwitches.hpp" #include "NstBoardBmc800in1.hpp" #include "../NstCrc32.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Game800in1::CartSwitches::CartSwitches(const Context& c) : type (DetectType(c)), mode (type == GAME_800IN1 ? 0x6 : type == GAME_70IN1 ? 0xD : 0x0) {} Game800in1::CartSwitches::Type Game800in1::CartSwitches::DetectType(const Context& c) { switch (Crc32::Compute(c.prg.Mem(),c.prg.Size())) { case GAME_800IN1: return GAME_800IN1; case GAME_70IN1: return GAME_70IN1; } return GAME_XIN1; } inline void Game800in1::CartSwitches::SetMode(uint value) { mode = value; } inline uint Game800in1::CartSwitches::GetMode() const { return mode; } uint Game800in1::CartSwitches::GetValue(uint) const { return mode; } void Game800in1::CartSwitches::SetValue(uint,uint value) { mode = value; } uint Game800in1::CartSwitches::NumDips() const { return 1; } uint Game800in1::CartSwitches::NumValues(uint) const { return 16; } cstring Game800in1::CartSwitches::GetDipName(uint) const { return "Mode"; } cstring Game800in1::CartSwitches::GetValueName(uint,uint i) const { static cstring const names[3][16] = { { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16" }, { "76-in-1", "150-in-1", "168-in-1", "190-in-1", "400-in-1", "500-in-1", "800-in-1", "1200-in-1", "2000-in-1", "5000-in-1", "300-in-1", "1500-in-1", "3000-in-1", "1010000-in-1", "5010000-in-1", "10000000-in-1" }, { "4-in-1", "5-in-1", "6-in-1", "77-in-1", "22-in-1", "38-in-1", "44-in-1", "46-in-1", "52-in-1", "55-in-1", "63-in-1", "66-in-1", "68-in-1", "70-in-1", "32-in-1", "80-in-1" } }; return names[type == GAME_70IN1 ? 2 : type == GAME_800IN1 ? 1 : 0][i]; } Game800in1::Game800in1(const Context& c) : Board(c), cartSwitches(c) {} Game800in1::Device Game800in1::QueryDevice(DeviceType type) { if (type == DEVICE_DIP_SWITCHES) return &cartSwitches; else return Board::QueryDevice( type ); } void Game800in1::SubReset(bool) { mode = 0x0; Map( 0x8000U, 0xFFFFU, &Game800in1::Peek_8000, &Game800in1::Poke_8000 ); NES_DO_POKE(8000,0x8000,0x00); NES_DO_POKE(8000,0xC000,0x00); } void Game800in1::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'B','8','1'>::V) ); if (baseChunk == AsciiId<'B','8','1'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { const uint data = state.Read8(); mode = data >> 4 & 0x1; cartSwitches.SetMode( data & 0xF ); } state.End(); } } } void Game800in1::SubSave(State::Saver& state) const { state.Begin( AsciiId<'B','8','1'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( cartSwitches.GetMode() | (mode << 4) ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(Game800in1,8000) { return prg.Peek( mode ? (address & 0x7FF0) | cartSwitches.GetMode() : address - 0x8000 ); } NES_POKE_A(Game800in1,8000) { uint banks[2] = { prg.GetBank(), prg.GetBank() }; if (address < 0xC000) { ppu.SetMirroring( (address & 0x20) ? Ppu::NMT_H : Ppu::NMT_V ); if (chr.Source().GetType() == Ram::RAM) { banks[0] = (banks[0] & 0x7) | (address << 3 & 0x38); banks[1] = (banks[1] & 0x7) | (address << 3 & 0x38); } else { chr.SwapBank( address & 0x7 ); return; } } else switch (address & 0x30) { case 0x00: mode = 0x0; banks[0] = (banks[0] & 0x38) | (address & 0x7); banks[1] = banks[0] | 0x7; break; case 0x10: mode = 0x1; banks[0] = (banks[0] & 0x38) | (address & 0x7); banks[1] = banks[0] | 0x7; break; case 0x20: mode = 0x0; banks[0] = (banks[0] & 0x38) | (address & 0x6); banks[1] = banks[0] | 0x1; break; case 0x30: mode = 0x0; banks[0] = (banks[0] & 0x38) | (address & 0x7); banks[1] = banks[0] | 0x0; break; } prg.SwapBanks( banks[0], banks[1] ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmc800in1.hpp000066400000000000000000000044161411157722000224540ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_800IN1_H #define NST_BOARD_BMC_800IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class Game800in1 : public Board { public: explicit Game800in1(const Context&); private: class CartSwitches : public DipSwitches { enum Type { GAME_XIN1 = 0, GAME_800IN1 = 0x0BB4FD7A, GAME_70IN1 = 0x668D69C2 }; const Type type; uint mode; public: explicit CartSwitches(const Context&); inline void SetMode(uint); inline uint GetMode() const; private: static Type DetectType(const Context&); uint GetValue(uint) const; void SetValue(uint,uint); uint NumDips() const; uint NumValues(uint) const; cstring GetDipName(uint) const; cstring GetValueName(uint,uint) const; }; void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); Device QueryDevice(DeviceType); NES_DECL_POKE( 8000 ); NES_DECL_PEEK( 8000 ); uint mode; CartSwitches cartSwitches; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmc8157.cpp000066400000000000000000000073431411157722000221360ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "../NstDipSwitches.hpp" #include "NstBoardBmc8157.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif B8157::CartSwitches::CartSwitches() : mode(0x100) {} inline void B8157::CartSwitches::SetMode(uint value) { mode = value ? 0x100 : 0x000; } inline uint B8157::CartSwitches::GetMode() const { return mode; } uint B8157::CartSwitches::GetValue(uint) const { return mode ? 0 : 1; } void B8157::CartSwitches::SetValue(uint,uint value) { mode = value ? 0x000 : 0x100; } uint B8157::CartSwitches::NumDips() const { return 1; } uint B8157::CartSwitches::NumValues(uint) const { return 2; } cstring B8157::CartSwitches::GetDipName(uint) const { return "Mode"; } cstring B8157::CartSwitches::GetValueName(uint,uint i) const { return i ? "20-in-1" : "4-in-1"; } B8157::Device B8157::QueryDevice(DeviceType type) { if (type == DEVICE_DIP_SWITCHES) return &cartSwitches; else return Board::QueryDevice( type ); } void B8157::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &B8157::Peek_8000, &B8157::Poke_8000 ); trash = 0x00; if (hard) NES_DO_POKE(8000,0x8000,0x00); } void B8157::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'B','8','1'>::V) ); if (baseChunk == AsciiId<'B','8','1'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { const uint data = state.Read8(); trash = (data & 0x2) ? 0xFF : 0x00; cartSwitches.SetMode( data & 0x1 ); } state.End(); } } } void B8157::SubSave(State::Saver& state) const { state.Begin( AsciiId<'B','8','1'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( (cartSwitches.GetMode() ? 0x1U : 0x0U) | (trash ? 0x2U : 0x0U) ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(B8157,8000) { return prg.Peek( address - 0x8000 ) | trash; } NES_POKE_A(B8157,8000) { trash = (address & cartSwitches.GetMode()) ? 0xFF : 0x00; prg.SwapBanks ( (address >> 2 & 0x18) | (address >> 2 & 0x7), (address >> 2 & 0x18) | ((address & 0x200) ? 0x7 : 0x0) ); ppu.SetMirroring( (address & 0x2) ? Ppu::NMT_H : Ppu::NMT_V ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmc8157.hpp000066400000000000000000000040641411157722000221400ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_8157_H #define NST_BOARD_BMC_8157_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class B8157 : public Board { public: explicit B8157(const Context& c) : Board(c) {} private: class CartSwitches : public DipSwitches { uint mode; public: CartSwitches(); inline void SetMode(uint); inline uint GetMode() const; private: uint GetValue(uint) const; void SetValue(uint,uint); uint NumDips() const; uint NumValues(uint) const; cstring GetDipName(uint) const; cstring GetValueName(uint,uint) const; }; void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); Device QueryDevice(DeviceType); NES_DECL_PEEK( 8000 ); NES_DECL_POKE( 8000 ); uint trash; CartSwitches cartSwitches; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmc9999999in1.cpp000066400000000000000000000032611411157722000230330ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmc9999999in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void B9999999in1::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &B9999999in1::Poke_8000 ); if (hard) NES_DO_POKE(8000,0x8000,0x00); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_A(B9999999in1,8000) { ppu.Update(); prg.SwapBank( address >> 1 ); chr.SwapBank( address >> 3 ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmc9999999in1.hpp000066400000000000000000000027221411157722000230410ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_9999999IN1_H #define NST_BOARD_BMC_9999999IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class B9999999in1 : public Board { public: explicit B9999999in1(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcA65as.cpp000066400000000000000000000035661411157722000224140ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmcA65as.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void A65as::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &A65as::Poke_8000 ); if (hard) NES_DO_POKE(8000,0x8000,0x00); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(A65as,8000) { if (data & 0x40) prg.SwapBank( data >> 1 ); else prg.SwapBanks( (data >> 1 & 0x18) | (data & 0x7), (data >> 1 & 0x18) | 0x7 ); ppu.SetMirroring ( (data & 0x80) ? (data & 0x20) ? Ppu::NMT_1 : Ppu::NMT_0 : (data & 0x08) ? Ppu::NMT_H : Ppu::NMT_V ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcA65as.hpp000066400000000000000000000026741411157722000224200ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_A65AS_H #define NST_BOARD_BMC_A65AS_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class A65as : public Board { public: explicit A65as(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcBallgames11in1.cpp000066400000000000000000000065371411157722000241770ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmcBallgames11in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Ballgames11in1::SubReset(const bool hard) { Map( 0x6000U, 0x7FFFU, &Ballgames11in1::Peek_6000, &Ballgames11in1::Poke_6000 ); Map( 0x8000U, 0xBFFFU, &Ballgames11in1::Poke_8000 ); Map( 0xC000U, 0xDFFFU, &Ballgames11in1::Poke_C000 ); Map( 0xE000U, 0xFFFFU, &Ballgames11in1::Poke_8000 ); if (hard) { bank = 0x0; mode = 0x1; UpdateBanks(); } } void Ballgames11in1::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'B','B','G'>::V) ); if (baseChunk == AsciiId<'B','B','G'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { { const uint data = state.Read8(); mode = data & 0x3; bank = data >> 4; } UpdateBanks(); } state.End(); } } } void Ballgames11in1::SubSave(State::Saver& state) const { state.Begin( AsciiId<'B','B','G'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( mode | (bank << 4) ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Ballgames11in1::UpdateBanks() { uint offset; if (mode & 0x1) { prg.SwapBank( bank ); offset = 0x23; } else { prg.SwapBanks( (bank << 1) | (mode >> 1), bank << 1 | 0x7 ); offset = 0x2F; } wrk.SwapBank( offset | (bank << 2) ); ppu.SetMirroring( (mode == 0x3) ? Ppu::NMT_H : Ppu::NMT_V ); } NES_PEEK_A(Ballgames11in1,6000) { return wrk[0][address - 0x6000]; } NES_POKE_D(Ballgames11in1,6000) { mode = (data >> 3 & 0x2) | (data >> 1 & 0x1); UpdateBanks(); } NES_POKE_D(Ballgames11in1,8000) { bank = data & 0xF; UpdateBanks(); } NES_POKE_D(Ballgames11in1,C000) { bank = data & 0xF; mode = (data >> 3 & 0x2) | (mode & 0x1); UpdateBanks(); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcBallgames11in1.hpp000066400000000000000000000033101411157722000241660ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_BALLGAMES11IN1_H #define NST_BOARD_BMC_BALLGAMES11IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class Ballgames11in1 : public Board { public: explicit Ballgames11in1(const Context& c) : Board(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void UpdateBanks(); NES_DECL_PEEK( 6000 ); NES_DECL_POKE( 6000 ); NES_DECL_POKE( 8000 ); NES_DECL_POKE( C000 ); uint bank; uint mode; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcCh001.cpp000066400000000000000000000056021411157722000223010ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmcCh001.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Ch001::SubReset(const bool hard) { Map( 0x8000U, 0xBFFFU, &Ch001::Peek_8000, &Ch001::Poke_8000 ); Map( 0x8000U, 0xFFFFU, &Ch001::Poke_8000 ); openBus = false; if (hard) NES_DO_POKE(8000,0x8000,0x00); } void Ch001::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'B','P','F'>::V) ); if (baseChunk == AsciiId<'B','P','F'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'I','R','Q'>::V) openBus = state.Read8() & 0x1; state.End(); } } } void Ch001::SubSave(State::Saver& state) const { state.Begin( AsciiId<'B','P','F'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( openBus ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(Ch001,8000) { return !openBus ? prg.Peek( address - 0x8000 ) : (address >> 8); } NES_POKE_A(Ch001,8000) { openBus = ((address & 0x300) == 0x300); prg.SwapBanks ( (address >> 1 & 0x1FC) | ((address & 0x2) ? 0x0 : (address >> 1 & 0x2) | 0x0), (address >> 1 & 0x1FC) | ((address & 0x2) ? 0x1 : (address >> 1 & 0x2) | 0x1), (address >> 1 & 0x1FC) | ((address & 0x2) ? 0x2 : (address >> 1 & 0x2) | 0x0), (address & 0x800) ? (address >> 0 & 0x07C) | ((address & 0x6) ? 0x3 : 0x1) : (address >> 1 & 0x1FC) | ((address & 0x2) ? 0x3 : ((address >> 1 & 0x2) | 0x1)) ); ppu.SetMirroring( (address & 0x1) ? Ppu::NMT_H : Ppu::NMT_V ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcCh001.hpp000066400000000000000000000031031411157722000223000ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_CH001_H #define NST_BOARD_BMC_CH001_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class Ch001 : public Board { public: explicit Ch001(const Context& c) : Board(c) {} private: void SubReset(bool); void SubLoad(State::Loader&,dword); void SubSave(State::Saver&) const; NES_DECL_PEEK( 8000 ); NES_DECL_POKE( 8000 ); ibool openBus; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcCtc65.cpp000066400000000000000000000060771411157722000224210ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmcCtc65.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Ctc65::SubReset(bool) { for (uint i=0x0000; i < 0x8000; i += 0x2) { Map( 0x8000 + i, &Ctc65::Peek_8000, &Ctc65::Poke_8000 ); Map( 0x8001 + i, &Ctc65::Peek_8000, &Ctc65::Poke_8001 ); } regs[0] = 0; regs[1] = 0; UpdatePrg(); } void Ctc65::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'B','C','T'>::V) ); if (baseChunk == AsciiId<'B','C','T'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<2> data( state ); regs[0] = data[0]; regs[1] = data[1]; UpdatePrg(); } state.End(); } } } void Ctc65::SubSave(State::Saver& state) const { const byte data[2] = {regs[0],regs[1]}; state.Begin( AsciiId<'B','C','T'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Ctc65::UpdatePrg() { const uint chip = (regs[1] << 5 & 0x20) << (regs[0] >> 7); openBus = chip < (regs[0] >> 7); prg.SwapBanks ( chip | (regs[0] & 0x1E) | (regs[0] >> 5 & regs[0]), chip | (regs[0] & 0x1F) | (~regs[0] >> 5 & 0x01) ); } NES_POKE_D(Ctc65,8000) { if (regs[0] != data) { regs[0] = data; UpdatePrg(); ppu.SetMirroring( (data & 0x40) ? Ppu::NMT_V : Ppu::NMT_H ); } } NES_POKE_D(Ctc65,8001) { if (regs[1] != data) { regs[1] = data; UpdatePrg(); } } NES_PEEK_A(Ctc65,8000) { return !openBus ? prg.Peek( address - 0x8000 ) : (address >> 8); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcCtc65.hpp000066400000000000000000000032141411157722000224140ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_CTC65_H #define NST_BOARD_BMC_CTC65_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class Ctc65 : public Board { public: explicit Ctc65(const Context& c) : Board(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void UpdatePrg(); NES_DECL_PEEK( 8000 ); NES_DECL_POKE( 8000 ); NES_DECL_POKE( 8001 ); uint regs[2]; ibool openBus; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcFamily4646B.cpp000066400000000000000000000051571411157722000234020ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardBmcFamily4646B.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Family4646B::SubReset(const bool hard) { if (hard) exReg = 0; Mmc3::SubReset( hard ); Map( 0x6001U, 0x6001U, &Family4646B::Poke_6001 ); } void Family4646B::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'B','F','K'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) exReg = state.Read8(); state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void Family4646B::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); state.Begin( AsciiId<'B','F','K'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( exReg ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Family4646B,6001) { if (exReg != data) { exReg = data; Mmc3::UpdatePrg(); Mmc3::UpdateChr(); } } void NST_FASTCALL Family4646B::UpdatePrg(uint address,uint bank) { prg.SwapBank( address, (exReg << 4 & 0x20) | (bank & 0x1F) ); } void NST_FASTCALL Family4646B::UpdateChr(uint address,uint bank) const { chr.SwapBank( address, (exReg << 3 & 0x100) | bank ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcFamily4646B.hpp000066400000000000000000000032351411157722000234020ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_FAMILY4646B_H #define NST_BOARD_BMC_FAMILY4646B_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class Family4646B : public Mmc3 { public: explicit Family4646B(const Context& c) : Mmc3(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void NST_FASTCALL UpdatePrg(uint,uint); void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_POKE( 6001 ); uint exReg; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcFk23c.cpp000066400000000000000000000211011411157722000223660ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardBmcFk23c.hpp" #include "../NstCrc32.hpp" #include "../NstDipSwitches.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif class Fk23c::CartSwitches : public DipSwitches { enum Type { CRC_4_IN_1 = 0x38BA830E, CRC_6_IN_1 = 0xC16708E8, CRC_8_IN_1 = 0x63A87C95, CRC_15_IN_1 = 0x30FF6159, CRC_18_IN_1 = 0x83A38A2F, CRC_20_IN_1 = 0xFD9D1925 }; uint mode; const Type type; explicit CartSwitches(Type t) : mode(0), type(t) {} uint NumValues(uint) const { return type == CRC_4_IN_1 || type == CRC_6_IN_1 || type == CRC_8_IN_1 ? 2 : 8; } public: static CartSwitches* Create(const Context& c) { switch (const dword crc = Crc32::Compute(c.prg.Mem(),c.prg.Size())) { case CRC_4_IN_1: case CRC_6_IN_1: case CRC_8_IN_1: case CRC_15_IN_1: case CRC_18_IN_1: case CRC_20_IN_1: return new CartSwitches( static_cast(crc) ); } return NULL; } void SetMode(uint value) { const uint num = CartSwitches::NumValues(0) - 1; mode = NST_MIN(value,num); } uint GetMode() const { return mode; } private: uint GetValue(uint) const { return mode; } void SetValue(uint,uint value) { mode = value; } uint NumDips() const { return 1; } cstring GetDipName(uint) const { return "Mode"; } cstring GetValueName(uint,uint i) const { switch (type) { case CRC_4_IN_1: { static const char names[2][8] = { "4-in-1", "7-in-1" }; return names[i]; } case CRC_6_IN_1: { static const char names[2][8] = { "6-in-1", "4-in-1" }; return names[i]; } case CRC_8_IN_1: { static const char names[2][8] = { "8-in-1", "4-in-1" }; return names[i]; } case CRC_15_IN_1: case CRC_20_IN_1: { static const char names[8][9] = { "15-in-1", "80-in-1", "160-in-1", "20-in-1", "99-in-1", "210-in-1", "25-in-1", "260-in-1" }; return names[i]; } case CRC_18_IN_1: { static const char names[8][9] = { "18-in-1", "58-in-1", "160-in-1", "15-in-1", "52-in-1", "180-in-1", "30-in-1", "288-in-1" }; return names[i]; } } return NULL; } }; Fk23c::Fk23c(const Context& c) : Mmc3(c), cartSwitches(CartSwitches::Create(c)) {} Fk23c::~Fk23c() { delete cartSwitches; } void Fk23c::SubReset(const bool hard) { for (uint i=0; i < 8; ++i) exRegs[i] = 0xFF; if (prg.Source().Size() <= SIZE_512K) { for (uint i=0; i < 4; ++i) exRegs[i] = 0x00; } unromChr = 0x0; Mmc3::SubReset( hard ); Map( 0x5000U, 0x5FFFU, &Fk23c::Poke_5000 ); Map( 0x8000U, 0xFFFFU, &Fk23c::Poke_8000 ); UpdatePrg(); UpdateChr(); } Fk23c::Device Fk23c::QueryDevice(DeviceType type) { if (type == DEVICE_DIP_SWITCHES) return cartSwitches; else return Board::QueryDevice( type ); } void Fk23c::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'B','F','K'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<9> data( state ); for (uint i=0; i < 8; ++i) exRegs[i] = data[i]; unromChr = data[8] & 0x3; if (cartSwitches) cartSwitches->SetMode( data[8] >> 2 & 0x7 ); } state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void Fk23c::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); const byte data[] = { exRegs[0], exRegs[1], exRegs[2], exRegs[3], exRegs[4], exRegs[5], exRegs[6], exRegs[7], unromChr | (cartSwitches ? cartSwitches->GetMode() << 2 : 0) }; state.Begin( AsciiId<'B','F','K'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void NST_FASTCALL Fk23c::UpdatePrg(uint address,uint bank) { if ((exRegs[0] & 0x7U) - 3 > 1 && (!(exRegs[3] & 0x2U) || address < 0x4000)) { if (exRegs[0] & 0x3U) bank = (bank & (0x3FU >> (exRegs[0] & 0x3U))) | (exRegs[1] << 1); prg.SwapBank( address, bank ); } } void NST_FASTCALL Fk23c::UpdateChr(uint address,uint bank) const { if (!(exRegs[0] & 0x40U) && (!(exRegs[3] & 0x2U) || (address != 0x400 && address != 0xC00))) chr.SwapBank( address, (exRegs[2] & 0x7FU) << 3 | bank ); } void Fk23c::UpdatePrg() { if ((exRegs[0] & 0x7U) == 4) { prg.SwapBank( exRegs[1] >> 1 ); } else if ((exRegs[0] & 0x7U) == 3) { prg.SwapBanks( exRegs[1], exRegs[1] ); } else { if (exRegs[3] & 0x2U) prg.SwapBanks( exRegs[4], exRegs[5] ); Mmc3::UpdatePrg(); } } void Fk23c::UpdateChr() const { ppu.Update(); if (exRegs[0] & 0x40U) { chr.SwapBank( exRegs[2] | unromChr ); } else { if (exRegs[3] & 0x2U) { const uint base = (exRegs[2] & 0x7FU) << 3; chr.SwapBank( base | exRegs[6] ); chr.SwapBank( base | exRegs[7] ); } Mmc3::UpdateChr(); } } NES_POKE_AD(Fk23c,5000) { if (address & (1U << ((cartSwitches ? cartSwitches->GetMode() : 0) + 4))) { exRegs[address & 0x3] = data; Fk23c::UpdatePrg(); Fk23c::UpdateChr(); } } NES_POKE_AD(Fk23c,8000) { if (exRegs[0] & 0x40U) { unromChr = (exRegs[0] & 0x30U) ? 0x0 : data & 0x3; Fk23c::UpdateChr(); } else switch (address & 0xE001) { case 0x8000: Mmc3::NES_DO_POKE(8000,address,data); break; case 0x8001: if (exRegs[3] << 2 & (regs.ctrl0 & 0x8)) { exRegs[4 | (regs.ctrl0 & 0x3)] = data; Fk23c::UpdatePrg(); Fk23c::UpdateChr(); } else { Mmc3::NES_DO_POKE(8001,address,data); } break; case 0xA000: SetMirroringHV(data); break; case 0xA001: Mmc3::NES_DO_POKE(A001,address,data); break; case 0xC000: Mmc3::NES_DO_POKE(C000,address,data); break; case 0xC001: Mmc3::NES_DO_POKE(C001,address,data); break; case 0xE000: Mmc3::NES_DO_POKE(E000,address,data); break; case 0xE001: Mmc3::NES_DO_POKE(E001,address,data); break; default: NST_UNREACHABLE(); } } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcFk23c.hpp000066400000000000000000000035351411157722000224060ustar00rootroot00000000000000 //////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_FK23C_H #define NST_BOARD_BMC_FK23C_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class Fk23c : public Mmc3 { public: explicit Fk23c(const Context&); private: ~Fk23c(); class CartSwitches; void SubReset(bool); void SubLoad(State::Loader&,dword); void SubSave(State::Saver&) const; Device QueryDevice(DeviceType); void UpdatePrg(); void UpdateChr() const; void NST_FASTCALL UpdatePrg(uint,uint); void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_POKE( 5000 ); NES_DECL_POKE( 8000 ); byte exRegs[8]; uint unromChr; CartSwitches* const cartSwitches; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcGamestarA.cpp000066400000000000000000000130301411157722000233640ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "../NstDipSwitches.hpp" #include "NstBoardBmcGamestarA.hpp" #include "../NstCrc32.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif class GamestarA::CartSwitches : public DipSwitches { enum Type { GKA_6IN1A = 0x2A80F48F, GKA_6IN1B = 0xF274BF1F, GKA_47IN1 = 0x8DA67F2D, GKA_54IN1 = 0x38EB6D5A, GKA_103IN1 = 0xB1F9BD94 }; uint mode; const Type type; explicit CartSwitches(Type t) : mode(0), type(t) {} public: static CartSwitches* Create(const Context& c) { switch (const dword crc = Crc32::Compute(c.prg.Mem(),c.prg.Size())) { case GKA_6IN1A: case GKA_6IN1B: case GKA_47IN1: case GKA_54IN1: case GKA_103IN1: return new CartSwitches( static_cast(crc) ); } return NULL; } void SetMode(uint value) { mode = value & 0x3; } uint GetMode() const { return mode; } private: uint GetValue(uint) const { return mode; } void SetValue(uint,uint value) { mode = value; } uint NumDips() const { return 1; } uint NumValues(uint) const { return 4; } cstring GetDipName(uint) const { return "Mode"; } cstring GetValueName(uint,uint i) const { static cstring const names[4][4] = { { "6-in-1", "2-in-1 (1)", "2-in-1 (2)", "2-in-1 (3)" }, { "47-in-1", "57-in-1", "67-in-1", "77-in-1" }, { "54-in-1", "74-in-1", "84-in-1", "94-in-1" }, { "103-in-1", "105-in-1", "106-in-1", "109-in-1" } }; switch (type) { case GKA_6IN1A: case GKA_6IN1B: default: return names[0][i]; case GKA_47IN1: return names[1][i]; case GKA_54IN1: return names[2][i]; case GKA_103IN1: return names[3][i]; } } }; GamestarA::GamestarA(const Context& c) : Board(c), cartSwitches(CartSwitches::Create(c)) {} GamestarA::~GamestarA() { delete cartSwitches; } GamestarA::Device GamestarA::QueryDevice(DeviceType type) { if (type == DEVICE_DIP_SWITCHES && cartSwitches) return cartSwitches; else return Board::QueryDevice( type ); } void GamestarA::SubReset(const bool hard) { Map( 0x6000U, &GamestarA::Peek_6000 ); for (uint i=0x0000; i < 0x8000; i += 0x1000) { Map( 0x8000+i, 0x87FF+i, &GamestarA::Poke_8000 ); Map( 0x8800+i, 0x8FFF+i, &GamestarA::Poke_8800 ); } if (hard) { regs[0] = 0; regs[1] = 0; NES_DO_POKE(8800,0x8800,0x00); } } void GamestarA::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( (baseChunk == AsciiId<'B','G','A'>::V) ); if (baseChunk == AsciiId<'B','G','A'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<3> data( state ); regs[0] = data[1]; regs[1] = data[2]; if (cartSwitches) cartSwitches->SetMode( data[0] ); } state.End(); } } } void GamestarA::SubSave(State::Saver& state) const { const byte data[3] = { cartSwitches ? cartSwitches->GetMode() : 0, regs[0], regs[1] }; state.Begin( AsciiId<'B','G','A'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK(GamestarA,6000) { return cartSwitches ? cartSwitches->GetMode() : 0x00; } void GamestarA::UpdateChr() const { chr.SwapBank( (regs[0] >> 1 & 0x8) | (regs[0] & 0x7) | (regs[1] & 0x3) ); } NES_POKE_D(GamestarA,8000) { regs[1] = data; ppu.Update(); UpdateChr(); } NES_POKE_D(GamestarA,8800) { regs[0] = data; prg.SwapBanks( (data >> 5) & ~(data >> 7), (data >> 5) | (data >> 7) ); ppu.SetMirroring( (data & 0x8) ? Ppu::NMT_H : Ppu::NMT_V ); UpdateChr(); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcGamestarA.hpp000066400000000000000000000033701411157722000233770ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_GAMESTARA_H #define NST_BOARD_BMC_GAMESTARA_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class GamestarA : public Board { public: explicit GamestarA(const Context&); private: ~GamestarA(); class CartSwitches; void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); Device QueryDevice(DeviceType); void UpdateChr() const; NES_DECL_PEEK( 6000 ); NES_DECL_POKE( 8000 ); NES_DECL_POKE( 8800 ); uint regs[2]; CartSwitches* const cartSwitches; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcGamestarB.cpp000066400000000000000000000034221411157722000233710ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmcGamestarB.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void GamestarB::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &GamestarB::Poke_8000 ); if (hard) NES_DO_POKE(8000,0x8000,0x00); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_A(GamestarB,8000) { ppu.SetMirroring( (address & 0x80) ? Ppu::NMT_H : Ppu::NMT_V ); prg.SwapBanks( address & ~(~address >> 6 & 0x1), address | (~address >> 6 & 0x1) ); chr.SwapBank( address >> 3 ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcGamestarB.hpp000066400000000000000000000027141411157722000234010ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_GAMESTARB_H #define NST_BOARD_BMC_GAMESTARB_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class GamestarB : public Board { public: explicit GamestarB(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcGolden190in1.cpp000066400000000000000000000033551411157722000236030ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmcGolden190in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Golden190in1::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &Golden190in1::Poke_8000 ); if (hard) NES_DO_POKE(8000,0x8000,0x00); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Golden190in1,8000) { ppu.SetMirroring( (data & 0x1) ? Ppu::NMT_H : Ppu::NMT_V ); data >>= 2; prg.SwapBanks( data, data ); chr.SwapBank( data ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcGolden190in1.hpp000066400000000000000000000027301411157722000236040ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_GOLDEN190IN1_H #define NST_BOARD_BMC_GOLDEN190IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class Golden190in1 : public Board { public: explicit Golden190in1(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcGoldenCard6in1.cpp000066400000000000000000000112151411157722000242230ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardBmcGoldenCard6in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void GoldenCard6in1::SubReset(const bool hard) { if (hard) { exRegs[0] = 0x00; exRegs[1] = 0xFF; exRegs[2] = 0x03; } exRegs[3] = false; Mmc3::SubReset( hard ); Map( 0x5000U, &GoldenCard6in1::Poke_5000 ); Map( 0x5001U, &GoldenCard6in1::Poke_5001 ); Map( 0x5007U, &GoldenCard6in1::Poke_5007 ); for (uint i=0x0000; i < 0x2000; i += 0x2) { Map( 0x8000 + i, &GoldenCard6in1::Poke_8000 ); Map( 0x8001 + i, &GoldenCard6in1::Poke_8001 ); Map( 0xA000 + i, &GoldenCard6in1::Poke_A000 ); Map( 0xA001 + i, &GoldenCard6in1::Poke_A001 ); } } void GoldenCard6in1::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'B','G','C'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { state.Read( exRegs ); exRegs[3] &= 0x1U; } state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void GoldenCard6in1::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); state.Begin( AsciiId<'B','G','C'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( exRegs ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void NST_FASTCALL GoldenCard6in1::UpdatePrg(uint address,uint bank) { if (exRegs[1] & 0x8U) bank = (bank & 0x1F); else bank = (bank & 0x0F) | (exRegs[1] & 0x10U); prg.SwapBank( address, (exRegs[1] << 5 & 0x60U) | bank ); } void NST_FASTCALL GoldenCard6in1::UpdateChr(uint address,uint bank) const { if (!(exRegs[1] & 0x8U)) bank = (exRegs[1] << 3 & 0x80U) | (bank & 0x7F); chr.SwapBank( address, (exRegs[1] << 8 & 0x300U) | bank ); } NES_POKE_D(GoldenCard6in1,5000) { exRegs[0] = data; if (data & 0x80) { data = (data & 0x0F) | (exRegs[1] << 4 & 0x30U); prg.SwapBanks( data, data ); } else { Mmc3::UpdatePrg(); } } NES_POKE_D(GoldenCard6in1,5001) { if (exRegs[1] != data) { exRegs[1] = data; Mmc3::UpdatePrg(); } } NES_POKE_D(GoldenCard6in1,5007) { exRegs[2] = data; } NES_POKE_D(GoldenCard6in1,8000) { if (exRegs[2]) Mmc3::NES_DO_POKE(C000,0xC000,data); else Mmc3::NES_DO_POKE(8000,0x8000,data); } NES_POKE_D(GoldenCard6in1,8001) { if (exRegs[2]) { static const byte lut[8] = {0,6,3,7,5,2,4,1}; data = (data & 0xC0) | lut[data & 0x07]; exRegs[3] = true; Mmc3::NES_DO_POKE(8000,0x8000,data); } else { Mmc3::NES_DO_POKE(8001,0x8001,data); } } NES_POKE_D(GoldenCard6in1,A000) { if (exRegs[2]) { if (exRegs[3] && ((exRegs[0] & 0x80U) == 0 || (regs.ctrl0 & 0x7) < 6)) { exRegs[3] = false; Mmc3::NES_DO_POKE(8001,0x8001,data); } } else { SetMirroringHV( data ); } } NES_POKE_D(GoldenCard6in1,A001) { if (exRegs[2]) SetMirroringHV( data ); else Mmc3::NES_DO_POKE(A001,0xA001,data); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcGoldenCard6in1.hpp000066400000000000000000000035331411157722000242340ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_GOLDENCARD6IN1_H #define NST_BOARD_BMC_GOLDENCARD6IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class GoldenCard6in1 : public Mmc3 { public: explicit GoldenCard6in1(const Context& c) : Mmc3(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void NST_FASTCALL UpdatePrg(uint,uint); void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_POKE( 5000 ); NES_DECL_POKE( 5001 ); NES_DECL_POKE( 5007 ); NES_DECL_POKE( 8000 ); NES_DECL_POKE( 8001 ); NES_DECL_POKE( A000 ); NES_DECL_POKE( A001 ); byte exRegs[4]; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcGoldenGame260in1.cpp000066400000000000000000000067731411157722000244020ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmcGoldenGame260in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif GoldenGame260in1::GoldenGame260in1(const Context& c) : Board (c), selector ( prg.Source().Size() == SIZE_1024K ? 0 : prg.Source().Size() == SIZE_2048K ? 1 : prg.Source().Size() == SIZE_3072K ? 2 : 3 ) { } void GoldenGame260in1::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &GoldenGame260in1::Poke_8000 ); if (selector != 3) Map( 0x8000U, 0xFFFFU, &GoldenGame260in1::Peek_8000 ); if (hard) { open = false; NES_DO_POKE(8000,0x8000,0x00); } } void GoldenGame260in1::SubLoad(State::Loader& state,const dword baseChunk) { if (selector != 3) { NST_VERIFY( baseChunk == (AsciiId<'B','G','G'>::V) ); if (baseChunk == AsciiId<'B','G','G'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'B','U','S'>::V) open = state.Read8() & 0x1; state.End(); } } } } void GoldenGame260in1::SubSave(State::Saver& state) const { if (selector != 3) state.Begin( AsciiId<'B','G','G'>::V ).Begin( AsciiId<'B','U','S'>::V ).Write8( open != 0 ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_A(GoldenGame260in1,8000) { ppu.SetMirroring ( (address & 0x0400) ? Ppu::NMT_0 : (address & 0x2000) ? Ppu::NMT_H : Ppu::NMT_V ); static const byte slots[4][4][2] = { { {0x00,0}, {0x00,1}, {0x00,1}, {0x00,1} }, { {0x00,0}, {0x00,1}, {0x20,0}, {0x00,1} }, { {0x00,0}, {0x00,1}, {0x20,0}, {0x40,0} }, { {0x00,0}, {0x20,0}, {0x40,0}, {0x60,0} } }; uint bank = slots[selector][address >> 8 & 0x3][0] | (address & 0x1F); open = slots[selector][address >> 8 & 0x3][1]; if (address & 0x800) { bank = (bank << 1) | (address >> 12 & 0x1); prg.SwapBanks( bank, bank ); } else { prg.SwapBank( bank ); } } NES_PEEK_A(GoldenGame260in1,8000) { return !open ? prg.Peek(address - 0x8000) : (address >> 8); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcGoldenGame260in1.hpp000066400000000000000000000031611411157722000243730ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_GOLDENGAME260IN1_H #define NST_BOARD_BMC_GOLDENGAME260IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class GoldenGame260in1 : public Board { public: explicit GoldenGame260in1(const Context&); private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); NES_DECL_POKE( 8000 ); NES_DECL_PEEK( 8000 ); uint open; const uint selector; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcHero.cpp000066400000000000000000000063621411157722000224270ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardBmcHero.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Hero::SubReset(const bool hard) { if (hard) { for (uint i=0; i < 5; ++i) exRegs[i] = 0; } Mmc3::SubReset( hard ); Map( 0x6000U, 0x7FFFU, &Hero::Poke_6000 ); } void Hero::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'B','H','R'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<5> data( state ); for (uint i=0; i < 5; ++i) exRegs[i] = data[i]; } state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void Hero::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); const byte data[5] = { exRegs[0], exRegs[1], exRegs[2], exRegs[3], exRegs[4] }; state.Begin( AsciiId<'B','H','R'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(Hero,6000) { if (exRegs[3] & 0x40) { NST_VERIFY( wrk.Writable(0) ); if (wrk.Writable(0)) wrk[0][address - 0x6000] = data; } else { exRegs[exRegs[4]] = data; exRegs[4] = (exRegs[4] + 1) & 0x3; Mmc3::UpdatePrg(); Mmc3::UpdateChr(); } } void NST_FASTCALL Hero::UpdatePrg(uint address,uint bank) { prg.SwapBank( address, exRegs[1] | (bank & (exRegs[3] ^ 0x3F)) ); } void NST_FASTCALL Hero::UpdateChr(uint address,uint bank) const { if (chr.Source().GetType() == Ram::ROM) { chr.SwapBank ( address, (exRegs[0] | (exRegs[2] << 4 & 0xF00)) | ((exRegs[2] & 0x8) ? bank & ((1U << ((exRegs[2] & 0x7) + 1)) - 1) : exRegs[2] ? 0 : bank) ); } } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcHero.hpp000066400000000000000000000032051411157722000224250ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_HERO_H #define NST_BOARD_BMC_HERO_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class Hero : public Mmc3 { public: explicit Hero(const Context& c) : Mmc3(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void NST_FASTCALL UpdatePrg(uint,uint); void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_POKE( 6000 ); uint exRegs[5]; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcMarioParty7in1.cpp000066400000000000000000000064111411157722000243130ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardBmcMarioParty7in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void MarioParty7in1::SubReset(const bool hard) { if (hard) { exRegs[0] = 0; exRegs[1] = 0; } Mmc3::SubReset( hard ); Map( 0x6000U, 0x7FFFU, &MarioParty7in1::Poke_6000 ); } void MarioParty7in1::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'B','M','P'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<2> data( state ); exRegs[0] = data[0]; exRegs[1] = data[1]; } state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void MarioParty7in1::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); const byte data[2] = { exRegs[0], exRegs[1] }; state.Begin( AsciiId<'B','M','P'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(MarioParty7in1,6000) { if (exRegs[1]) { NST_VERIFY( wrk.Writable(0) ); if (wrk.Writable(0)) wrk[0][address - 0x6000] = data; } else { exRegs[1] = 1; exRegs[0] = data; Mmc3::UpdatePrg(); Mmc3::UpdateChr(); } } void NST_FASTCALL MarioParty7in1::UpdatePrg(uint address,uint bank) { prg.SwapBank ( address, (((exRegs[0] & 0x6) | (exRegs[0] >> 3 & exRegs[0] & 0x1)) << 4) | (bank & ((exRegs[0] << 1 & 0x10) ^ 0x1F)) ); } void NST_FASTCALL MarioParty7in1::UpdateChr(uint address,uint bank) const { chr.SwapBank ( address, (((exRegs[0] >> 3 & 0x4) | (exRegs[0] >> 1 & 0x2) | ((exRegs[0] >> 6) & (exRegs[0] >> 4) & 0x1)) << 7) | (bank & (((exRegs[0] & 0x40) << 1) ^ 0xFF)) ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcMarioParty7in1.hpp000066400000000000000000000032711411157722000243210ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_MARIOPARTY7IN1_H #define NST_BOARD_BMC_MARIOPARTY7IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class MarioParty7in1 : public Mmc3 { public: explicit MarioParty7in1(const Context& c) : Mmc3(c,Mmc3::REV_C) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void NST_FASTCALL UpdatePrg(uint,uint); void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_POKE( 6000 ); uint exRegs[2]; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcNovelDiamond.cpp000066400000000000000000000032541411157722000241060ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmcNovelDiamond.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void NovelDiamond::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &NovelDiamond::Poke_8000 ); if (hard) NES_DO_POKE(8000,0x8000,0x00); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_A(NovelDiamond,8000) { ppu.Update(); prg.SwapBank( address ); chr.SwapBank( address ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcNovelDiamond.hpp000066400000000000000000000027301411157722000241110ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_NOVELDIAMOND_H #define NST_BOARD_BMC_NOVELDIAMOND_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class NovelDiamond : public Board { public: explicit NovelDiamond(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcPowerjoy84in1.cpp000066400000000000000000000076411411157722000241350ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardBmcPowerjoy84in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Powerjoy84in1::SubReset(const bool hard) { if (hard) { for (uint i=0; i < 4; ++i) exRegs[i] = 0; } Mmc3::SubReset( hard ); for (uint i=0x6000; i < 0x8000; i += 0x4) { Map( i + 0x0, &Powerjoy84in1::Poke_6000 ); Map( i + 0x1, &Powerjoy84in1::Poke_6001 ); Map( i + 0x2, &Powerjoy84in1::Poke_6001 ); Map( i + 0x3, &Powerjoy84in1::Poke_6000 ); } } void Powerjoy84in1::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'B','P','J'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) state.Read( exRegs ); state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void Powerjoy84in1::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); state.Begin( AsciiId<'B','P','J'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( exRegs ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif uint Powerjoy84in1::GetExChrExBank() const { return ( (~uint(exRegs[0]) << 0 & 0x080 & uint(exRegs[2])) | ( uint(exRegs[0]) << 4 & 0x080 & uint(exRegs[0])) | ( uint(exRegs[0]) << 3 & 0x100) | ( uint(exRegs[0]) << 5 & 0x200) ); } void NST_FASTCALL Powerjoy84in1::UpdatePrg(uint address,uint bank) { bank &= (~uint(exRegs[0]) >> 2 & 0x10) | 0x0F; bank |= (exRegs[0] & (0x6U | (exRegs[0] & 0x40U) >> 6)) << 4 | (exRegs[0] & 0x10U) << 3; if (!(exRegs[3] & 0x3U)) { prg.SwapBank( address, bank ); } else if (address == (regs.ctrl0 << 8 & 0x4000)) { if ((exRegs[3] & 0x3U) == 0x3) prg.SwapBank( bank >> 2 ); else prg.SwapBanks( bank >> 1, bank >> 1 ); } } void NST_FASTCALL Powerjoy84in1::UpdateChr(uint address,uint bank) const { if (!(exRegs[3] & 0x10U)) chr.SwapBank( address, GetExChrExBank() | (bank & ((exRegs[0] & 0x80U) - 1)) ); } NES_POKE_AD(Powerjoy84in1,6000) { if (!(exRegs[3] & 0x80U)) NES_DO_POKE(6001,address,data); } NES_POKE_AD(Powerjoy84in1,6001) { address &= 0x3; if (exRegs[address] != data) { exRegs[address] = data; if (exRegs[3] & 0x10U) chr.SwapBank( GetExChrExBank() >> 3 | (exRegs[2] & 0xFU) ); else Mmc3::UpdateChr(); Mmc3::UpdatePrg(); } } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcPowerjoy84in1.hpp000066400000000000000000000033651411157722000241410ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_POWERJOY84IN1_H #define NST_BOARD_BMC_POWERJOY84IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class Powerjoy84in1 : public Mmc3 { public: explicit Powerjoy84in1(const Context& c) : Mmc3(c,Mmc3::REV_C) {} private: void SubReset(bool); void SubLoad(State::Loader&,dword); void SubSave(State::Saver&) const; uint GetExChrExBank() const; void NST_FASTCALL UpdatePrg(uint,uint); void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_POKE( 6000 ); NES_DECL_POKE( 6001 ); byte exRegs[4]; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcResetBased4in1.cpp000066400000000000000000000042771411157722000242520ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmcResetBased4in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void ResetBased4in1::SubReset(const bool hard) { if (hard) resetSwitch = 0; else resetSwitch = (resetSwitch + 1) & 0x3; chr.SwapBank( resetSwitch ); prg.SwapBanks( resetSwitch, resetSwitch ); } void ResetBased4in1::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'B','R','4'>::V) ); if (baseChunk == AsciiId<'B','R','4'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) resetSwitch = state.Read8() & 0x3; state.End(); } } } void ResetBased4in1::SubSave(State::Saver& state) const { state.Begin( AsciiId<'B','R','4'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( resetSwitch ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } } } nestopia-1.51.1/source/core/board/NstBoardBmcResetBased4in1.hpp000066400000000000000000000030561411157722000242510ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_RESETBASED4IN1_H #define NST_BOARD_BMC_RESETBASED4IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class ResetBased4in1 : public Board { public: explicit ResetBased4in1(const Context& c) : Board(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); uint resetSwitch; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcSuper22Games.cpp000066400000000000000000000106541411157722000237500ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "../NstDipSwitches.hpp" #include "NstBoardBmcSuper22Games.hpp" #include "../NstCrc32.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif class Super22Games::CartSwitches : public DipSwitches { enum Type { SUPER_X_GAMES = 0, SUPER_22_GAMES = 0xB27414ED }; uint hiPrg; const Type type; explicit CartSwitches(Type t) : hiPrg(0x00), type(t) {} public: static CartSwitches* Create(const Context& c) { if (c.prg.Size() == SIZE_1024K) return new CartSwitches( Crc32::Compute(c.prg.Mem(),c.prg.Size()) == SUPER_22_GAMES ? SUPER_22_GAMES : SUPER_X_GAMES ); else return NULL; } void EnableHiPrg(bool enable) { hiPrg = enable ? 0x20 : 0x00; } uint GetHiPrg() const { return hiPrg; } private: uint GetValue(uint) const { return hiPrg ? 1 : 0; } void SetValue(uint,uint value) { hiPrg = value ? 0x20 : 0x00; } uint NumDips() const { return 1; } uint NumValues(uint) const { return 2; } cstring GetDipName(uint) const { return "Mode"; } cstring GetValueName(uint,uint i) const { return i ? (type == SUPER_22_GAMES ? "20-in-1" : "2") : (type == SUPER_22_GAMES ? "22-in-1" : "1"); } }; Super22Games::Super22Games(const Context& c) : Board(c), cartSwitches(CartSwitches::Create(c)) {} Super22Games::~Super22Games() { delete cartSwitches; } Super22Games::Device Super22Games::QueryDevice(DeviceType type) { if (type == DEVICE_DIP_SWITCHES) return cartSwitches; else return Board::QueryDevice( type ); } void Super22Games::SubReset(bool) { Map( 0x8000U, 0xFFFFU, &Super22Games::Poke_8000 ); NES_DO_POKE(8000,0x8000,0x00); } void Super22Games::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'B','2','2'>::V) ); if (baseChunk == AsciiId<'B','2','2'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { NST_VERIFY( cartSwitches ); if (cartSwitches) cartSwitches->EnableHiPrg( state.Read8() & 0x1 ); } state.End(); } } } void Super22Games::SubSave(State::Saver& state) const { if (cartSwitches) state.Begin( AsciiId<'B','2','2'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( cartSwitches->GetHiPrg() ? 0x1 : 0x0 ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Super22Games,8000) { const uint hiPrg = cartSwitches ? cartSwitches->GetHiPrg() : 0x00; if (data & 0x20) prg.SwapBanks( hiPrg | (data & 0x1F), hiPrg | (data & 0x1F) ); else prg.SwapBank( (hiPrg >> 1) | (data >> 1 & 0xF) ); static const byte lut[4][4] = { {0,0,0,0}, {0,1,0,1}, {0,0,1,1}, {1,1,1,1} }; ppu.SetMirroring( lut[data >> 6] ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcSuper22Games.hpp000066400000000000000000000032331411157722000237500ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_SUPER22GAMES_H #define NST_BOARD_BMC_SUPER22GAMES_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class Super22Games : public Board { public: explicit Super22Games(const Context&); private: ~Super22Games(); class CartSwitches; void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); Device QueryDevice(DeviceType); NES_DECL_POKE( 8000 ); CartSwitches* const cartSwitches; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcSuper24in1.cpp000066400000000000000000000066131411157722000234050ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardBmcSuper24in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Super24in1::SubReset(const bool hard) { if (hard) { exRegs[0] = 0x24; exRegs[1] = 0x9F; exRegs[2] = 0x00; } Mmc3::SubReset( hard ); Map( 0x5FF0U, &Super24in1::Poke_5FF0 ); Map( 0x5FF1U, &Super24in1::Poke_5FF1 ); Map( 0x5FF2U, &Super24in1::Poke_5FF2 ); } void Super24in1::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'B','2','4'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<3> data( state ); exRegs[0] = data[0]; exRegs[1] = data[1]; exRegs[2] = data[2]; } state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void Super24in1::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); const byte data[3] = { exRegs[0], exRegs[1], exRegs[2] }; state.Begin( AsciiId<'B','2','4'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Super24in1,5FF0) { if (exRegs[0] != data) { exRegs[0] = data; Mmc3::UpdateChr(); Mmc3::UpdatePrg(); } } NES_POKE_D(Super24in1,5FF1) { if (exRegs[1] != data) { exRegs[1] = data; Mmc3::UpdatePrg(); } } NES_POKE_D(Super24in1,5FF2) { if (exRegs[2] != data) { exRegs[2] = data; Mmc3::UpdateChr(); } } void NST_FASTCALL Super24in1::UpdatePrg(uint address,uint bank) { static const byte masks[8] = {0x3F,0x1F,0xF,0x1,0x3,0x0,0x0,0x0}; prg.SwapBank( address, (exRegs[1] << 1) | (bank & masks[exRegs[0] & 0x7]) ); } void NST_FASTCALL Super24in1::UpdateChr(uint address,uint bank) const { chr.Source( exRegs[0] >> 5 & 0x1 ).SwapBank( address, (exRegs[2] << 3 & 0xF00) | bank ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcSuper24in1.hpp000066400000000000000000000035131411157722000234060ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_SUPER24IN1_H #define NST_BOARD_BMC_SUPER24IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class Super24in1 : public Mmc3 { public: explicit Super24in1(const Context& c) : Mmc3(c) {} private: void SubReset(bool); void SubLoad(State::Loader&,dword); void SubSave(State::Saver&) const; void NST_FASTCALL UpdatePrg(uint,uint); void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_POKE( 5FF0 ); NES_DECL_POKE( 5FF1 ); NES_DECL_POKE( 5FF2 ); NES_DECL_POKE( C000 ); NES_DECL_POKE( C001 ); NES_DECL_POKE( E000 ); NES_DECL_POKE( E001 ); uint exRegs[3]; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcSuper40in1.cpp000066400000000000000000000051241411157722000233770ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmcSuper40in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Super40in1::SubReset(const bool hard) { reg = 0x00; for (uint i=0x6000; i < 0x7000; i += 0x2) { Map( i + 0x0, &Super40in1::Poke_6000 ); Map( i + 0x1, &Super40in1::Poke_6001 ); } if (hard) NES_DO_POKE(6000,0x6000,0x00); } void Super40in1::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'B','S','4'>::V) ); if (baseChunk == AsciiId<'B','S','4'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) reg = state.Read8() & 0x20; state.End(); } } } void Super40in1::SubSave(State::Saver& state) const { state.Begin( AsciiId<'B','S','4'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( reg ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Super40in1,6000) { if (!reg) { reg = data & 0x20; prg.SwapBanks( data & ~(~data >> 3 & 0x1), data | (~data >> 3 & 0x1) ); ppu.SetMirroring( (data & 0x10) ? Ppu::NMT_H : Ppu::NMT_V ); } } NES_POKE_D(Super40in1,6001) { if (!reg) { ppu.Update(); chr.SwapBank( data ); } } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcSuper40in1.hpp000066400000000000000000000031221411157722000234000ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_SUPER40IN1_H #define NST_BOARD_BMC_SUPER40IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class Super40in1 : public Board { public: explicit Super40in1(const Context& c) : Board(c) {} private: void SubReset(bool); void SubLoad(State::Loader&,dword); void SubSave(State::Saver&) const; NES_DECL_POKE( 6000 ); NES_DECL_POKE( 6001 ); uint reg; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcSuper700in1.cpp000066400000000000000000000035541411157722000234670ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmcSuper700in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Super700in1::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &Super700in1::Poke_8000 ); if (hard) NES_DO_POKE(8000,0x8000,0x00); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(Super700in1,8000) { ppu.SetMirroring( (address & 0x80) ? Ppu::NMT_H : Ppu::NMT_V ); chr.SwapBank( (address << 2) | (data & 0x3) ); data = (address & 0x40) | (address >> 8 & 0x3F); address = ~address >> 6 & 0x1; prg.SwapBanks( data & ~address, data | address ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcSuper700in1.hpp000066400000000000000000000027241411157722000234720ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_SUPER700IN1_H #define NST_BOARD_BMC_SUPER700IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class Super700in1 : public Board { public: explicit Super700in1(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcSuperBig7in1.cpp000066400000000000000000000054171411157722000237510ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardBmcSuperBig7in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void SuperBig7in1::SubReset(const bool hard) { if (hard) exReg = 0; Mmc3::SubReset( hard ); for (uint i=0xA001; i < 0xC000; i += 0x2) Map( i, &SuperBig7in1::Poke_A001 ); } void SuperBig7in1::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'B','S','B'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { exReg = state.Read8(); exReg = NST_MIN(exReg & 7,6); } state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void SuperBig7in1::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); state.Begin( AsciiId<'B','S','B'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( exReg ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(SuperBig7in1,A001) { data &= 0x7; if (exReg != data) { exReg = data; Mmc3::UpdatePrg(); Mmc3::UpdateChr(); } } void NST_FASTCALL SuperBig7in1::UpdatePrg(uint address,uint bank) { prg.SwapBank( address, (exReg << 4) | (bank & (exReg >= 6 ? 0x1F : 0x0F)) ); } void NST_FASTCALL SuperBig7in1::UpdateChr(uint address,uint bank) const { chr.SwapBank( address, (exReg << 7) | (bank & (exReg >= 6 ? 0xFF : 0x7F)) ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcSuperBig7in1.hpp000066400000000000000000000032411411157722000237470ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_SUPERBIG7IN1_H #define NST_BOARD_BMC_SUPERBIG7IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class SuperBig7in1 : public Mmc3 { public: explicit SuperBig7in1(const Context& c) : Mmc3(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void NST_FASTCALL UpdatePrg(uint,uint); void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_POKE( A001 ); uint exReg; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcSuperGun20in1.cpp000066400000000000000000000033041411157722000240450ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmcSuperGun20in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void SuperGun20in1::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &SuperGun20in1::Poke_8000 ); if (hard) NES_DO_POKE(8000,0x8000,0x00); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_A(SuperGun20in1,8000) { ppu.Update(); prg.SwapBanks( address >> 2, address >> 2 ); chr.SwapBank( address ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcSuperGun20in1.hpp000066400000000000000000000027341411157722000240600ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_SUPERGUN20IN1_H #define NST_BOARD_BMC_SUPERGUN20IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class SuperGun20in1 : public Board { public: explicit SuperGun20in1(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcSuperHiK300in1.cpp000066400000000000000000000040241411157722000240500ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmcSuperHiK300in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void SuperHiK300in1::SubReset(const bool hard) { Map( 0x8000U, 0xBFFFU, &SuperHiK300in1::Poke_8000 ); Map( 0xC000U, 0xFFFFU, &SuperHiK300in1::Poke_C000 ); if (hard) NES_DO_POKE(C000,0xFFFF,0x00); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void SuperHiK300in1::SwapGfx(const uint address) const { ppu.SetMirroring( (address & 0x8) ? Ppu::NMT_H : Ppu::NMT_V ); chr.SwapBank( address ); } NES_POKE_A(SuperHiK300in1,8000) { prg.SwapBanks( address, address ); SwapGfx( address ); } NES_POKE_A(SuperHiK300in1,C000) { prg.SwapBank( address >> 1 ); SwapGfx( address ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcSuperHiK300in1.hpp000066400000000000000000000030351411157722000240560ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_SUPERHIK300IN1_H #define NST_BOARD_BMC_SUPERHIK300IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class SuperHiK300in1 : public Board { public: explicit SuperHiK300in1(const Context& c) : Board(c) {} private: void SubReset(bool); void SwapGfx(uint) const; NES_DECL_POKE( 8000 ); NES_DECL_POKE( C000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcSuperHiK4in1.cpp000066400000000000000000000055411411157722000237160ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardBmcSuperHiK4in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void SuperHiK4in1::SubReset(const bool hard) { if (hard) exReg = 0x00; Mmc3::SubReset( hard ); Map( 0x6000U, 0x7FFFU, &SuperHiK4in1::Poke_6000 ); prg.SwapBank( 0 ); } void SuperHiK4in1::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'B','H','4'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) exReg = state.Read8(); state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void SuperHiK4in1::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); state.Begin( AsciiId<'B','H','4'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( exReg ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(SuperHiK4in1,6000) { if (regs.ctrl1 & 0x80) { if (exReg != data) { exReg = data; if (exReg & 0x1) Mmc3::UpdatePrg(); else prg.SwapBank( exReg >> 4 & 0x3 ); Mmc3::UpdateChr(); } } } void NST_FASTCALL SuperHiK4in1::UpdatePrg(uint address,uint bank) { if (exReg & 0x1) prg.SwapBank( address, (exReg >> 2 & 0x30) | (bank & 0x0F) ); } void NST_FASTCALL SuperHiK4in1::UpdateChr(uint address,uint bank) const { chr.SwapBank( address, (exReg << 1 & 0x180) | (bank & 0x7F) ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcSuperHiK4in1.hpp000066400000000000000000000032411411157722000237160ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_SUPERHIK4IN1_H #define NST_BOARD_BMC_SUPERHIK4IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class SuperHiK4in1 : public Mmc3 { public: explicit SuperHiK4in1(const Context& c) : Mmc3(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void NST_FASTCALL UpdatePrg(uint,uint); void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_POKE( 6000 ); uint exReg; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcSuperVision16in1.cpp000066400000000000000000000066151411157722000246000ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmcSuperVision16in1.hpp" #include "../NstCrc32.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif SuperVision16in1::SuperVision16in1(const Context& c) : Board (c), epromFirst (c.prg.Size() >= SIZE_32K && Crc32::Compute(c.prg.Mem(),SIZE_32K) == EPROM_CRC) { } void SuperVision16in1::SubReset(const bool hard) { if (hard) { regs[0] = 0; regs[1] = 0; UpdatePrg(); } Map( 0x6000U, 0x7FFFU, &SuperVision16in1::Peek_6000, &SuperVision16in1::Poke_6000 ); Map( 0x8000U, 0xFFFFU, &SuperVision16in1::Poke_8000 ); } void SuperVision16in1::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'B','S','V'>::V) ); if (baseChunk == AsciiId<'B','S','V'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { { State::Loader::Data<2> data( state ); regs[0] = data[0]; regs[1] = data[1]; } UpdatePrg(); } state.End(); } } } void SuperVision16in1::SubSave(State::Saver& state) const { state.Begin( AsciiId<'B','S','V'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write16( regs[0] | uint(regs[1]) << 8 ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void SuperVision16in1::UpdatePrg() { const uint r = regs[0] << 3 & 0x78; wrk.SwapBank ( (r << 1 | 0xF) + (epromFirst ? 0x4 : 0x0) ); prg.SwapBanks ( (regs[0] & 0x10) ? (r | (regs[1] & 0x7)) + (epromFirst ? 0x2 : 0x0) : epromFirst ? 0x00 : 0x80, (regs[0] & 0x10) ? (r | (0xFF & 0x7)) + (epromFirst ? 0x2 : 0x0) : epromFirst ? 0x01 : 0x81 ); } NES_PEEK_A(SuperVision16in1,6000) { return wrk[0][address - 0x6000]; } NES_POKE_D(SuperVision16in1,6000) { regs[0] = data; UpdatePrg(); ppu.SetMirroring( (data & 0x20) ? Ppu::NMT_H : Ppu::NMT_V ); } NES_POKE_D(SuperVision16in1,8000) { regs[1] = data; UpdatePrg(); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcSuperVision16in1.hpp000066400000000000000000000033501411157722000245760ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_SUPERVISION16IN1_H #define NST_BOARD_BMC_SUPERVISION16IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class SuperVision16in1 : public Board { public: explicit SuperVision16in1(const Context&); private: enum { EPROM_CRC = 0x63794E25 }; void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void UpdatePrg(); NES_DECL_PEEK( 6000 ); NES_DECL_POKE( 6000 ); NES_DECL_POKE( 8000 ); uint regs[2]; const ibool epromFirst; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcT262.cpp000066400000000000000000000050001411157722000221530ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmcT262.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void T262::SubReset(bool) { Map( 0x8000U, 0xFFFFU, &T262::Poke_8000 ); mode = false; NES_DO_POKE(8000,0x8001,0x00); mode = false; } void T262::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'B','T','6'>::V) ); if (baseChunk == AsciiId<'B','T','6'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) mode = state.Read8() & 0x1; state.End(); } } } void T262::SubSave(State::Saver& state) const { state.Begin( AsciiId<'B','T','6'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( mode ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(T262,8000) { if (mode || address == 0x8000) { prg.SwapBank( (prg.GetBank() & 0x38) | (data & 0x07) ); } else { mode = true; data = (address >> 3 & 0x20) | (address >> 2 & 0x18); prg.SwapBanks( data | (prg.GetBank() & 0x07), data | 0x07 ); ppu.SetMirroring( (address & 0x2) ? Ppu::NMT_H : Ppu::NMT_V ); } } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcT262.hpp000066400000000000000000000030371411157722000221700ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_T262_H #define NST_BOARD_BMC_T262_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class T262 : public Board { public: explicit T262(const Context& c) : Board(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); NES_DECL_POKE( 8000 ); ibool mode; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcVrc4.cpp000066400000000000000000000043161411157722000223450ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "../NstTimer.hpp" #include "NstBoardBmcVrc4.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Vrc4::SubReset(const bool hard) { Konami::Vrc4::SubReset( hard ); Map( 0x8000U, 0x8FFFU, &Vrc4::Poke_8000 ); Map( 0xA000U, 0xAFFFU, &Vrc4::Poke_A000 ); Map( 0xB000U, 0xEFFFU, &Vrc4::Poke_B000 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Vrc4,8000) { prg.SwapBank( prgSwap << 13, (prg.GetBank() & 0x20) | (data & 0x1F) ); } NES_POKE_D(Vrc4,A000) { prg.SwapBank( (prg.GetBank() & 0x20) | (data & 0x1F) ); } NES_POKE_D(Vrc4,B000) { data = data << 2 & 0x20; prg.SwapBanks ( data | (prg.GetBank() & 0x1F), data | (prg.GetBank() & 0x1F), data | (prg.GetBank() & 0x1F), data | (prg.GetBank() & 0x1F) ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcVrc4.hpp000066400000000000000000000030451411157722000223500ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_VRC4_H #define NST_BOARD_BMC_VRC4_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardKonamiVrc4.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { class Vrc4 : public Konami::Vrc4 { public: explicit Vrc4(const Context& c) : Konami::Vrc4(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); NES_DECL_POKE( A000 ); NES_DECL_POKE( B000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcVt5201.cpp000066400000000000000000000117261411157722000224330ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "../NstDipSwitches.hpp" #include "NstBoardBmcVt5201.hpp" #include "../NstCrc32.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Vt5201::CartSwitches::CartSwitches(const Context& c) : mode(0), type(DetectType(c)) {} Vt5201::CartSwitches::Type Vt5201::CartSwitches::DetectType(const Context& c) { switch (const dword crc = Crc32::Compute(c.prg.Mem(),c.prg.Size())) { case VT5201_6IN1: case VT5201_12IN1: case VT5201_28IN1: case VT5201_54IN1: case VT5201_55IN1: case VT5201_65IN1: return static_cast(crc); } return VT5201_XIN1; } void Vt5201::CartSwitches::SetMode(uint value) { mode = value; } uint Vt5201::CartSwitches::GetMode() const { return mode; } uint Vt5201::CartSwitches::GetValue(uint) const { return mode; } void Vt5201::CartSwitches::SetValue(uint,uint value) { mode = value; } uint Vt5201::CartSwitches::NumDips() const { return 1; } uint Vt5201::CartSwitches::NumValues(uint) const { return 4; } cstring Vt5201::CartSwitches::GetDipName(uint) const { return "Mode"; } cstring Vt5201::CartSwitches::GetValueName(uint,uint i) const { static cstring const names[7][4] = { { "1", "2", "3", "4" }, { "6-in-1", "15-in-1", "35-in-1", "43-in-1" }, { "12-in-1", "66-in-1", "77-in-1", "88-in-1" }, { "28-in-1", "46-in-1", "63-in-1", "118-in-1" }, { "54-in-1", "64-in-1", "74-in-1", "84-in-1" }, { "55-in-1", "65-in-1", "75-in-1", "85-in-1" }, { "65-in-1", "75-in-1", "85-in-1", "95-in-1" } }; uint id = 0; switch (type) { case VT5201_6IN1: id = 1; break; case VT5201_12IN1: id = 2; break; case VT5201_28IN1: id = 3; break; case VT5201_54IN1: id = 4; break; case VT5201_55IN1: id = 5; break; case VT5201_65IN1: id = 6; break; case VT5201_XIN1: default: break; } return names[id][i]; } Vt5201::Vt5201(const Context& c) : Board(c), cartSwitches(c) {} Vt5201::Device Vt5201::QueryDevice(DeviceType type) { if (type == DEVICE_DIP_SWITCHES) return &cartSwitches; else return Board::QueryDevice( type ); } void Vt5201::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &Vt5201::Peek_8000, &Vt5201::Poke_8000 ); if (hard) NES_DO_POKE(8000,0x8000,0x00); } void Vt5201::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'B','V','T'>::V) ); if (baseChunk == AsciiId<'B','V','T'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { const uint data = state.Read8(); cartMode = data << 1 & 0x100; cartSwitches.SetMode( data & 0x3 ); } state.End(); } } } void Vt5201::SubSave(State::Saver& state) const { state.Begin( AsciiId<'B','V','T'>::V ) .Begin( AsciiId<'R','E','G'>::V ).Write8( cartSwitches.GetMode() | cartMode >> 1 ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(Vt5201,8000) { return !cartMode ? prg.Peek( address - 0x8000 ) : cartSwitches.GetMode(); } NES_POKE_A(Vt5201,8000) { cartMode = address & 0x100; ppu.SetMirroring( (address & 0x8) ? Ppu::NMT_H : Ppu::NMT_V ); prg.SwapBanks( (address >> 4) & ~(~address >> 7 & 0x1), (address >> 4) | (~address >> 7 & 0x1) ); chr.SwapBank( address ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcVt5201.hpp000066400000000000000000000046131411157722000224350ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BMC_VT5201_H #define NST_BOARD_BMC_VT5201_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class Vt5201 : public Board { public: explicit Vt5201(const Context&); private: class CartSwitches : public DipSwitches { enum Type { VT5201_XIN1 = 0, VT5201_6IN1 = 0x766130C4, VT5201_12IN1 = 0xBA6A6F73, VT5201_28IN1 = 0x7A423007, VT5201_54IN1 = 0x2B81E99F, VT5201_55IN1 = 0x4978BA70, VT5201_65IN1 = 0x487F8A54 }; uint mode; const Type type; public: explicit CartSwitches(const Context&); void SetMode(uint); uint GetMode() const; private: static Type DetectType(const Context&); uint GetValue(uint) const; void SetValue(uint,uint); uint NumDips() const; uint NumValues(uint) const; cstring GetDipName(uint) const; cstring GetValueName(uint,uint) const; }; void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); Device QueryDevice(DeviceType); NES_DECL_PEEK( 8000 ); NES_DECL_POKE( 8000 ); uint cartMode; CartSwitches cartSwitches; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBmcY2k64in1.cpp000066400000000000000000000055161411157722000227610ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBmcY2k64in1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Bmc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Y2k64in1::SubReset(bool) { Map( 0x5000U, 0x5003U, &Y2k64in1::Poke_5000 ); Map( 0x8000U, 0xFFFFU, &Y2k64in1::Poke_8000 ); regs[0] = 0x80; regs[1] = 0x43; regs[2] = 0x00; regs[3] = 0x00; Update(); } void Y2k64in1::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'B','Y','2'>::V) ); if (baseChunk == AsciiId<'B','Y','2'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) state.Read( regs ); state.End(); } } } void Y2k64in1::SubSave(State::Saver& state) const { state.Begin(AsciiId<'B','Y','2'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( regs ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Y2k64in1::Update() { uint bank = regs[1] & 0x1FU; if (regs[0] & 0x80U & regs[1]) { prg.SwapBank( bank ); } else { bank = (bank << 1) | (regs[1] >> 6 & 0x1U); prg.SwapBank( bank ); if (regs[0] & 0x80U) prg.SwapBank( bank ); } ppu.SetMirroring( (regs[0] & 0x20U) ? Ppu::NMT_H : Ppu::NMT_V ); chr.SwapBank( (regs[2] << 2) | (regs[0] >> 1 & 0x3U) ); } NES_POKE_AD(Y2k64in1,5000) { regs[address & 0x3] = data; Update(); } NES_POKE_D(Y2k64in1,8000) { regs[3] = data; Update(); } } } } } nestopia-1.51.1/source/core/board/NstBoardBmcY2k64in1.hpp000066400000000000000000000031451411157722000227620ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARDS_BMC_Y2K64IN1_H #define NST_BOARDS_BMC_Y2K64IN1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Bmc { class Y2k64in1 : public Board { public: explicit Y2k64in1(const Context& c) : Board(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Update(); NES_DECL_POKE( 5000 ); NES_DECL_POKE( 8000 ); byte regs[4]; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBtl2708.cpp000066400000000000000000000063571411157722000221560ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBtl2708.hpp" namespace Nes { namespace Core { namespace Boards { namespace Btl { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void B2708::SubReset(const bool hard) { if (hard) { mode = 0; wrk.Source(1).SwapBank( 0 ); prg.SwapBank( ~0U ); } Map( 0x6000U, 0x7FFFU, &B2708::Peek_6000, &B2708::Poke_6000 ); Map( 0x8000U, 0x8FFFU, &B2708::Poke_8000 ); Map( 0xB800U, 0xBFFFU, &B2708::Peek_B800, &B2708::Poke_B800 ); Map( 0xC000U, 0xD7FFU, &B2708::Peek_C000, &B2708::Poke_B800 ); Map( 0xE000U, 0xEFFFU, &B2708::Poke_E000 ); Map( 0xF000U, 0xFFFFU, &B2708::Poke_F000 ); } void B2708::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( (baseChunk == AsciiId<'2','7','8'>::V) ); if (baseChunk == AsciiId<'2','7','8'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) mode = state.Read8() & 0x10; state.End(); } } } void B2708::SubSave(State::Saver& state) const { state.Begin( AsciiId<'2','7','8'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( mode ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(B2708,6000) { return mode ? wrk[0][address - 0x6000] : wrk.Source()[address - 0x6000]; } NES_POKE_AD(B2708,6000) { wrk.Source()[address - 0x6000] = data; } NES_POKE_D(B2708,8000) { wrk.Source(1).SwapBank( data & 0xF ); } NES_PEEK_A(B2708,B800) { return mode ? prg[1][address - 0xA000] : wrk.Source()[address - 0x9800]; } NES_POKE_AD(B2708,B800) { wrk.Source()[address - 0x9800] = data; } NES_PEEK_A(B2708,C000) { return mode ? prg[2][address - 0xC000] : wrk.Source()[address - 0x9800]; } NES_POKE_D(B2708,E000) { ppu.SetMirroring( (data & 0x8) ? Ppu::NMT_H : Ppu::NMT_V ); } NES_POKE_D(B2708,F000) { mode = data & 0x10; } } } } } nestopia-1.51.1/source/core/board/NstBoardBtl2708.hpp000066400000000000000000000033141411157722000221510ustar00rootroot00000000000000/////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BTL_B2708_H #define NST_BOARD_BTL_B2708_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Btl { class B2708 : public Board { public: explicit B2708(const Context& c) : Board(c) {} private: void SubReset(bool); void SubLoad(State::Loader&,dword); void SubSave(State::Saver&) const; NES_DECL_PEEK( 6000 ); NES_DECL_POKE( 6000 ); NES_DECL_POKE( 8000 ); NES_DECL_PEEK( B800 ); NES_DECL_POKE( B800 ); NES_DECL_PEEK( C000 ); NES_DECL_POKE( E000 ); NES_DECL_POKE( F000 ); uint mode; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBtl6035052.cpp000066400000000000000000000044541411157722000223760ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardBtl6035052.hpp" namespace Nes { namespace Core { namespace Boards { namespace Btl { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void B6035052::SubReset(const bool hard) { security = 0x0; Mmc3::SubReset( hard ); Map( 0x4020U, 0x7FFFU, &B6035052::Peek_4020, &B6035052::Poke_4020 ); } void B6035052::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'B','6','0'>::V) ); if (baseChunk == AsciiId<'B','6','0'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) security = state.Read8() & 0x3; state.End(); } } } void B6035052::SubSave(State::Saver& state) const { state.Begin( AsciiId<'B','6','0'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( security ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK(B6035052,4020) { return security; } NES_POKE_D(B6035052,4020) { security = data & 0x3; if (security == 0x1) security = 0x2; } } } } } nestopia-1.51.1/source/core/board/NstBoardBtl6035052.hpp000066400000000000000000000031131411157722000223720ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BTL_6035052_H #define NST_BOARD_BTL_6035052_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Btl { class B6035052 : public Mmc3 { public: explicit B6035052(const Context& c) : Mmc3(c) {} private: void SubReset(bool); void SubLoad(State::Loader&,dword); void SubSave(State::Saver&) const; NES_DECL_PEEK( 4020 ); NES_DECL_POKE( 4020 ); uint security; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBtlAx5705.cpp000066400000000000000000000075611411157722000224450ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBtlAx5705.hpp" namespace Nes { namespace Core { namespace Boards { namespace Btl { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Ax5705::SubReset(bool) { for (uint i=0x0000; i < 0x1000; i += 0x10) { Map( i + 0x8000, &Ax5705::Poke_8000 ); Map( i + 0x8008, NMT_SWAP_HV ); Map( i + 0xA000, &Ax5705::Poke_8000 ); Map( i + 0xA008, &Ax5705::Poke_A008 ); Map( i + 0xA009, &Ax5705::Poke_A009 ); Map( i + 0xA00A, &Ax5705::Poke_A00A ); Map( i + 0xA00B, &Ax5705::Poke_A00B ); Map( i + 0xC000, &Ax5705::Poke_C000 ); Map( i + 0xC001, &Ax5705::Poke_C001 ); Map( i + 0xC002, &Ax5705::Poke_C002 ); Map( i + 0xC003, &Ax5705::Poke_C003 ); Map( i + 0xC008, &Ax5705::Poke_C008 ); Map( i + 0xC009, &Ax5705::Poke_C009 ); Map( i + 0xC00A, &Ax5705::Poke_C00A ); Map( i + 0xC00B, &Ax5705::Poke_C00B ); Map( i + 0xE000, &Ax5705::Poke_E000 ); Map( i + 0xE001, &Ax5705::Poke_E001 ); Map( i + 0xE002, &Ax5705::Poke_E002 ); Map( i + 0xE003, &Ax5705::Poke_E003 ); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(Ax5705,8000) { prg.SwapBank( address & 0x2000, (data << 2 & 0x8) | (data & 0x5) | (data >> 2 & 0x2) ); } void Ax5705::SwapChr(uint address,uint data) const { ppu.Update(); chr.SwapBank( address, data ); } void Ax5705::SwapChrLo(uint address,uint data) const { SwapChr( address, (data & 0x0F) | (chr.GetBank(address) & 0xF0) ); } void Ax5705::SwapChrHi(uint address,uint data) const { SwapChr( address, (chr.GetBank(address) & 0x0F) | (data << 3 & 0x20) | (data << 5 & 0x40) | (data << 4 & 0x90) ); } NES_POKE_D(Ax5705,A008) { SwapChrLo( 0x0000, data ); } NES_POKE_D(Ax5705,A009) { SwapChrHi( 0x0000, data ); } NES_POKE_D(Ax5705,A00A) { SwapChrLo( 0x0400, data ); } NES_POKE_D(Ax5705,A00B) { SwapChrHi( 0x0400, data ); } NES_POKE_D(Ax5705,C000) { SwapChrLo( 0x0800, data ); } NES_POKE_D(Ax5705,C001) { SwapChrHi( 0x0800, data ); } NES_POKE_D(Ax5705,C002) { SwapChrLo( 0x0C00, data ); } NES_POKE_D(Ax5705,C003) { SwapChrHi( 0x0C00, data ); } NES_POKE_D(Ax5705,C008) { SwapChrLo( 0x1000, data ); } NES_POKE_D(Ax5705,C009) { SwapChrHi( 0x1000, data ); } NES_POKE_D(Ax5705,C00A) { SwapChrLo( 0x1400, data ); } NES_POKE_D(Ax5705,C00B) { SwapChrHi( 0x1400, data ); } NES_POKE_D(Ax5705,E000) { SwapChrLo( 0x1800, data ); } NES_POKE_D(Ax5705,E001) { SwapChrHi( 0x1800, data ); } NES_POKE_D(Ax5705,E002) { SwapChrLo( 0x1C00, data ); } NES_POKE_D(Ax5705,E003) { SwapChrHi( 0x1C00, data ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBtlAx5705.hpp000066400000000000000000000040031411157722000224360ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BTL_AX5705_H #define NST_BOARD_BTL_AX5705_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Btl { class Ax5705 : public Board { public: explicit Ax5705(const Context& c) : Board(c) {} private: void SubReset(bool); void SwapChr(uint,uint) const; void SwapChrLo(uint,uint) const; void SwapChrHi(uint,uint) const; NES_DECL_POKE( 8000 ); NES_DECL_POKE( A008 ); NES_DECL_POKE( A009 ); NES_DECL_POKE( A00A ); NES_DECL_POKE( A00B ); NES_DECL_POKE( C000 ); NES_DECL_POKE( C001 ); NES_DECL_POKE( C002 ); NES_DECL_POKE( C003 ); NES_DECL_POKE( C008 ); NES_DECL_POKE( C009 ); NES_DECL_POKE( C00A ); NES_DECL_POKE( C00B ); NES_DECL_POKE( E000 ); NES_DECL_POKE( E001 ); NES_DECL_POKE( E002 ); NES_DECL_POKE( E003 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBtlDragonNinja.cpp000066400000000000000000000062501411157722000237400ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstTimer.hpp" #include "NstBoard.hpp" #include "NstBoardBtlDragonNinja.hpp" namespace Nes { namespace Core { namespace Boards { namespace Btl { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif DragonNinja::DragonNinja(const Context& c) : Board(c), irq(*c.cpu,*c.ppu) {} void DragonNinja::Irq::Reset(bool) { count = 0; } void DragonNinja::SubReset(bool) { irq.Reset( true ); for (uint i=0x0000; i < 0x1000; i += 0x4) { Map( 0x8000 + i, PRG_SWAP_8K_0 ); Map( 0x9000 + i, NMT_SWAP_HV ); Map( 0xA000 + i, PRG_SWAP_8K_1 ); Map( 0xB000 + i, CHR_SWAP_1K_0 ); Map( 0xB002 + i, CHR_SWAP_1K_1 ); Map( 0xC000 + i, CHR_SWAP_1K_2 ); Map( 0xC002 + i, CHR_SWAP_1K_3 ); Map( 0xD000 + i, CHR_SWAP_1K_4 ); Map( 0xD002 + i, CHR_SWAP_1K_5 ); Map( 0xE000 + i, CHR_SWAP_1K_6 ); Map( 0xE002 + i, CHR_SWAP_1K_7 ); Map( 0xF000 + i, &DragonNinja::Poke_F000 ); } } void DragonNinja::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'B','D','N'>::V) ); if (baseChunk == AsciiId<'B','D','N'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'I','R','Q'>::V) irq.unit.count = state.Read8(); state.End(); } } } void DragonNinja::SubSave(State::Saver& state) const { state.Begin( AsciiId<'B','D','N'>::V ).Begin( AsciiId<'I','R','Q'>::V ).Write8( irq.unit.count ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif bool DragonNinja::Irq::Clock() { if (!count || ++count < 240) return false; count = 0; return true; } NES_POKE_D(DragonNinja,F000) { irq.Update(); irq.ClearIRQ(); irq.unit.count = data; } void DragonNinja::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBtlDragonNinja.hpp000066400000000000000000000034171411157722000237470ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BTL_DRAGONNINJA_H #define NST_BOARD_BTL_DRAGONNINJA_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Btl { class DragonNinja : public Board { public: explicit DragonNinja(const Context&); private: void SubReset(bool); void SubLoad(State::Loader&,dword); void SubSave(State::Saver&) const; void Sync(Event,Input::Controllers*); NES_DECL_POKE( F000 ); struct Irq { void Reset(bool); bool Clock(); enum { CLOCK_FILTER = 16 }; uint count; }; Timer::A12 irq; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBtlGeniusMerioBros.cpp000066400000000000000000000036271411157722000246270ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBtlGeniusMerioBros.hpp" namespace Nes { namespace Core { namespace Boards { namespace Btl { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void GeniusMerioBros::SubReset(const bool hard) { Map( 0x6000U, 0x6FFFU, &GeniusMerioBros::Peek_6000 ); Map( 0x7000U, 0x7FFFU, &GeniusMerioBros::Peek_7000, &GeniusMerioBros::Poke_7000 ); if (hard) prg.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(GeniusMerioBros,6000) { return *prg.Source().Mem(0x8000 + (address & 0x7FF)); } NES_PEEK_A(GeniusMerioBros,7000) { return wrk[0][address & 0x7FF]; } NES_POKE_AD(GeniusMerioBros,7000) { wrk[0][address & 0x7FF] = data; } } } } } nestopia-1.51.1/source/core/board/NstBoardBtlGeniusMerioBros.hpp000066400000000000000000000030361411157722000246260ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BTL_GENIUSMERIOBROS_H #define NST_BOARD_BTL_GENIUSMERIOBROS_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Btl { class GeniusMerioBros : public Board { public: explicit GeniusMerioBros(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_PEEK( 6000 ); NES_DECL_PEEK( 7000 ); NES_DECL_POKE( 7000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBtlMarioBaby.cpp000066400000000000000000000074011411157722000234120ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstTimer.hpp" #include "NstBoard.hpp" #include "NstBoardBtlMarioBaby.hpp" namespace Nes { namespace Core { namespace Boards { namespace Btl { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif MarioBaby::MarioBaby(const Context& c) : Board(c), irq(*c.cpu,*c.cpu) {} void MarioBaby::Irq::Reset(const bool hard) { if (hard) count = 0; } void MarioBaby::SubReset(const bool hard) { Map( 0x6000U, 0x7FFFU, &MarioBaby::Peek_6000 ); for (uint i=0x0000; i < 0x2000; i += 0x4) { Map( 0x8000 + i, CHR_SWAP_8K ); Map( 0xE000 + i, &MarioBaby::Poke_E000 ); Map( 0xE001 + i, &MarioBaby::Poke_E001 ); Map( 0xE002 + i, &MarioBaby::Poke_E002 ); } irq.Reset( hard, hard ? false : irq.Connected() ); if (hard) prg.SwapBank(~0U); } void MarioBaby::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'B','M','B'>::V) ); if (baseChunk == AsciiId<'B','M','B'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'I','R','Q'>::V) { State::Loader::Data<3> data( state ); irq.Connect( data[0] & 0x1 ); irq.unit.count = data[1] | (data[2] << 8 & 0x7F00); } state.End(); } } } void MarioBaby::SubSave(State::Saver& state) const { const byte data[3] = { irq.Connected() ? 0x1 : 0x0, irq.unit.count >> 0 & 0xFF, irq.unit.count >> 8 & 0x7F }; state.Begin( AsciiId<'B','M','B'>::V ).Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(MarioBaby,6000) { return wrk[0][address - 0x6000]; } NES_POKE_D(MarioBaby,E000) { wrk.SwapBank(data & 0xF); } NES_POKE_D(MarioBaby,E001) { ppu.SetMirroring( (data & 0x8) ? Ppu::NMT_H : Ppu::NMT_V ); } NES_POKE_D(MarioBaby,E002) { irq.Update(); if (!irq.Connect( data & 0x2 )) { irq.unit.count = 0; irq.ClearIRQ(); } } bool MarioBaby::Irq::Clock() { const uint prev = count++; if ((count & 0x6000) != (prev & 0x6000)) { if ((count & 0x6000) == 0x6000) return true; else cpu.ClearIRQ(); } return false; } void MarioBaby::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBtlMarioBaby.hpp000066400000000000000000000035221411157722000234170ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BTL_MARIOBABY_H #define NST_BOARD_BTL_MARIOBABY_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Btl { class MarioBaby : public Board { public: explicit MarioBaby(const Context&); private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Sync(Event,Input::Controllers*); NES_DECL_PEEK( 6000 ); NES_DECL_POKE( E000 ); NES_DECL_POKE( E001 ); NES_DECL_POKE( E002 ); struct Irq { void Reset(bool); bool Clock(); uint count; Cpu& cpu; explicit Irq(Cpu& c) : cpu(c) {} }; Timer::M2 irq; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBtlPikachuY2k.cpp000066400000000000000000000051061411157722000235170ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardBtlPikachuY2k.hpp" namespace Nes { namespace Core { namespace Boards { namespace Btl { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void PikachuY2k::SubReset(const bool hard) { security = ~0U; Mmc3::SubReset( hard ); Map( 0x6000U, 0x7FFFU, &PikachuY2k::Peek_6000, &PikachuY2k::Poke_6000 ); for (uint i=0x8000; i < 0xA000; i += 0x2) Map( i, &PikachuY2k::Poke_8000 ); } void PikachuY2k::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'B','P','2'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) security = (state.Read8() & 0x1) ? ~0U : 0U; state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void PikachuY2k::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); state.Begin( AsciiId<'B','P','2'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( security & 0x1 ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(PikachuY2k,6000) { return wrk[0][address - 0x6000] ^ (regs.ctrl1 & security); } NES_POKE_AD(PikachuY2k,6000) { wrk[0][address - 0x6000] = data; } NES_POKE_AD(PikachuY2k,8000) { security = 0U; Mmc3::NES_DO_POKE(8000,address,data); } } } } } nestopia-1.51.1/source/core/board/NstBoardBtlPikachuY2k.hpp000066400000000000000000000031621411157722000235240ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BTL_PIKACHUY2K_H #define NST_BOARD_BTL_PIKACHUY2K_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Btl { class PikachuY2k : public Mmc3 { public: explicit PikachuY2k(const Context& c) : Mmc3(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); NES_DECL_PEEK( 6000 ); NES_DECL_POKE( 6000 ); NES_DECL_POKE( 8000 ); uint security; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBtlShuiGuanPipe.cpp000066400000000000000000000104201411157722000241010ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "../NstTimer.hpp" #include "NstBoardBtlShuiGuanPipe.hpp" namespace Nes { namespace Core { namespace Boards { namespace Btl { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif ShuiGuanPipe::ShuiGuanPipe(const Context& c) : Board(c), irq(*c.cpu) {} void ShuiGuanPipe::Irq::Reset(const bool hard) { if (hard) { enabled = false; count[0] = 0; count[1] = 0; } } void ShuiGuanPipe::SubReset(const bool hard) { irq.Reset( hard, true ); Map( 0x6000U, 0x7FFFU, &ShuiGuanPipe::Peek_6000 ); for (uint i=0x0000; i < 0x0800; i += 0x10) { Map( 0x8800 + i, 0x8803 + i, PRG_SWAP_8K_0 ); Map( 0x9800 + i, 0x9803 + i, NMT_SWAP_VH01 ); Map( 0xA000 + i, 0xA003 + i, PRG_SWAP_8K_2 ); Map( 0xA800 + i, 0xA803 + i, PRG_SWAP_8K_1 ); } for (uint i=0x000; i < 0x1000; i += 0x10) { Map( 0xB000 + i, 0xE00F + i, &ShuiGuanPipe::Poke_B000 ); Map( 0xF000 + i, 0xF003 + i, &ShuiGuanPipe::Poke_F000 ); Map( 0xF004 + i, 0xF007 + i, &ShuiGuanPipe::Poke_F004 ); Map( 0xF008 + i, 0xF00B + i, &ShuiGuanPipe::Poke_F008 ); } } void ShuiGuanPipe::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'B','S','P'>::V) ); if (baseChunk == AsciiId<'B','S','P'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'I','R','Q'>::V) { State::Loader::Data<2> data( state ); irq.unit.enabled = data[0] & 0x1; irq.unit.count[1] = data[1]; } state.End(); } } } void ShuiGuanPipe::SubSave(State::Saver& state) const { state.Begin( AsciiId<'B','S','P'>::V ).Begin( AsciiId<'I','R','Q'>::V ).Write16( (irq.unit.enabled != false) | (irq.unit.count[1] & 0xFF) << 8 ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif bool ShuiGuanPipe::Irq::Clock() { if (++count[0] < 114) return false; count[0] = 0; return enabled && (++count[1] & 0xFF) == 0; } NES_PEEK_A(ShuiGuanPipe,6000) { return wrk[0][address - 0x6000]; } NES_POKE_AD(ShuiGuanPipe,B000) { ppu.Update(); const uint part = address & 0x4; address = ((address - 0x3000) >> 1 | (address << 7)) & 0x1C00; chr.SwapBank( address, (chr.GetBank(address) & 0xF0 >> part) | (data & 0x0F) << part ); } NES_POKE_D(ShuiGuanPipe,F000) { irq.Update(); irq.unit.count[1] = (irq.unit.count[1] & 0xF0) | (data << 0 & 0x0F); } NES_POKE_D(ShuiGuanPipe,F004) { irq.Update(); irq.unit.count[1] = (irq.unit.count[1] & 0x0F) | (data << 4 & 0xF0); } NES_POKE_D(ShuiGuanPipe,F008) { irq.Update(); irq.unit.enabled = data; if (!data) irq.ClearIRQ(); } void ShuiGuanPipe::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) { irq.VSync(); irq.unit.count[0] = 0; } Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBtlShuiGuanPipe.hpp000066400000000000000000000036261411157722000241200ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BTL_SHUIGUANPIPE_H #define NST_BOARD_BTL_SHUIGUANPIPE_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Btl { class ShuiGuanPipe : public Board { public: explicit ShuiGuanPipe(const Context&); private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void UpdateChr(uint,uint) const; void Sync(Event,Input::Controllers*); NES_DECL_PEEK( 6000 ); NES_DECL_POKE( B000 ); NES_DECL_POKE( F000 ); NES_DECL_POKE( F004 ); NES_DECL_POKE( F008 ); NES_DECL_POKE( F00C ); struct Irq { void Reset(bool); bool Clock(); ibool enabled; uint count[2]; }; Timer::M2 irq; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBtlSmb2a.cpp000066400000000000000000000067471411157722000225250ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstTimer.hpp" #include "NstBoard.hpp" #include "NstBoardBtlSmb2a.hpp" namespace Nes { namespace Core { namespace Boards { namespace Btl { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Smb2a::Smb2a(const Context& c) : Board(c), irq(*c.cpu) {} void Smb2a::SubReset(const bool hard) { if (hard) { wrk.SwapBank( 6 ); prg.SwapBanks( 4, 5, 0, 7 ); } irq.Reset( hard, true ); Map( 0x6000U, 0x7FFFU, &Smb2a::Peek_6000 ); Map( 0x8000U, 0x9FFFU, &Smb2a::Poke_8000 ); Map( 0xA000U, 0xBFFFU, &Smb2a::Poke_A000 ); Map( 0xE000U, 0xFFFFU, PRG_SWAP_8K_2 ); } void Smb2a::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'B','2','A'>::V) ); if (baseChunk == AsciiId<'B','2','A'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'I','R','Q'>::V) { State::Loader::Data<3> data( state ); irq.unit.enabled = data[0] & 0x1U; irq.unit.count = data[1] | (data[2] << 8 & 0xF00); } state.End(); } } } void Smb2a::SubSave(State::Saver& state) const { const byte data[3] = { irq.unit.enabled != 0, irq.unit.count & 0xFF, irq.unit.count >> 8 }; state.Begin( AsciiId<'B','2','A'>::V ).Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Smb2a::Irq::Reset(const bool hard) { if (hard) { enabled = false; count = 0; } } bool Smb2a::Irq::Clock() { if (enabled) { count = (count + 1) & 0xFFF; if (!count) { enabled = false; return true; } } return false; } NES_PEEK_A(Smb2a,6000) { return wrk[0][address - 0x6000]; } NES_POKE(Smb2a,8000) { irq.Update(); irq.unit.enabled = false; irq.unit.count = 0; irq.ClearIRQ(); } NES_POKE(Smb2a,A000) { irq.Update(); irq.unit.enabled = true; } void Smb2a::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBtlSmb2a.hpp000066400000000000000000000033711411157722000225200ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BTL_SMB2A_H #define NST_BOARD_BTL_SMB2A_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Btl { class Smb2a : public Board { public: explicit Smb2a(const Context&); private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Sync(Event,Input::Controllers*); NES_DECL_PEEK( 6000 ); NES_DECL_POKE( 8000 ); NES_DECL_POKE( A000 ); struct Irq { void Reset(bool); bool Clock(); ibool enabled; uint count; }; Timer::M2 irq; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBtlSmb2b.cpp000066400000000000000000000066261411157722000225220ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstTimer.hpp" #include "NstBoard.hpp" #include "NstBoardBtlSmb2b.hpp" namespace Nes { namespace Core { namespace Boards { namespace Btl { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Smb2b::Smb2b(const Context& c) : Board(c), irq(*c.cpu) {} void Smb2b::Irq::Reset(const bool hard) { if (hard) count = 0; } void Smb2b::SubReset(const bool hard) { if (hard) { wrk.SwapBank( 15 ); prg.SwapBanks( 8, 9, 0, 11 ); } irq.Reset( hard, hard ? false : irq.Connected() ); for (uint i=0x4020; i < 0x6000; i += 0x80) Map( i+0x00, i+0x20, (i & 0x100) ? &Smb2b::Poke_4120 : &Smb2b::Poke_4020 ); Map( 0x6000U, 0x7FFFU, &Smb2b::Peek_6000 ); } void Smb2b::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( (baseChunk == AsciiId<'S','2','B'>::V) ); if (baseChunk == AsciiId<'S','2','B'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'I','R','Q'>::V) { State::Loader::Data<3> data( state ); irq.Connect( data[0] & 0x1 ); irq.unit.count = data[1] | data[2] << 8; } state.End(); } } } void Smb2b::SubSave(State::Saver& state) const { const byte data[3] = { irq.Connected() ? 0x1 : 0x0, irq.unit.count & 0xFF, irq.unit.count >> 8 }; state.Begin( AsciiId<'S','2','B'>::V ).Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(Smb2b,6000) { return wrk[0][address - 0x6000]; } NES_POKE_D(Smb2b,4020) { prg.SwapBank ( (data << 0 & 0x8) | (data << 2 & 0x4) | (data >> 1 & 0x3) ); } NES_POKE_D(Smb2b,4120) { irq.Update(); irq.Connect( data & 0x1 ); irq.ClearIRQ(); } bool Smb2b::Irq::Clock() { return ++count == 0x1000; } void Smb2b::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) { irq.unit.count = 0; irq.VSync(); } Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBtlSmb2b.hpp000066400000000000000000000033431411157722000225200ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BTL_SMB2B_H #define NST_BOARD_BTL_SMB2B_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Btl { class Smb2b : public Board { public: explicit Smb2b(const Context&); private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Sync(Event,Input::Controllers*); NES_DECL_PEEK( 6000 ); NES_DECL_POKE( 4020 ); NES_DECL_POKE( 4120 ); struct Irq { void Reset(bool); bool Clock(); uint count; }; Timer::M2 irq; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBtlSmb2c.cpp000066400000000000000000000070771411157722000225240ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstTimer.hpp" #include "NstBoard.hpp" #include "NstBoardBtlSmb2c.hpp" namespace Nes { namespace Core { namespace Boards { namespace Btl { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Smb2c::Smb2c(const Context& c) : Board (c), prgLowerOffset (prg.Source().Size() - SIZE_8K - SIZE_4K - 0x5000), irq (*c.cpu) {} void Smb2c::SubReset(const bool hard) { irq.Reset( hard, true ); if (hard) prg.SwapBank(prg.Source().Size() >= SIZE_64K); if (prg.Source().Size() >= SIZE_64K) Map( 0x4022U, &Smb2c::Poke_4022 ); Map( 0x4122U, &Smb2c::Poke_4122 ); Map( 0x5000U, 0x7FFFU, &Smb2c::Peek_5000 ); } void Smb2c::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'B','2','C'>::V) ); if (baseChunk == AsciiId<'B','2','C'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'I','R','Q'>::V) { State::Loader::Data<3> data( state ); irq.unit.enabled = data[0] & 0x1; irq.unit.count = data[1] | (data[2] << 8 & 0xF00); } state.End(); } } } void Smb2c::SubSave(State::Saver& state) const { const byte data[3] = { irq.unit.enabled != 0, irq.unit.count & 0xFF, irq.unit.count >> 8 }; state.Begin( AsciiId<'B','2','C'>::V ).Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Smb2c::Irq::Reset(const bool hard) { if (hard) { enabled = false; count = 0; } } bool Smb2c::Irq::Clock() { if (enabled) { count = (count + 1) & 0xFFF; if (!count) { enabled = false; return true; } } return false; } NES_POKE_D(Smb2c,4022) { prg.SwapBank( data & 0x1 ); } NES_POKE_D(Smb2c,4122) { irq.Update(); irq.ClearIRQ(); irq.unit.enabled = data & 0x3; irq.unit.count = 0; } NES_PEEK_A(Smb2c,5000) { return *prg.Source().Mem( address + prgLowerOffset ); } void Smb2c::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBtlSmb2c.hpp000066400000000000000000000034321411157722000225200ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BTL_SMB2C_H #define NST_BOARD_BTL_SMB2C_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Btl { class Smb2c : public Board { public: explicit Smb2c(const Context&); private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Sync(Event,Input::Controllers*); NES_DECL_POKE( 4022 ); NES_DECL_POKE( 4122 ); NES_DECL_PEEK( 5000 ); struct Irq { void Reset(bool); bool Clock(); ibool enabled; uint count; }; const uint prgLowerOffset; Timer::M2 irq; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBtlSmb3.cpp000066400000000000000000000107561411157722000223600ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstTimer.hpp" #include "NstBoard.hpp" #include "NstBoardBtlSmb3.hpp" namespace Nes { namespace Core { namespace Boards { namespace Btl { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Smb3::Smb3(const Context& c) : Board(c), irq(*c.cpu) {} void Smb3::Irq::Reset(const bool hard) { if (hard) { enabled = false; count = 0; } } void Smb3::SubReset(const bool hard) { irq.Reset( hard, true ); for (uint i=0x0000; i < 0x8000; i += 0x10) { Map( i + 0x8000U, &Smb3::Poke_8000 ); Map( i + 0x8001U, &Smb3::Poke_8001 ); Map( i + 0x8002U, &Smb3::Poke_8000 ); Map( i + 0x8003U, &Smb3::Poke_8001 ); Map( i + 0x8004U, i + 0x8007U, &Smb3::Poke_8004 ); Map( i + 0x8008U, i + 0x800BU, &Smb3::Poke_8008 ); Map( i + 0x800CU, &Smb3::Poke_800C ); Map( i + 0x800DU, &Smb3::Poke_800D ); Map( i + 0x800EU, &Smb3::Poke_800E ); Map( i + 0x800FU, &Smb3::Poke_800F ); } } void Smb3::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( (baseChunk == AsciiId<'B','S','3'>::V) ); if (baseChunk == AsciiId<'B','S','3'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'I','R','Q'>::V) { State::Loader::Data<3> data( state ); irq.unit.enabled = data[0] & 0x1; irq.unit.count = data[1] | data[2] << 8; } state.End(); } } } void Smb3::SubSave(State::Saver& state) const { const byte data[3] = { irq.unit.enabled ? 0x1 : 0x0, irq.unit.count & 0xFF, irq.unit.count >> 8 }; state.Begin( AsciiId<'B','S','3'>::V ).Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Smb3::UpdateChr(uint address,uint data) const { ppu.Update(); chr.SwapBank( address << 10 & 0x1C00, data ); } NES_POKE_AD(Smb3,8000) { UpdateChr( address, data & 0xFE ); } NES_POKE_AD(Smb3,8001) { UpdateChr( address, data | 0x01 ); } NES_POKE_AD(Smb3,8004) { UpdateChr( address, data ); } NES_POKE_AD(Smb3,8008) { address = address << 13 & 0x6000; prg.SwapBank( address, data | (address == 0x0000 || address == 0x6000 ? 0x10 : 0x00) ); } NES_POKE_D(Smb3,800C) { ppu.SetMirroring( (data & 0x1) ? Ppu::NMT_H : Ppu::NMT_V ); } NES_POKE_D(Smb3,800D) { irq.Update(); irq.unit.count = 0; irq.unit.enabled = false; irq.ClearIRQ(); } NES_POKE_D(Smb3,800E) { irq.Update(); irq.unit.count = (irq.unit.count & 0xFF00) | (data << 0); } NES_POKE_D(Smb3,800F) { irq.Update(); irq.unit.count = (irq.unit.count & 0x00FF) | (data << 8); irq.unit.enabled = true; } bool Smb3::Irq::Clock() { return enabled && (count = (count + 1) & 0xFFFF) == 0x0000 ? (enabled=false, true) : false; } void Smb3::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBtlSmb3.hpp000066400000000000000000000036551411157722000223650ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BTL_SMB3_H #define NST_BOARD_BTL_SMB3_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Btl { class Smb3 : public Board { public: explicit Smb3(const Context&); private: void SubReset(bool); void SubLoad(State::Loader&,dword); void SubSave(State::Saver&) const; void Sync(Event,Input::Controllers*); void UpdateChr(uint,uint) const; NES_DECL_POKE( 8000 ); NES_DECL_POKE( 8001 ); NES_DECL_POKE( 8004 ); NES_DECL_POKE( 8008 ); NES_DECL_POKE( 800C ); NES_DECL_POKE( 800D ); NES_DECL_POKE( 800E ); NES_DECL_POKE( 800F ); struct Irq { void Reset(bool); bool Clock(); ibool enabled; uint count; }; Timer::M2 irq; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBtlSuperBros11.cpp000066400000000000000000000035631411157722000236400ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardBtlSuperBros11.hpp" namespace Nes { namespace Core { namespace Boards { namespace Btl { void SuperBros11::SubReset(const bool hard) { Mmc3::SubReset( hard ); for (uint i=0x0000; i < 0x2000; i += 0x8) { Map( 0x8000 + i, 0x8003 + i, &SuperBros11::Poke_8000 ); Map( 0x8004 + i, 0x8007 + i, &SuperBros11::Poke_8001 ); Map( 0xA000 + i, 0xA003 + i, NMT_SWAP_HV ); Map( 0xA004 + i, 0xA007 + i, &SuperBros11::Poke_A001 ); Map( 0xC000 + i, 0xC003 + i, &SuperBros11::Poke_C000 ); Map( 0xC004 + i, 0xC007 + i, &SuperBros11::Poke_C001 ); Map( 0xE000 + i, 0xE003 + i, &SuperBros11::Poke_E000 ); Map( 0xE004 + i, 0xE007 + i, &SuperBros11::Poke_E001 ); } } } } } } nestopia-1.51.1/source/core/board/NstBoardBtlSuperBros11.hpp000066400000000000000000000026631411157722000236450ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BTL_SUPERBROS11_H #define NST_BOARD_BTL_SUPERBROS11_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Btl { class SuperBros11 : public Mmc3 { public: explicit SuperBros11(const Context& c) : Mmc3(c) {} private: void SubReset(bool); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBtlT230.cpp000066400000000000000000000033661411157722000222030ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstTimer.hpp" #include "NstBoard.hpp" #include "NstBoardKonamiVrc4.hpp" #include "NstBoardBtlT230.hpp" namespace Nes { namespace Core { namespace Boards { namespace Btl { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void T230::SubReset(const bool hard) { Vrc4::SubReset( hard ); Map( 0x8000U, 0x8FFFU, NOP_POKE ); Map( 0xA000U, 0xAFFFU, &T230::Poke_A000 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(T230,A000) { data = data << 1 & 0x1F; prg.SwapBank( prgSwap << 13, data ); prg.SwapBank( data | 0x1 ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBtlT230.hpp000066400000000000000000000026761411157722000222130ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BTL_T230_H #define NST_BOARD_BTL_T230_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Btl { class T230 : public Konami::Vrc4 { public: explicit T230(const Context& c) : Vrc4(c) {} private: void SubReset(bool); NES_DECL_POKE( A000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBtlTobidaseDaisakusen.cpp000066400000000000000000000035721411157722000253140ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBtlTobidaseDaisakusen.hpp" namespace Nes { namespace Core { namespace Boards { namespace Btl { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void TobidaseDaisakusen::SubReset(const bool hard) { if (hard) prg.SwapBank( 2 ); for (uint i=0x4100; i < 0x6000; ++i) { if ((i & 0xE3C0) == 0x41C0) Map( i, &TobidaseDaisakusen::Poke_41FF ); } Map( 0x6000U, 0x7FFFU, &TobidaseDaisakusen::Peek_6000 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(TobidaseDaisakusen,6000) { return wrk[0][address - 0x6000]; } NES_POKE_D(TobidaseDaisakusen,41FF) { wrk.SwapBank( data & 0x7 ); } } } } } nestopia-1.51.1/source/core/board/NstBoardBtlTobidaseDaisakusen.hpp000066400000000000000000000030151411157722000253110ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BTL_TOBIDASEDAISAKUSEN_H #define NST_BOARD_BTL_TOBIDASEDAISAKUSEN_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Btl { class TobidaseDaisakusen : public Board { public: explicit TobidaseDaisakusen(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_PEEK( 6000 ); NES_DECL_POKE( 41FF ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardBxRom.cpp000066400000000000000000000030161411157722000221300ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardBxRom.hpp" namespace Nes { namespace Core { namespace Boards { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void BxRom::SubReset(const bool hard) { if (board == Type::STD_BNROM) Map( PRG_SWAP_32K_BC ); else Map( 0x8000U, 0xFFFFU, PRG_SWAP_32K ); if (hard) prg.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } } nestopia-1.51.1/source/core/board/NstBoardBxRom.hpp000066400000000000000000000025571411157722000221460ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_BXROM_H #define NST_BOARD_BXROM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { class BxRom : public Board { public: explicit BxRom(const Context& c) : Board(c) {} private: void SubReset(bool); }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardCaltron.cpp000066400000000000000000000050111411157722000225000ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardCaltron.hpp" namespace Nes { namespace Core { namespace Boards { namespace Caltron { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Mc6in1::SubReset(const bool hard) { Map( 0x6000U, 0x67FFU, &Mc6in1::Poke_6000 ); Map( 0x8000U, 0xFFFFU, &Mc6in1::Poke_8000 ); if (hard) { reg = 0; prg.SwapBank(0); } } void Mc6in1::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'C','6','1'>::V) ); if (baseChunk == AsciiId<'C','6','1'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) reg = state.Read8(); state.End(); } } } void Mc6in1::SubSave(State::Saver& state) const { state.Begin( AsciiId<'C','6','1'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( reg ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_A(Mc6in1,6000) { reg = address & 0xFF; prg.SwapBank( address & 0x7 ); ppu.SetMirroring( (address & 0x10) ? Ppu::NMT_H : Ppu::NMT_V ); } NES_POKE_D(Mc6in1,8000) { NST_VERIFY( reg & 0x4 ); if (reg & 0x4) { ppu.Update(); chr.SwapBank( (reg >> 1 & 0xC) | (data & 0x3) ); } } } } } } nestopia-1.51.1/source/core/board/NstBoardCaltron.hpp000066400000000000000000000031001411157722000225020ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_CALTRON_H #define NST_BOARD_CALTRON_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Caltron { class Mc6in1 : public Board { public: explicit Mc6in1(const Context& c) : Board(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); NES_DECL_POKE( 8000 ); NES_DECL_POKE( 6000 ); uint reg; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardCamerica.cpp000066400000000000000000000057171411157722000226170ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardCamerica.hpp" namespace Nes { namespace Core { namespace Boards { namespace Camerica { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Bf9093::SubReset(bool) { Map( 0xC000U, 0xFFFFU, PRG_SWAP_16K_0 ); Map( 0x8000U, 0xBFFFU, &Bf9093::Poke_C000 ); } void Bf9096::SubReset(bool) { Map( 0x8000U, 0xBFFFU, &Bf9096::Poke_8000 ); Map( 0xC000U, 0xFFFFU, &Bf9096::Poke_A000 ); } void Bf9097::SubReset(const bool hard) { Bf9093::SubReset( hard ); Map( 0x8000U, 0x9FFFU, &Bf9097::Poke_8000 ); } void GoldenFive::SubReset(const bool hard) { Map( 0x8000U, 0x9FFFU, &GoldenFive::Poke_8000 ); Map( 0xC000U, 0xFFFFU, &GoldenFive::Poke_C000 ); if (hard) prg.SwapBank( 0x0F ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Bf9093,C000) { prg.SwapBank( data ); } void Bf9096::SwapBasePrg(uint base) { prg.SwapBanks( base | (prg.GetBank() & 0x3), base | 0x3 ); } NES_POKE_D(Bf9096,8000) { SwapBasePrg( data >> 1 & 0xC ); } NES_POKE_D(Bf9096,A000) { prg.SwapBank( (prg.GetBank() & 0xC) | (data & 0x3) ); } NES_POKE_D(Bf9097,8000) { ppu.SetMirroring( (data & 0x10) ? Ppu::NMT_1 : Ppu::NMT_0 ); } NES_POKE_D(GoldenFive,8000) { if (data & 0x8) { prg.SwapBank( (data << 4 & 0x70) | (prg.GetBank() & 0x0F) ); prg.SwapBank( (data << 4 & 0x70) | 0x0F ); } } NES_POKE_D(GoldenFive,C000) { prg.SwapBank( (prg.GetBank() & 0x70) | (data & 0x0F) ); } } } } } nestopia-1.51.1/source/core/board/NstBoardCamerica.hpp000066400000000000000000000043361411157722000226200ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_CAMERICA_H #define NST_BOARD_CAMERICA_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Camerica { class Bf9093 : public Board { public: explicit Bf9093(const Context& c) : Board(c) {} protected: void SubReset(bool); private: NES_DECL_POKE( C000 ); }; class Bf9096 : public Board { public: explicit Bf9096(const Context& c) : Board(c) {} protected: void SubReset(bool); void SwapBasePrg(uint); private: NES_DECL_POKE( 8000 ); NES_DECL_POKE( A000 ); }; class Bf9097 : public Bf9093 { public: explicit Bf9097(const Context& c) : Bf9093(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; typedef Bf9093 Algnv11; typedef Bf9096 Algqv11; class GoldenFive : public Board { public: explicit GoldenFive(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); NES_DECL_POKE( C000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardCne.hpp000066400000000000000000000023451411157722000216170ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_CNE_H #define NST_BOARD_CNE_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardCneDecathlon.hpp" #include "NstBoardCnePsb.hpp" #include "NstBoardCneShlz.hpp" #endif nestopia-1.51.1/source/core/board/NstBoardCneDecathlon.cpp000066400000000000000000000034531411157722000234350ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardCneDecathlon.hpp" namespace Nes { namespace Core { namespace Boards { namespace Cne { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Decathlon::SubReset(const bool hard) { Map( 0x8065U, 0x80A4U, &Decathlon::Poke_8065 ); Map( 0x80A5U, 0x80E4U, &Decathlon::Poke_80A5 ); if (hard) prg.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_A(Decathlon,8065) { prg.SwapBank( (address - 0x8065) & 0x3 ); } NES_POKE_A(Decathlon,80A5) { ppu.Update(); chr.SwapBank( (address - 0x80A5) & 0x7 ); } } } } } nestopia-1.51.1/source/core/board/NstBoardCneDecathlon.hpp000066400000000000000000000027511411157722000234420ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_CNE_DECATHLON_H #define NST_BOARD_CNE_DECATHLON_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Cne { class Decathlon : public Board { public: explicit Decathlon(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8065 ); NES_DECL_POKE( 80A5 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardCnePsb.cpp000066400000000000000000000033501411157722000222540ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardCnePsb.hpp" namespace Nes { namespace Core { namespace Boards { namespace Cne { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Psb::SubReset(bool) { for (uint i=0x6000; i < 0x6800; i += 0x8) { Map( i + 0x0, PRG_SWAP_8K_0 ); Map( i + 0x1, PRG_SWAP_8K_1 ); Map( i + 0x2, PRG_SWAP_8K_2 ); Map( i + 0x3, PRG_SWAP_8K_3 ); Map( i + 0x4, CHR_SWAP_2K_0 ); Map( i + 0x5, CHR_SWAP_2K_1 ); Map( i + 0x6, CHR_SWAP_2K_2 ); Map( i + 0x7, CHR_SWAP_2K_3 ); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } } } nestopia-1.51.1/source/core/board/NstBoardCnePsb.hpp000066400000000000000000000026251411157722000222650ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_CNE_PSB_H #define NST_BOARD_CNE_PSB_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Cne { class Psb : public Board { public: explicit Psb(const Context& c) : Board(c) {} private: void SubReset(bool); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardCneShlz.cpp000066400000000000000000000031101411157722000224420ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardCneShlz.hpp" namespace Nes { namespace Core { namespace Boards { namespace Cne { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Shlz::SubReset(bool) { Map( 0x4020U, 0x5FFFU, &Shlz::Poke_4020 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Shlz,4020) { ppu.Update(); prg.SwapBank( data >> 4 ); chr.SwapBank( data ); } } } } } nestopia-1.51.1/source/core/board/NstBoardCneShlz.hpp000066400000000000000000000026701411157722000224610ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_CNE_SHLZ_H #define NST_BOARD_CNE_SHLZ_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Cne { class Shlz : public Board { public: explicit Shlz(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 4020 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardCony.cpp000066400000000000000000000215041411157722000220130ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstTimer.hpp" #include "NstBoard.hpp" #include "NstBoardCony.hpp" #include "../NstDipSwitches.hpp" #include "../NstCrc32.hpp" namespace Nes { namespace Core { namespace Boards { namespace Cony { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif class Standard::CartSwitches : public DipSwitches { enum { FF2 = 0xD0350E25, SFXT40 = 0x1030C4EB, WH2 = 0x1461D1F8 }; uint region; CartSwitches() : region(0) {} public: static CartSwitches* Create(const Context& c) { switch (Crc32::Compute(c.prg.Mem(),c.prg.Size())) { case FF2: case SFXT40: case WH2: return new CartSwitches; } return NULL; } void SetRegion(uint value) { region = value ? 1 : 0; } uint GetRegion() const { return region ? 0xFF : 0x00; } private: uint GetValue(uint) const { return region; } void SetValue(uint,uint value) { region = value; } uint NumDips() const { return 1; } uint NumValues(uint) const { return 2; } cstring GetDipName(uint) const { return "Region"; } cstring GetValueName(uint,uint i) const { return i ? "Asia" : "US"; } }; void Standard::Irq::Reset(const bool hard) { if (hard) { enabled = false; count = 0; step = 1; } } Standard::Standard(const Context& c) : Board (c), irq (*c.cpu), cartSwitches (CartSwitches::Create(c)) {} Standard::~Standard() { delete cartSwitches; } Standard::Device Standard::QueryDevice(DeviceType type) { if (type == DEVICE_DIP_SWITCHES) return cartSwitches; else return Board::QueryDevice( type ); } void Standard::SubReset(const bool hard) { irq.Reset( hard, true ); if (hard) { regs.ctrl = 0; for (uint i=0; i < 5; ++i) regs.prg[i] = 0; regs.pr8 = 0; } UpdatePrg(); Map( 0x5000U, &Standard::Peek_5000 ); Map( 0x5100U, 0x51FF, &Standard::Peek_5100, &Standard::Poke_5100 ); if (!board.GetWram()) Map( 0x6000U, 0x7FFFU, &Standard::Peek_6000 ); for (uint i=0x8000; i < 0x9000; i += 0x400) { Map( i+0x000, i+0x0FF, &Standard::Poke_8000 ); Map( i+0x100, i+0x1FF, &Standard::Poke_8100 ); for (uint j=i+0x00, n=i+0x100; j < n; j += 0x02) { Map( j+0x200, &Standard::Poke_8200 ); Map( j+0x201, &Standard::Poke_8201 ); } for (uint j=i+0x00, n=i+0x100; j < n; j += 0x20) { Map( j+0x300, j+0x30F, &Standard::Poke_8300 ); if (chr.Source().Size() == SIZE_512K) { Map( j+0x310, j+0x311, &Standard::Poke_8310_1 ); Map( j+0x316, j+0x317, &Standard::Poke_8310_1 ); } else { Map( j+0x310, j+0x317, &Standard::Poke_8310_0 ); } } } Map( 0xB000U, &Standard::Poke_8000 ); Map( 0xB0FFU, &Standard::Poke_8000 ); Map( 0xB100U, &Standard::Poke_8000 ); } void Standard::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'C','N','Y'>::V) ); if (baseChunk == AsciiId<'C','N','Y'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: regs.ctrl = state.Read8(); state.Read( regs.prg ); break; case AsciiId<'P','R','8'>::V: regs.pr8 = state.Read8(); break; case AsciiId<'I','R','Q'>::V: { State::Loader::Data<3> data( state ); irq.unit.enabled = data[0] & 0x1; irq.unit.step = (data[0] & 0x2) ? ~0U : 1U; irq.unit.count = data[1] | data[2] << 8; break; } case AsciiId<'L','A','N'>::V: NST_VERIFY( cartSwitches ); if (cartSwitches) cartSwitches->SetRegion( state.Read8() & 0x1 ); break; } state.End(); } } } void Standard::SubSave(State::Saver& state) const { state.Begin( AsciiId<'C','N','Y'>::V ); { const byte data[1+5] = { regs.ctrl, regs.prg[0], regs.prg[1], regs.prg[2], regs.prg[3], regs.prg[4] }; state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End(); } state.Begin( AsciiId<'P','R','8'>::V ).Write8( regs.pr8 ).End(); { const byte data[3] = { (irq.unit.enabled ? 0x1U : 0x0U) | (irq.unit.step == 1 ? 0x0U : 0x2U), irq.unit.count & 0xFF, irq.unit.count >> 8 }; state.Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End(); } if (cartSwitches) state.Begin( AsciiId<'L','A','N'>::V ).Write8( cartSwitches->GetRegion() ? 0x1 : 0x0 ).End(); state.End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Standard::UpdatePrg() { if (regs.ctrl & 0x10U) { wrk.SwapBank( 0x1F ); prg.SwapBanks( regs.prg[0], regs.prg[1] ); prg.SwapBank( regs.prg[2] ); } else { wrk.SwapBank( regs.prg[3] ); prg.SwapBank( regs.prg[4] & 0x3FU ); prg.SwapBank( (regs.prg[4] & 0x30U) | 0x0F ); } } NES_PEEK(Standard,5000) { return cartSwitches ? cartSwitches->GetRegion() : 0xFF; } NES_PEEK(Standard,5100) { return regs.pr8; } NES_POKE_D(Standard,5100) { regs.pr8 = data; } NES_PEEK_A(Standard,6000) { NST_VERIFY( regs.ctrl & 0x20U ); return (regs.ctrl & 0x20U) ? wrk[0][address - 0x6000] : address >> 8; } NES_POKE_D(Standard,8000) { if (regs.prg[4] != data) { regs.prg[4] = data; UpdatePrg(); } } NES_POKE_D(Standard,8100) { const uint diff = data ^ regs.ctrl; regs.ctrl = data; if (diff & 0x10) UpdatePrg(); if (diff & 0xC0) { irq.Update(); irq.unit.step = (data & 0x40) ? ~0U : 1U; } if (diff & 0x03) SetMirroringVH01( data ); } NES_POKE_D(Standard,8200) { irq.Update(); irq.unit.count = (irq.unit.count & 0xFF00) | data; irq.ClearIRQ(); } NES_POKE_D(Standard,8201) { irq.Update(); irq.unit.count = (irq.unit.count & 0x00FF) | (data << 8); irq.unit.enabled = regs.ctrl & 0x80U; irq.ClearIRQ(); } NES_POKE_AD(Standard,8310_0) { ppu.Update(); chr.SwapBank( (address & 0x7) << 10, (regs.prg[4] << 4 & 0x300U) | data ); } NES_POKE_AD(Standard,8310_1) { ppu.Update(); chr.SwapBank( (address & 0x3) << 11, data ); } NES_POKE_AD(Standard,8300) { data &= 0x1F; if (regs.prg[address & 0x3] != data) { regs.prg[address & 0x3] = data; UpdatePrg(); } } bool Standard::Irq::Clock() { if (enabled && count) { count = (count + step) & 0xFFFF; if (!count) { enabled = false; return true; } } return false; } void Standard::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardCony.hpp000066400000000000000000000043731411157722000220250ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_CONY_H #define NST_BOARD_CONY_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Cony { class Standard : public Board { public: explicit Standard(const Context&); private: ~Standard(); class CartSwitches; void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); Device QueryDevice(DeviceType); void UpdatePrg(); void Sync(Event,Input::Controllers*); NES_DECL_PEEK( 5000 ); NES_DECL_PEEK( 5100 ); NES_DECL_POKE( 5100 ); NES_DECL_PEEK( 6000 ); NES_DECL_POKE( 8000 ); NES_DECL_POKE( 8100 ); NES_DECL_POKE( 8200 ); NES_DECL_POKE( 8201 ); NES_DECL_POKE( 8300 ); NES_DECL_POKE( 8310_0 ); NES_DECL_POKE( 8310_1 ); struct Irq { void Reset(bool); bool Clock(); ibool enabled; uint count; uint step; }; struct { word ctrl; byte prg[5]; byte pr8; } regs; Timer::M2 irq; CartSwitches* const cartSwitches; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardCxRom.cpp000066400000000000000000000050431411157722000221330ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardCxRom.hpp" namespace Nes { namespace Core { namespace Boards { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif CnRom::Ce::Ce(const Context& c) : mask(0x0), state(0x0) { if (c.chr.Pin(26) == L"CE") { mask |= 0x1; state |= 0x1; } else if (c.chr.Pin(26) == L"/CE") { mask |= 0x1; state |= 0x0; } if (c.chr.Pin(27) == L"CE") { mask |= 0x2; state |= 0x2; } else if (c.chr.Pin(27) == L"/CE") { mask |= 0x2; state |= 0x0; } } CnRom::CnRom(const Context& c) : Board(c), ce(c) {} void CnRom::SubReset(bool) { if (ce.mask) { Map( 0x8000U, 0xFFFFU, &CnRom::Poke_8000 ); } else if (board == Type::STD_CNROM) { Map( CHR_SWAP_8K_BC ); } else { Map( 0x8000U, 0xFFFFU, CHR_SWAP_8K ); } } void CpRom::SubReset(const bool hard) { Map( CHR_SWAP_4K_1_BC ); if (hard) chr.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_ACCESSOR(CnRom,ChrOpenBus) { return 0xFF; } NES_POKE_AD(CnRom,8000) { data = GetBusData(address,data); ppu.Update(); chr.SwapBank( data & ~ce.mask ); if ((data & ce.mask) == ce.state) chr.ResetAccessor(); else chr.SetAccessor( this, &CnRom::Access_ChrOpenBus ); } } } } nestopia-1.51.1/source/core/board/NstBoardCxRom.hpp000066400000000000000000000033141411157722000221370ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_CXROM_H #define NST_BOARD_CXROM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { class CnRom : public Board { public: explicit CnRom(const Context&); protected: void SubReset(bool); private: NES_DECL_POKE( 8000 ); NES_DECL_ACCESSOR( ChrOpenBus ); struct Ce { explicit Ce(const Context&); uint mask; uint state; }; const Ce ce; }; class CpRom : public Board { public: explicit CpRom(const Context& c) : Board(c) {} private: void SubReset(bool); }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardDiscrete.cpp000066400000000000000000000057551411157722000226570ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardDiscrete.hpp" namespace Nes { namespace Core { namespace Boards { namespace Discrete { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Ic74x161x161x32::SubReset(bool) { if (board == Type::DISCRETE_74_161_161_32_A) Map( 0x8000U, 0xFFFFU, &Ic74x161x161x32::Poke_8000_0 ); else Map( 0x8000U, 0xFFFFU, &Ic74x161x161x32::Poke_8000_1 ); } void Ic74x139x74::SubReset(bool) { Map( 0x6000U, 0x7FFFU, &Ic74x139x74::Poke_6000 ); } void Ic74x161x138::SubReset(const bool hard) { Map( 0x6000U, 0x7FFFU, &Ic74x161x138::Poke_6000 ); if (hard) prg.SwapBank(0); } void Ic74x377::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &Ic74x377::Poke_8000 ); if (hard) prg.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(Ic74x161x161x32,8000_0) { ppu.Update(); data = GetBusData(address,data); chr.SwapBank( data ); prg.SwapBank( data >> 4 ); } NES_POKE_AD(Ic74x161x161x32,8000_1) { data = GetBusData(address,data); ppu.SetMirroring( (data & 0x80) ? Ppu::NMT_1 : Ppu::NMT_0 ); chr.SwapBank( data ); prg.SwapBank( data >> 4 ); } NES_POKE_D(Ic74x139x74,6000) { ppu.Update(); chr.SwapBank( (data >> 1 & 0x1) | (data << 1 & 0x2) ); } NES_POKE_D(Ic74x161x138,6000) { ppu.Update(); chr.SwapBank( data >> 2 ); prg.SwapBank( data ); } NES_POKE_AD(Ic74x377,8000) { ppu.Update(); data = GetBusData(address,data); prg.SwapBank( data ); chr.SwapBank( data >> 4 ); } } } } } nestopia-1.51.1/source/core/board/NstBoardDiscrete.hpp000066400000000000000000000041731411157722000226550ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_DISCRETE_H #define NST_BOARD_DISCRETE_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Discrete { class Ic74x161x161x32 : public Board { public: explicit Ic74x161x161x32(const Context& c) : Board(c) {} protected: void SubReset(bool); private: NES_DECL_POKE( 8000_0 ); NES_DECL_POKE( 8000_1 ); }; class Ic74x139x74 : public Board { public: explicit Ic74x139x74(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 6000 ); }; class Ic74x161x138 : public Board { public: explicit Ic74x161x138(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 6000 ); }; class Ic74x377 : public Board { public: explicit Ic74x377(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardDreamtech.cpp000066400000000000000000000026471411157722000230060ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardDreamtech.hpp" namespace Nes { namespace Core { namespace Boards { namespace DreamTech { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void D01::SubReset(bool) { Map( 0x5020U, PRG_SWAP_16K_0 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } } } nestopia-1.51.1/source/core/board/NstBoardDreamtech.hpp000066400000000000000000000026371411157722000230120ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_DREAMTECH_H #define NST_BOARD_DREAMTECH_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace DreamTech { class D01 : public Board { public: explicit D01(const Context& c) : Board(c) {} private: void SubReset(bool); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardDxRom.hpp000066400000000000000000000024231411157722000221400ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_DXROM_H #define NST_BOARD_DXROM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardNamcot.hpp" namespace Nes { namespace Core { namespace Boards { typedef Namcot::N34x3 DxRom; } } } #endif nestopia-1.51.1/source/core/board/NstBoardEvent.cpp000066400000000000000000000136571411157722000221760ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstBoard.hpp" #include "../NstTimer.hpp" #include "NstBoardMmc1.hpp" #include "NstBoardEvent.hpp" #include "../api/NstApiUser.hpp" namespace Nes { namespace Core { namespace Boards { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Event::CartSwitches::CartSwitches() : time(DEFAULT_DIP), showTime(true) {} Event::Event(const Context& c) : Mmc1(c,REV_B2), irq(*c.cpu) { NST_COMPILE_ASSERT( TIME_TEXT_MIN_OFFSET == 11 && TIME_TEXT_SEC_OFFSET == 13 ); std::strcpy( text, "Time left: x:xx" ); } uint Event::CartSwitches::NumDips() const { return 2; } uint Event::CartSwitches::NumValues(uint dip) const { NST_ASSERT( dip < 2 ); return (dip == 0) ? 16 : 2; } cstring Event::CartSwitches::GetDipName(uint dip) const { NST_ASSERT( dip < 2 ); return (dip == 0) ? "Time" : "Show Time"; } cstring Event::CartSwitches::GetValueName(uint dip,uint value) const { NST_ASSERT( dip < 2 ); if (dip == 0) { NST_ASSERT( value < 16 ); static const char times[16][7] = { "5:00.4", "5:19.2", "5:38.0", "5:56.7", "6:15.5", "6:34.3", "6:53.1", "7:11.9", "7:30.6", "7:49.4", "8:08.2", "8:27.0", "8:45.8", "9:04.5", "9:23.3", "9:42.1" }; return times[value]; } else { NST_ASSERT( value < 2 ); return (value == 0) ? "no" : "yes"; } } uint Event::CartSwitches::GetValue(uint dip) const { NST_ASSERT( dip < 2 ); return (dip == 0) ? time : showTime; } void Event::CartSwitches::SetValue(uint dip,uint value) { NST_ASSERT( dip < 2 ); if (dip == 0) { NST_ASSERT( value < 16 ); time = value; } else { NST_ASSERT( value < 2 ); showTime = value; } } inline dword Event::CartSwitches::GetTime() const { return BASE_TIME * (time + 16UL) - 1; } inline bool Event::CartSwitches::ShowTime() const { return showTime; } Event::Device Event::QueryDevice(DeviceType type) { if (type == DEVICE_DIP_SWITCHES) return &cartSwitches; else return Board::QueryDevice( type ); } void Event::SubReset(const bool hard) { irq.Reset( hard, true ); time = 0; Mmc1::SubReset( hard ); prg.SwapBank( 1 ); } void Event::SubLoad(State::Loader& state,const dword baseChunk) { time = 0; if (baseChunk == AsciiId<'E','V','T'>::V) { irq.unit.count = 0; while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'I','R','Q'>::V) irq.unit.count = state.Read32(); state.End(); } } else { Mmc1::SubLoad( state, baseChunk ); } } void Event::SubSave(State::Saver& state) const { state.Begin( AsciiId<'E','V','T'>::V ).Begin( AsciiId<'I','R','Q'>::V ).Write32( irq.unit.count ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void NST_FASTCALL Event::UpdateRegisters(const uint index) { NST_ASSERT( index < 4 ); if (index != 2) { if (regs[1] & 0x8U) { switch (regs[0] & 0xCU) { case 0x0: case 0x4: prg.SwapBank( 0x4 | (regs[3] >> 1 & 0x3U) ); break; case 0x8: prg.SwapBanks( 0x8, 0x8 | (regs[3] & 0x7U) ); break; case 0xC: prg.SwapBanks( 0x8 | (regs[3] & 0x7U), 0xF ); break; } } else { prg.SwapBank( regs[1] >> 1 & 0x3U ); } UpdateWrk(); if (index == 0) { UpdateNmt(); } else { irq.Update(); if (regs[1] & 0x10U) { irq.unit.count = 0; irq.ClearIRQ(); } else if (irq.unit.count == 0) { irq.unit.count = cartSwitches.GetTime(); } } } } void Event::Irq::Reset(bool) { count = 0; } bool Event::Irq::Clock() { return count && --count == 0; } void Event::Sync(Board::Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) { if (cartSwitches.ShowTime() && irq.unit.count) { const dword t = cpu.GetTime( irq.unit.count ); if (time != t) { time = t; text[TIME_TEXT_MIN_OFFSET+0] = '0' + t / 60; text[TIME_TEXT_SEC_OFFSET+0] = '0' + t % 60 / 10; text[TIME_TEXT_SEC_OFFSET+1] = '0' + t % 60 % 10; Api::User::eventCallback( Api::User::EVENT_DISPLAY_TIMER, text ); } } irq.VSync(); Mmc1::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardEvent.hpp000066400000000000000000000045771411157722000222040ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_EVENT_H #define NST_BOARD_EVENT_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "../NstDipSwitches.hpp" namespace Nes { namespace Core { namespace Boards { class Event : public Mmc1 { public: explicit Event(const Context&); private: class CartSwitches : public DipSwitches { public: CartSwitches(); inline bool ShowTime() const; inline dword GetTime() const; private: enum { DEFAULT_DIP = 4, BASE_TIME = 0x2000000 }; uint NumDips() const; uint NumValues(uint) const; cstring GetDipName(uint) const; cstring GetValueName(uint,uint) const; uint GetValue(uint) const; void SetValue(uint,uint); uint time; ibool showTime; }; void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); Device QueryDevice(DeviceType); void NST_FASTCALL UpdateRegisters(uint); void Sync(Board::Event,Input::Controllers*); struct Irq { void Reset(bool); bool Clock(); dword count; }; enum { TIME_TEXT_MIN_OFFSET = 11, TIME_TEXT_SEC_OFFSET = 13 }; Timer::M2 irq; dword time; CartSwitches cartSwitches; char text[16]; }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardExRom.hpp000066400000000000000000000025411411157722000221420ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_EXROM_H #define NST_BOARD_EXROM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardMmc5.hpp" namespace Nes { namespace Core { namespace Boards { class ExRom : public Mmc5 { public: explicit ExRom(const Context& c) : Mmc5(c) {} }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardFb.cpp000066400000000000000000000072441411157722000214370ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "../NstDipSwitches.hpp" #include "../NstLog.hpp" #include "NstBoardFb.hpp" namespace Nes { namespace Core { namespace Boards { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Fb::Fb(const Context& c) : Board(c), cartSwitch(wrk) {} void Fb::SubReset(const bool hard) { cartSwitch.Reset( hard ); switch (board.GetWram()) { case SIZE_8K: Map( 0x6000U, 0x7FFFU, &Fb::Peek_Wrk_6, &Fb::Poke_Wrk_6 ); break; case SIZE_4K: Map( 0x6000U, 0x7000U, &Fb::Peek_Wrk_6, &Fb::Poke_Wrk_6 ); break; case SIZE_2K: Map( 0x7000U, 0x7800U, &Fb::Peek_Wrk_7, &Fb::Poke_Wrk_7 ); break; } } void Fb::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_POWER_OFF) cartSwitch.Flush(); Board::Sync( event, controllers ); } Fb::Device Fb::QueryDevice(DeviceType type) { if (type == DEVICE_DIP_SWITCHES) return &cartSwitch; else return Board::QueryDevice( type ); } Fb::CartSwitch::CartSwitch(Wrk& w) : wrk(w), init(true) {} void Fb::CartSwitch::Reset(bool hard) { if (init) { init = false; } else if (hard) { Flush(); } } void Fb::CartSwitch::Flush() const { if (wrk.Source().Writable()) { wrk.Source().Fill( 0x00 ); Log::Flush( "Fb: battery-switch OFF, discarding W-RAM.." NST_LINEBREAK ); } } uint Fb::CartSwitch::NumDips() const { return 1; } uint Fb::CartSwitch::NumValues(uint) const { return 2; } cstring Fb::CartSwitch::GetDipName(uint) const { return "Backup Switch"; } cstring Fb::CartSwitch::GetValueName(uint,uint value) const { NST_ASSERT( value < 2 ); return value == 0 ? "Off" : "On"; } uint Fb::CartSwitch::GetValue(uint) const { return wrk.Source().Writable() ? 0 : 1; } void Fb::CartSwitch::SetValue(uint,uint value) { NST_ASSERT( value < 2 ); wrk.Source().SetSecurity( true, !value ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(Fb,Wrk_6) { NST_VERIFY( wrk.Writable(0) ); if (wrk.Writable(0)) wrk[0][address - 0x6000] = data; } NES_PEEK_A(Fb,Wrk_6) { return wrk[0][address - 0x6000]; } NES_POKE_AD(Fb,Wrk_7) { NST_VERIFY( wrk.Writable(0) ); if (wrk.Writable(0)) wrk[0][address - 0x7000] = data; } NES_PEEK_A(Fb,Wrk_7) { return wrk[0][address - 0x7000]; } } } } nestopia-1.51.1/source/core/board/NstBoardFb.hpp000066400000000000000000000037321411157722000214420ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_FB_H #define NST_BOARD_FB_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { class Fb : public Board { public: explicit Fb(const Context&); private: class CartSwitch : public DipSwitches { public: explicit CartSwitch(Wrk&); void Flush() const; void Reset(bool); private: Wrk& wrk; bool init; uint NumDips() const; uint NumValues(uint) const; cstring GetDipName(uint) const; cstring GetValueName(uint,uint) const; uint GetValue(uint) const; void SetValue(uint,uint); }; void SubReset(bool); void Sync(Event,Input::Controllers*); Device QueryDevice(DeviceType); NES_DECL_PEEK( Wrk_6 ); NES_DECL_POKE( Wrk_6 ); NES_DECL_PEEK( Wrk_7 ); NES_DECL_POKE( Wrk_7 ); CartSwitch cartSwitch; }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardFfe.cpp000066400000000000000000000135351411157722000216100ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstBoard.hpp" #include "../NstTimer.hpp" #include "NstBoardFfe.hpp" namespace Nes { namespace Core { namespace Boards { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Ffe::Trainer::Trainer(const Ram& ram) : available(ram.Size() >= SIZE) { if (available) std::memcpy( data, ram.Mem(), SIZE ); else std::memset( data, 0x00, SIZE ); } Ffe::Ffe(const Context& c) : Board (c), irq (board == Type::CUSTOM_FFE3 ? NULL : new Timer::M2(*c.cpu,0xFFFF)), trainer (c.trainer) { } Ffe::~Ffe() { delete irq; } void Ffe::Irq::Reset(const bool hard) { if (hard) { count = 0; enabled = false; } } void Ffe::SubReset(const bool hard) { if (hard) mode = 0; if (trainer.available && board.GetWram() >= 0x1000 + Trainer::SIZE) std::memcpy( wrk.Source().Mem(0x1000), trainer.data, Trainer::SIZE ); Map( 0x42FEU, &Ffe::Poke_42FE ); Map( 0x42FFU, &Ffe::Poke_42FF ); if (irq) { irq->Reset( hard, hard || irq->Connected() ); Map( 0x4501U, &Ffe::Poke_4501 ); Map( 0x4502U, &Ffe::Poke_4502 ); Map( 0x4503U, &Ffe::Poke_4503 ); } if (board.GetId() == Type::CUSTOM_FFE3) { Map( 0x8000U, 0xFFFFU, &Ffe::Poke_Prg_F3 ); if (hard) prg.SwapBank(0); } else if (board.GetId() == Type::CUSTOM_FFE4) { Map( 0x8000U, 0xFFFFU, &Ffe::Poke_Prg_F4 ); if (hard) prg.SwapBank(7); } else if (board.GetId() == Type::CUSTOM_FFE8) { Map( 0x4504U, PRG_SWAP_8K_0 ); Map( 0x4505U, PRG_SWAP_8K_1 ); Map( 0x4506U, PRG_SWAP_8K_2 ); Map( 0x4507U, PRG_SWAP_8K_3 ); Map( 0x4510U, CHR_SWAP_1K_0 ); Map( 0x4511U, CHR_SWAP_1K_1 ); Map( 0x4512U, CHR_SWAP_1K_2 ); Map( 0x4513U, CHR_SWAP_1K_3 ); Map( 0x4514U, CHR_SWAP_1K_4 ); Map( 0x4515U, CHR_SWAP_1K_5 ); Map( 0x4516U, CHR_SWAP_1K_6 ); Map( 0x4517U, CHR_SWAP_1K_7 ); } } void Ffe::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'F','F','E'>::V) ); if (baseChunk == AsciiId<'F','F','E'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: NST_VERIFY( board == Type::CUSTOM_FFE4 ); if (board == Type::CUSTOM_FFE4) mode = state.Read8() & 0x1; break; case AsciiId<'I','R','Q'>::V: NST_VERIFY( irq ); if (irq) { State::Loader::Data<3> data( state ); irq->unit.enabled = data[0] & 0x1; irq->unit.count = data[1] | data[2] << 8; } break; } state.End(); } } } void Ffe::SubSave(State::Saver& state) const { state.Begin( AsciiId<'F','F','E'>::V ); if (board == Type::CUSTOM_FFE4) state.Begin( AsciiId<'R','E','G'>::V ).Write8( mode ).End(); if (irq) { const byte data[3] = { irq->unit.enabled != false, irq->unit.count & 0xFF, irq->unit.count >> 8 }; state.Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End(); } state.End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif bool Ffe::Irq::Clock() { if (enabled && count++ == clock) { count = 0; enabled = false; return true; } return false; } NES_POKE_D(Ffe,42FE) { mode = data >> 7 ^ 0x1; ppu.SetMirroring( (data & 0x10) ? Ppu::NMT_1 : Ppu::NMT_0 ); } NES_POKE_D(Ffe,42FF) { ppu.SetMirroring( (data & 0x10) ? Ppu::NMT_H : Ppu::NMT_V ); } NES_POKE_D(Ffe,4501) { irq->Update(); irq->unit.enabled = data & 0x1; irq->ClearIRQ(); } NES_POKE_D(Ffe,4502) { irq->Update(); irq->unit.count = (irq->unit.count & 0xFF00) | data; } NES_POKE_D(Ffe,4503) { irq->Update(); irq->unit.count = (irq->unit.count & 0x00FF) | (data << 8); irq->unit.enabled = true; irq->ClearIRQ(); } NES_POKE_D(Ffe,Prg_F3) { ppu.Update(); prg.SwapBank( data >> 3 ); chr.SwapBank( data & 0x7 ); } NES_POKE_D(Ffe,Prg_F4) { ppu.Update(); if (mode || chr.Source(0).Writable()) { prg.SwapBank( data >> 2 ); data &= 0x3; } chr.Source( mode ).SwapBank( data ); } void Ffe::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) { if (irq) irq->VSync(); } Board::Sync( event, controllers ); } } } } nestopia-1.51.1/source/core/board/NstBoardFfe.hpp000066400000000000000000000044621411157722000216140ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_FFE_H #define NST_BOARD_FFE_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { class Ffe : public Board { public: explicit Ffe(const Context&); private: ~Ffe(); void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Sync(Event,Input::Controllers*); NES_DECL_POKE( 42FC ); NES_DECL_POKE( 42FD ); NES_DECL_POKE( 42FE ); NES_DECL_POKE( 42FF ); NES_DECL_POKE( 43FC ); NES_DECL_POKE( 43FD ); NES_DECL_POKE( 43FE ); NES_DECL_POKE( 43FF ); NES_DECL_POKE( 4501 ); NES_DECL_POKE( 4502 ); NES_DECL_POKE( 4503 ); NES_DECL_POKE( Prg_F3 ); NES_DECL_POKE( Prg_F4 ); NES_DECL_POKE( Prg_X ); struct Irq { void Reset(bool); bool Clock(); uint count; ibool enabled; const uint clock; explicit Irq(uint c) : clock(c) {} }; struct Trainer { explicit Trainer(const Ram&); enum { SIZE = 512 }; byte data[SIZE]; const bool available; }; Timer::M2* const irq; uint mode; const Trainer trainer; }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardFujiya.cpp000066400000000000000000000044351411157722000223360ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardFujiya.hpp" namespace Nes { namespace Core { namespace Boards { namespace Fujiya { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Standard::SubReset(bool) { reg = 0x00; Map( 0x6502U, &Standard::Poke_7000 ); Map( 0x7000U, &Standard::Poke_7000 ); Map( 0x7001U, &Standard::Peek_7001 ); Map( 0x7777U, &Standard::Peek_7001 ); } void Standard::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'F','U','A'>::V) ); if (baseChunk == AsciiId<'F','U','A'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) reg = state.Read8() & 0x80; state.End(); } } } void Standard::SubSave(State::Saver& state) const { state.Begin( AsciiId<'F','U','A'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( reg ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Standard,7000) { reg = data << 1 & 0x80; } NES_PEEK_A(Standard,7001) { return reg | (address >> 8 & 0x7F); } } } } } nestopia-1.51.1/source/core/board/NstBoardFujiya.hpp000066400000000000000000000031011411157722000223300ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_FUJIYA_H #define NST_BOARD_FUJIYA_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Fujiya { class Standard : public Board { public: explicit Standard(const Context& c) : Board(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); NES_DECL_POKE( 7000 ); NES_DECL_PEEK( 7001 ); uint reg; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardFukutake.cpp000066400000000000000000000050561411157722000226660ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstBoard.hpp" #include "NstBoardFukutake.hpp" namespace Nes { namespace Core { namespace Boards { namespace Fukutake { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Sbx::SubReset(const bool hard) { Map( 0x4200U, 0x4201U, &Sbx::Peek_4200 ); Map( 0x4202U, &Sbx::Peek_4202 ); Map( 0x4203U, &Sbx::Peek_4200 ); Map( 0x4204U, 0x43FFU, &Sbx::Peek_4204 ); for (uint i=0x4200; i < 0x4400; i += 0x2) { Map( i + 0x0, &Sbx::Poke_4200 ); Map( i + 0x1, PRG_SWAP_16K_0 ); } if (board.GetWram() >= SIZE_1K) Map( 0x4400U, 0x4EFFU, &Sbx::Peek_4400, &Sbx::Poke_4400 ); Map( 0x6000U, 0x7FFFU, &Sbx::Peek_6000 ); if (hard) { wrk.Source(1).SwapBank(0); prg.SwapBanks(0,0); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK(Sbx,4200) { return 0x00; } NES_PEEK(Sbx,4202) { return 0x40; } NES_PEEK(Sbx,4204) { return 0xFF; } NES_POKE_D(Sbx,4200) { wrk.Source(1).SwapBank( data >> 6 ); } NES_PEEK_A(Sbx,4400) { return *wrk.Source(0).Mem(address - 0x4400); } NES_POKE_AD(Sbx,4400) { *wrk.Source(0).Mem(address - 0x4400) = data; } NES_PEEK_A(Sbx,6000) { return wrk[0][address - 0x6000]; } } } } } nestopia-1.51.1/source/core/board/NstBoardFukutake.hpp000066400000000000000000000031511411157722000226650ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_FUKUTAKE_H #define NST_BOARD_FUKUTAKE_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Fukutake { class Sbx : public Board { public: explicit Sbx(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_PEEK( 4200 ); NES_DECL_POKE( 4200 ); NES_DECL_PEEK( 4202 ); NES_DECL_PEEK( 4204 ); NES_DECL_PEEK( 4400 ); NES_DECL_POKE( 4400 ); NES_DECL_PEEK( 6000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardFutureMedia.cpp000066400000000000000000000075311411157722000233210ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstTimer.hpp" #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardFutureMedia.hpp" namespace Nes { namespace Core { namespace Boards { namespace FutureMedia { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Standard::Standard(const Context& c) : Board(c), irq(*c.cpu,*c.ppu) {} void Standard::Irq::Reset(bool) { enabled = false; count = 0; latch = 0; } void Standard::SubReset(bool) { irq.Reset( true ); Map( 0x8000U, PRG_SWAP_8K_0 ); Map( 0x8001U, PRG_SWAP_8K_1 ); Map( 0x8002U, PRG_SWAP_8K_2 ); Map( 0x8003U, PRG_SWAP_8K_3 ); Map( 0xA000U, CHR_SWAP_1K_0 ); Map( 0xA001U, CHR_SWAP_1K_1 ); Map( 0xA002U, CHR_SWAP_1K_2 ); Map( 0xA003U, CHR_SWAP_1K_3 ); Map( 0xA004U, CHR_SWAP_1K_4 ); Map( 0xA005U, CHR_SWAP_1K_5 ); Map( 0xA006U, CHR_SWAP_1K_6 ); Map( 0xA007U, CHR_SWAP_1K_7 ); Map( 0xC001U, &Standard::Poke_C001 ); Map( 0xC002U, &Standard::Poke_C002 ); Map( 0xC003U, &Standard::Poke_C003 ); Map( 0xD000U, NMT_SWAP_HV ); Map( 0xE000U, &Standard::Poke_E000 ); } void Standard::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'F','D','A'>::V) ); if (baseChunk == AsciiId<'F','D','A'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'I','R','Q'>::V) { State::Loader::Data<3> data( state ); irq.unit.enabled = data[0] & 0x1; irq.unit.latch = data[1]; irq.unit.count = data[2]; } state.End(); } } } void Standard::SubSave(State::Saver& state) const { const byte data[3] = { irq.unit.enabled ? 0x1 : 0x0, irq.unit.latch, irq.unit.count }; state.Begin( AsciiId<'F','D','A'>::V ).Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif bool Standard::Irq::Clock() { return (enabled && count && !--count); } NES_POKE_D(Standard,C001) { irq.Update(); irq.unit.latch = data; } NES_POKE(Standard,C002) { cpu.ClearIRQ(); } NES_POKE(Standard,C003) { irq.Update(); irq.unit.count = irq.unit.latch; } NES_POKE_D(Standard,E000) { irq.Update(); irq.unit.enabled = data & 0x1; } void Standard::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardFutureMedia.hpp000066400000000000000000000036111411157722000233210ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_FUTUREMEDIA_H #define NST_BOARD_FUTUREMEDIA_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace FutureMedia { class Standard : public Board { public: explicit Standard(const Context&); private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Sync(Event,Input::Controllers*); NES_DECL_POKE( C001 ); NES_DECL_POKE( C002 ); NES_DECL_POKE( C003 ); NES_DECL_POKE( E000 ); struct Irq { void Reset(bool); bool Clock(); enum { CLOCK_FILTER = 16 }; ibool enabled; uint count; uint latch; }; Timer::A12 irq; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardFxRom.hpp000066400000000000000000000025411411157722000221430ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_FXROM_H #define NST_BOARD_FXROM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardMmc4.hpp" namespace Nes { namespace Core { namespace Boards { class FxRom : public Mmc4 { public: explicit FxRom(const Context& c) : Mmc4(c) {} }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardGouder.cpp000066400000000000000000000103161411157722000223270ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardGouder.hpp" namespace Nes { namespace Core { namespace Boards { namespace Gouder { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void G37017::SubReset(const bool hard) { if (hard) { regs.select = 0; for (uint i=0; i < 4; ++i) regs.buffer[i] = 0; } Mmc3::SubReset( hard ); Map( 0x4800U, 0x4FFFU, &G37017::Poke_4800 ); Map( 0x5000U, 0x57FFU, &G37017::Poke_5000 ); Map( 0x5800U, 0x5FFFU, &G37017::Peek_5800, &G37017::Poke_5800 ); } void G37017::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'G','D','R'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { state.Read( regs.buffer ); regs.select = state.Read8(); } state.End(); } } } void G37017::SubSave(State::Saver& state) const { state.Begin( AsciiId<'G','D','R'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( regs.buffer ).Write8( regs.select ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void NST_FASTCALL G37017::UpdatePrg(uint,uint) { // controlled by $4800..$4FFF } NES_POKE_D(G37017,4800) { prg.SwapBank( (data & 0x1) | (data >> 3 & 0x2) ); } NES_POKE_D(G37017,5000) { regs.select = data; } NES_POKE_AD(G37017,5800) { static const byte lut[256] = { 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x49,0x19,0x09,0x59,0x49,0x19,0x09, 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x51,0x41,0x11,0x01,0x51,0x41,0x11,0x01, 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x49,0x19,0x09,0x59,0x49,0x19,0x09, 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x51,0x41,0x11,0x01,0x51,0x41,0x11,0x01, 0x00,0x10,0x40,0x50,0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x08,0x18,0x48,0x58,0x08,0x18,0x48,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x10,0x40,0x50,0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x08,0x18,0x48,0x58,0x08,0x18,0x48,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x58,0x48,0x18,0x08,0x58,0x48,0x18,0x08, 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x50,0x40,0x10,0x00,0x50,0x40,0x10,0x00, 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x58,0x48,0x18,0x08,0x58,0x48,0x18,0x08, 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x50,0x40,0x10,0x00,0x50,0x40,0x10,0x00, 0x01,0x11,0x41,0x51,0x01,0x11,0x41,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x09,0x19,0x49,0x59,0x09,0x19,0x49,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x01,0x11,0x41,0x51,0x01,0x11,0x41,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x09,0x19,0x49,0x59,0x09,0x19,0x49,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; regs.buffer[address & 0x3] = data ^ lut[regs.select]; } NES_PEEK_A(G37017,5800) { return regs.buffer[address & 0x3]; } } } } } nestopia-1.51.1/source/core/board/NstBoardGouder.hpp000066400000000000000000000033451411157722000223400ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_GOUDER_H #define NST_BOARD_GOUDER_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Gouder { class G37017 : public Mmc3 { public: explicit G37017(const Context& c) : Mmc3(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void NST_FASTCALL UpdatePrg(uint,uint); NES_DECL_POKE( 4800 ); NES_DECL_POKE( 5000 ); NES_DECL_POKE( 5800 ); NES_DECL_PEEK( 5800 ); struct { uint select; byte buffer[4]; } regs; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardGxRom.cpp000066400000000000000000000027671411157722000221510ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardGxRom.hpp" namespace Nes { namespace Core { namespace Boards { void GxRom::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &GxRom::Poke_8000 ); if (hard) prg.SwapBank(0); } NES_POKE_AD(GxRom,8000) { ppu.Update(); data = GetBusData(address,data); chr.SwapBank( data ); prg.SwapBank( data >> 4 ); } } } } nestopia-1.51.1/source/core/board/NstBoardGxRom.hpp000066400000000000000000000026151411157722000221460ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_GXROM_H #define NST_BOARD_GXROM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { class GxRom : public Board { public: explicit GxRom(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardHenggedianzi.cpp000066400000000000000000000037301411157722000235000ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardHenggedianzi.hpp" namespace Nes { namespace Core { namespace Boards { namespace Hengedianzi { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Standard::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &Standard::Poke_8000 ); if (hard) prg.SwapBank(0); } void Xjzb::SubReset(const bool hard) { Map( 0x5000U, 0x5FFFU, &Xjzb::Poke_5000 ); Map( 0x8000U, 0xFFFFU, NMT_SWAP_HV ); if (hard) prg.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Xjzb,5000) { prg.SwapBank( data >> 1 ); } NES_POKE_D(Standard,8000) { prg.SwapBank( data ); ppu.SetMirroring( (data >> 5 & 0x1) ? Ppu::NMT_H : Ppu::NMT_V ); } } } } } nestopia-1.51.1/source/core/board/NstBoardHenggedianzi.hpp000066400000000000000000000032251411157722000235040ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_HENGGEDIANZI_H #define NST_BOARD_HENGGEDIANZI_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Hengedianzi { class Standard : public Board { public: explicit Standard(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; class Xjzb : public Board { public: explicit Xjzb(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 5000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardHes.cpp000066400000000000000000000034301411157722000216200ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardHes.hpp" namespace Nes { namespace Core { namespace Boards { namespace Hes { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Standard::SubReset(const bool hard) { for (uint i=0x4100; i < 0x6000; i += 0x200) Map( i+0x00, i+0xFF, &Standard::Poke_4100 ); if (hard) prg.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Standard,4100) { ppu.SetMirroring( (data & 0x80) ? Ppu::NMT_V : Ppu::NMT_H ); prg.SwapBank( data >> 3 & 0x7 ); chr.SwapBank( (data >> 3 & 0x8) | (data & 0x7) ); } } } } } nestopia-1.51.1/source/core/board/NstBoardHes.hpp000066400000000000000000000026661411157722000216370ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_HES_H #define NST_BOARD_HES_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Hes { class Standard : public Board { public: explicit Standard(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 4100 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardHosenkan.cpp000066400000000000000000000074021411157722000226520ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardHosenkan.hpp" namespace Nes { namespace Core { namespace Boards { namespace Hosenkan { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Standard::Standard(const Context& c) : Board (c), irq (*c.cpu,*c.ppu,false) {} void Standard::SubReset(const bool hard) { if (hard) command = 0; irq.Reset( hard ); for (uint i=0x0000; i < 0x1000; i += 0x4) { Map( 0x8001 + i, NMT_SWAP_HV ); Map( 0xA000 + i, &Standard::Poke_A000 ); Map( 0xC000 + i, &Standard::Poke_C000 ); Map( 0xE003 + i, &Standard::Poke_E003 ); } } void Standard::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'H','S','N'>::V) ); if (baseChunk == AsciiId<'H','S','N'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: command = state.Read8(); break; case AsciiId<'I','R','Q'>::V: irq.unit.LoadState( state ); break; } state.End(); } } } void Standard::SubSave(State::Saver& state) const { state.Begin( AsciiId<'H','S','N'>::V ); state.Begin( AsciiId<'R','E','G'>::V ).Write8( command ).End(); irq.unit.SaveState( state, AsciiId<'I','R','Q'>::V ); state.End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Standard,A000) { command = data; } NES_POKE_D(Standard,C000) { ppu.Update(); switch (command & 0x7) { case 0x0: chr.SwapBank(data >> 1); break; case 0x1: chr.SwapBank(data); break; case 0x2: chr.SwapBank(data >> 1); break; case 0x3: chr.SwapBank(data); break; case 0x4: prg.SwapBank(data); break; case 0x5: prg.SwapBank(data); break; case 0x6: chr.SwapBank(data); break; case 0x7: chr.SwapBank(data); break; } } NES_POKE_D(Standard,E003) { irq.Update(); if (data) { irq.ClearIRQ(); irq.unit.Enable(); irq.unit.SetLatch( data ); irq.unit.Reload(); } else { irq.unit.Disable( cpu ); } } void Standard::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardHosenkan.hpp000066400000000000000000000032261411157722000226570ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_HOSENKAN_H #define NST_BOARD_HOSENKAN_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Hosenkan { class Standard : public Board { public: explicit Standard(const Context&); private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Sync(Event,Input::Controllers*); NES_DECL_POKE( A000 ); NES_DECL_POKE( C000 ); NES_DECL_POKE( E003 ); uint command; Mmc3::Irq<> irq; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardHxRom.hpp000066400000000000000000000025411411157722000221450ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_HXROM_H #define NST_BOARD_HXROM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardMmc6.hpp" namespace Nes { namespace Core { namespace Boards { class HxRom : public Mmc6 { public: explicit HxRom(const Context& c) : Mmc6(c) {} }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardInlNsf.cpp000066400000000000000000000051121411157722000222710ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardInlNsf.hpp" namespace Nes { namespace Core { namespace Boards { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void InlNsf::SubReset(const bool hard) { Map ( 0x5000U, 0x5FFFU, &InlNsf::Poke_5000 ); Map ( 0x8000U, 0xFFFFU, &InlNsf::Peek_8000 ); if (hard) { for (int i=0; i<8; ++i) regs[i] = 0; Bank( 7, 0xFF ); } } void InlNsf::SubSave(State::Saver& state) const { state.Begin( AsciiId<'I','N','L'>::V ); state.Begin( AsciiId<'R','E','G'>::V ).Write( regs ).End(); state.End(); } void InlNsf::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'I','N','L'>::V) ); if (baseChunk == AsciiId<'I','N','L'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: state.Read( regs ); break; } state.End(); } } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void InlNsf::Bank(uint slot, Data data) { slot = slot & 7; regs[slot] = data; } NES_POKE_AD(InlNsf,5000) { Bank(address & 7, data); } NES_PEEK_A(InlNsf,8000) { // Not an ideal way to do this, but Nestopia does not seem to support 4K banks directly? uint slot = (address >> 12) & 7; byte b = regs[slot]; prg.SwapBank( address & 0x6000, b >> 1 ); // 2 banks per 8k page. return prg.Peek( ((b & 1) << 12) | (address & 0x6FFF) ); // Read from 1/2 of the banks. } } } } nestopia-1.51.1/source/core/board/NstBoardInlNsf.hpp000066400000000000000000000030131411157722000222740ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_INLNSF_H #define NST_BOARD_INLNSF_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { class InlNsf : public Board { public: explicit InlNsf(const Context& c) : Board(c) {} private: NES_DECL_POKE( 5000 ); NES_DECL_PEEK( 8000 ); void Bank(uint slot, Data data); void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); protected: byte regs[8]; }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardIrem.hpp000066400000000000000000000024651411157722000220110ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_IREM_H #define NST_BOARD_IREM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardIremG101.hpp" #include "NstBoardIremH3001.hpp" #include "NstBoardIremLrog017.hpp" #include "NstBoardIremHolyDiver.hpp" #include "NstBoardIremKaiketsu.hpp" #endif nestopia-1.51.1/source/core/board/NstBoardIremG101.cpp000066400000000000000000000063101411157722000223260ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardIremG101.hpp" namespace Nes { namespace Core { namespace Boards { namespace Irem { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void G101::SubReset(const bool hard) { Map( 0x8000U, 0x8FFFU, &G101::Poke_8000 ); Map( 0x9000U, 0x9FFFU, &G101::Poke_9000 ); Map( 0xA000U, 0xAFFFU, PRG_SWAP_8K_1 ); for (uint i=0xB000; i < 0xC000; i += 0x8) { Map( i + 0x0, CHR_SWAP_1K_0 ); Map( i + 0x1, CHR_SWAP_1K_1 ); Map( i + 0x2, CHR_SWAP_1K_2 ); Map( i + 0x3, CHR_SWAP_1K_3 ); Map( i + 0x4, CHR_SWAP_1K_4 ); Map( i + 0x5, CHR_SWAP_1K_5 ); Map( i + 0x6, CHR_SWAP_1K_6 ); Map( i + 0x7, CHR_SWAP_1K_7 ); } if (hard) { regs[0] = 0; regs[1] = 0; prg.SwapBanks(0U,~0U,~1U,~0U); } } void G101::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'I','G','1'>::V) ); if (baseChunk == AsciiId<'I','G','1'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<2> data( state ); regs[0] = data[0]; regs[1] = data[1]; } state.End(); } } } void G101::SubSave(State::Saver& state) const { const byte data[2] = { regs[0], regs[1] }; state.Begin( AsciiId<'I','G','1'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void G101::UpdatePrg() { prg.SwapBank( (regs[1] & 0x2) ? ~1U : regs[0] ); prg.SwapBank( (regs[1] & 0x2) ? regs[0] : ~1U ); } NES_POKE_D(G101,8000) { regs[0] = data; UpdatePrg(); } NES_POKE_D(G101,9000) { regs[1] = data; UpdatePrg(); if (board == Type::IREM_G101A_0 || board == Type::IREM_G101A_1) ppu.SetMirroring( (data & 0x1) ? Ppu::NMT_H : Ppu::NMT_V ); } } } } } nestopia-1.51.1/source/core/board/NstBoardIremG101.hpp000066400000000000000000000031311411157722000223310ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_IREM_G101_H #define NST_BOARD_IREM_G101_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Irem { class G101 : public Board { public: explicit G101(const Context& c) : Board(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void UpdatePrg(); NES_DECL_POKE( 8000 ); NES_DECL_POKE( 9000 ); uint regs[2]; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardIremH3001.cpp000066400000000000000000000101551411157722000224130ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "../NstTimer.hpp" #include "NstBoardIremH3001.hpp" namespace Nes { namespace Core { namespace Boards { namespace Irem { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif H3001::H3001(const Context& c) : Board(c), irq(*c.cpu) {} void H3001::Irq::Reset(const bool hard) { if (hard) { enabled = false; count = 0; latch = 0; } } void H3001::SubReset(const bool hard) { irq.Reset( hard, true ); Map( 0x9001U, &H3001::Poke_9001 ); Map( 0x9003U, &H3001::Poke_9003 ); Map( 0x9004U, &H3001::Poke_9004 ); Map( 0x9005U, &H3001::Poke_9005 ); Map( 0x9006U, &H3001::Poke_9006 ); Map( 0x8000U, PRG_SWAP_8K_0 ); Map( 0xA000U, PRG_SWAP_8K_1 ); Map( 0xC000U, PRG_SWAP_8K_2 ); Map( 0xB000U, CHR_SWAP_1K_0 ); Map( 0xB001U, CHR_SWAP_1K_1 ); Map( 0xB002U, CHR_SWAP_1K_2 ); Map( 0xB003U, CHR_SWAP_1K_3 ); Map( 0xB004U, CHR_SWAP_1K_4 ); Map( 0xB005U, CHR_SWAP_1K_5 ); Map( 0xB006U, CHR_SWAP_1K_6 ); Map( 0xB007U, CHR_SWAP_1K_7 ); } void H3001::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'I','H','3'>::V) ); if (baseChunk == AsciiId<'I','H','3'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'I','R','Q'>::V) { State::Loader::Data<5> data( state ); irq.unit.enabled = data[0] & 0x1; irq.unit.latch = data[1] | data[2] << 8; irq.unit.count = data[3] | data[4] << 8; } state.End(); } } } void H3001::SubSave(State::Saver& state) const { const byte data[5] = { irq.unit.enabled ? 0x1 : 0x0, irq.unit.latch & 0xFF, irq.unit.latch >> 8, irq.unit.count & 0xFF, irq.unit.count >> 8 }; state.Begin( AsciiId<'I','H','3'>::V ).Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(H3001,9001) { ppu.SetMirroring( (data & 0x80) ? Ppu::NMT_H : Ppu::NMT_V ); } NES_POKE_D(H3001,9003) { irq.Update(); irq.unit.enabled = data & 0x80; irq.ClearIRQ(); } NES_POKE(H3001,9004) { irq.Update(); irq.unit.count = irq.unit.latch; irq.ClearIRQ(); } NES_POKE_D(H3001,9005) { irq.Update(); irq.unit.latch = (irq.unit.latch & 0x00FF) | data << 8; } NES_POKE_D(H3001,9006) { irq.Update(); irq.unit.latch = (irq.unit.latch & 0xFF00) | data << 0; } bool H3001::Irq::Clock() { if (enabled && count && !--count) { enabled = false; return true; } return false; } void H3001::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardIremH3001.hpp000066400000000000000000000035111411157722000224160ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_IREM_H3001_H #define NST_BOARD_IREM_H3001_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Irem { class H3001 : public Board { public: explicit H3001(const Context&); private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Sync(Event,Input::Controllers*); NES_DECL_POKE( 9001 ); NES_DECL_POKE( 9003 ); NES_DECL_POKE( 9004 ); NES_DECL_POKE( 9005 ); NES_DECL_POKE( 9006 ); struct Irq { void Reset(bool); bool Clock(); ibool enabled; uint count; uint latch; }; Timer::M2 irq; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardIremHolyDiver.cpp000066400000000000000000000032641411157722000236300ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardIremHolyDiver.hpp" namespace Nes { namespace Core { namespace Boards { namespace Irem { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void HolyDiver::SubReset(bool) { Map( 0x8000U, 0xFFFFU, &HolyDiver::Poke_8000 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(HolyDiver,8000) { data = GetBusData(address,data); ppu.SetMirroring( (data & 0x8) ? Ppu::NMT_V : Ppu::NMT_H ); prg.SwapBank( data ); chr.SwapBank( data >> 4 ); } } } } } nestopia-1.51.1/source/core/board/NstBoardIremHolyDiver.hpp000066400000000000000000000027171411157722000236370ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_IREM_HOLYDIVER_H #define NST_BOARD_IREM_HOLYDIVER_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Irem { class HolyDiver : public Board { public: explicit HolyDiver(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardIremKaiketsu.cpp000066400000000000000000000033171411157722000235020ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardIremKaiketsu.hpp" namespace Nes { namespace Core { namespace Boards { namespace Irem { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Kaiketsu::SubReset(const bool hard) { Map( 0x8000U, 0xBFFFU, &Kaiketsu::Poke_8000 ); if (hard) prg.SwapBanks( ~0U, 0U ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(Kaiketsu,8000) { data = GetBusData(address,data); prg.SwapBank( data ); ppu.SetMirroring( (data & 0x80) ? Ppu::NMT_V : Ppu::NMT_H ); } } } } } nestopia-1.51.1/source/core/board/NstBoardIremKaiketsu.hpp000066400000000000000000000027131411157722000235060ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_IREM_KAIKETSU_H #define NST_BOARD_IREM_KAIKETSU_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Irem { class Kaiketsu : public Board { public: explicit Kaiketsu(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardIremLrog017.cpp000066400000000000000000000035331411157722000230550ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardIremLrog017.hpp" namespace Nes { namespace Core { namespace Boards { namespace Irem { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Lrog017::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &Lrog017::Poke_8000 ); chr.Source(1).SwapBank( 0 ); chr.Source(1).SwapBank( 1 ); chr.Source(1).SwapBank( 2 ); if (hard) prg.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(Lrog017,8000) { ppu.Update(); data = GetBusData(address,data); prg.SwapBank(data); chr.SwapBank(data >> 4); } } } } } nestopia-1.51.1/source/core/board/NstBoardIremLrog017.hpp000066400000000000000000000027071411157722000230640ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_IREM_LROG017_H #define NST_BOARD_IREM_LROG017_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Irem { class Lrog017 : public Board { public: explicit Lrog017(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardJaleco.hpp000066400000000000000000000056621411157722000223140ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_JALECO_H #define NST_BOARD_JALECO_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardKonamiVrc1.hpp" #include "NstBoardJalecoJf11.hpp" #include "NstBoardJalecoJf13.hpp" #include "NstBoardJalecoJf16.hpp" #include "NstBoardJalecoJf17.hpp" #include "NstBoardJalecoJf19.hpp" #include "NstBoardJalecoSs88006.hpp" namespace Nes { namespace Core { namespace Boards { namespace Jaleco { typedef NRom Jf01; typedef NRom Jf02; typedef NRom Jf03; typedef NRom Jf04; typedef Discrete::Ic74x139x74 Jf05; typedef Discrete::Ic74x139x74 Jf06; typedef Discrete::Ic74x139x74 Jf07; typedef Discrete::Ic74x139x74 Jf08; typedef Discrete::Ic74x139x74 Jf09; typedef Discrete::Ic74x139x74 Jf10; typedef Jf11 Jf12; typedef Jf11 Jf14; typedef UxRom Jf15; typedef UxRom Jf18; typedef Konami::Vrc1 Jf20; typedef Jf19 Jf21; typedef Konami::Vrc1 Jf22; typedef Ss88006 Jf23; typedef Ss88006 Jf24; typedef Ss88006 Jf25; typedef Jf17 Jf26; typedef Ss88006 Jf27; typedef Jf17 Jf28; typedef Ss88006 Jf29; typedef Ss88006 Jf30; typedef Ss88006 Jf31; typedef Ss88006 Jf32; typedef Ss88006 Jf33; typedef Ss88006 Jf34; typedef Ss88006 Jf35; typedef Ss88006 Jf36; typedef Ss88006 Jf37; typedef Ss88006 Jf38; typedef UxRom Jf39; typedef Ss88006 Jf40; typedef Ss88006 Jf41; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardJalecoJf11.cpp000066400000000000000000000032241411157722000227210ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardJalecoJf11.hpp" namespace Nes { namespace Core { namespace Boards { namespace Jaleco { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Jf11::SubReset(const bool hard) { Map( 0x6000U, 0x7FFFU, &Jf11::Poke_6000 ); if (hard) prg.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Jf11,6000) { ppu.Update(); chr.SwapBank( data ); prg.SwapBank( data >> 4 ); } } } } } nestopia-1.51.1/source/core/board/NstBoardJalecoJf11.hpp000066400000000000000000000027011411157722000227250ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_JALECO_JF11_H #define NST_BOARD_JALECO_JF11_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Jaleco { class Jf11 : public Board { public: explicit Jf11(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 6000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardJalecoJf13.cpp000066400000000000000000000043121411157722000227220ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "../NstSoundPlayer.hpp" #include "NstBoardJalecoJf13.hpp" namespace Nes { namespace Core { namespace Boards { namespace Jaleco { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Jf13::Jf13(const Context& c) : Board (c), sound (Sound::Player::Create(*c.apu,c.chips,L"D7756C",board == Type::JALECO_JF13 ? Sound::Player::GAME_MOERO_PRO_YAKYUU : Sound::Player::GAME_UNKNOWN,32)) { } Jf13::~Jf13() { Sound::Player::Destroy( sound ); } void Jf13::SubReset(const bool hard) { Map( 0x6000U, &Jf13::Poke_6000 ); if (sound) Map( 0x7000U, &Jf13::Poke_7000 ); if (hard) prg.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Jf13,6000) { ppu.Update(); prg.SwapBank( data >> 4 & 0x3 ); chr.SwapBank( (data >> 4 & 0x4) | (data & 0x3) ); } NES_POKE_D(Jf13,7000) { NST_ASSERT( sound ); if ((data & 0x30) == 0x20) sound->Play( data & 0x1F ); } } } } } nestopia-1.51.1/source/core/board/NstBoardJalecoJf13.hpp000066400000000000000000000030571411157722000227340ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_JALECO_JF13_H #define NST_BOARD_JALECO_JF13_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Sound { class Player; } namespace Boards { namespace Jaleco { class Jf13 : public Board { public: explicit Jf13(const Context&); private: ~Jf13(); void SubReset(bool); NES_DECL_POKE( 6000 ); NES_DECL_POKE( 7000 ); Sound::Player* const sound; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardJalecoJf16.cpp000066400000000000000000000032441411157722000227300ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardJalecoJf16.hpp" namespace Nes { namespace Core { namespace Boards { namespace Jaleco { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Jf16::SubReset(bool) { Map( 0x8000U, 0xFFFFU, &Jf16::Poke_8000 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(Jf16,8000) { data = GetBusData(address,data); ppu.SetMirroring( (data & 0x8) ? Ppu::NMT_1 : Ppu::NMT_0 ); prg.SwapBank( data ); chr.SwapBank( data >> 4 ); } } } } } nestopia-1.51.1/source/core/board/NstBoardJalecoJf16.hpp000066400000000000000000000027011411157722000227320ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_JALECO_JF16_H #define NST_BOARD_JALECO_JF16_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Jaleco { class Jf16 : public Board { public: explicit Jf16(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardJalecoJf17.cpp000066400000000000000000000041511411157722000227270ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "../NstSoundPlayer.hpp" #include "NstBoardJalecoJf17.hpp" namespace Nes { namespace Core { namespace Boards { namespace Jaleco { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Jf17::Jf17(const Context& c) : Board (c), sound (Sound::Player::Create(*c.apu,c.chips,L"D7756C",board == Type::JALECO_JF17 ? Sound::Player::GAME_MOERO_PRO_TENNIS : Sound::Player::GAME_UNKNOWN,32)) { } Jf17::~Jf17() { Sound::Player::Destroy( sound ); } void Jf17::SubReset(bool) { Map( 0x8000U, 0xFFFFU, &Jf17::Poke_8000 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(Jf17,8000) { data = GetBusData(address,data); if (data & 0x40) { ppu.Update(); chr.SwapBank( data & 0xF ); } if (data & 0x80) prg.SwapBank( data & 0xF ); if (sound && (data & 0x30) == 0x20) sound->Play( address & 0x1F ); } } } } } nestopia-1.51.1/source/core/board/NstBoardJalecoJf17.hpp000066400000000000000000000031141411157722000227320ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_JALECO_JF17_H #define NST_BOARD_JALECO_JF17_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Sound { class Player; } namespace Boards { namespace Jaleco { class Jf17 : public Board { public: explicit Jf17(const Context&); private: ~Jf17(); void SubReset(bool); NES_DECL_POKE( 6000 ); NES_DECL_POKE( 7000 ); NES_DECL_POKE( 8000 ); Sound::Player* const sound; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardJalecoJf19.cpp000066400000000000000000000041541411157722000227340ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "../NstSoundPlayer.hpp" #include "NstBoardJalecoJf19.hpp" namespace Nes { namespace Core { namespace Boards { namespace Jaleco { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Jf19::Jf19(const Context& c) : Board (c), sound (Sound::Player::Create(*c.apu,c.chips,L"D7756C",board == Type::JALECO_JF19 ? Sound::Player::GAME_MOERO_PRO_YAKYUU_88 : Sound::Player::GAME_UNKNOWN,32)) { } Jf19::~Jf19() { Sound::Player::Destroy( sound ); } void Jf19::SubReset(bool) { Map( 0x8000U, 0xFFFFU, &Jf19::Poke_8000 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(Jf19,8000) { data = GetBusData(address,data); if (data & 0x40) { ppu.Update(); chr.SwapBank( data & 0xF ); } if (data & 0x80) prg.SwapBank( data & 0xF ); if (sound && (data & 0x30) == 0x20) sound->Play( address & 0x1F ); } } } } } nestopia-1.51.1/source/core/board/NstBoardJalecoJf19.hpp000066400000000000000000000031141411157722000227340ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_JALECO_JF19_H #define NST_BOARD_JALECO_JF19_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Sound { class Player; } namespace Boards { namespace Jaleco { class Jf19 : public Board { public: explicit Jf19(const Context&); private: ~Jf19(); void SubReset(bool); NES_DECL_POKE( 6000 ); NES_DECL_POKE( 7000 ); NES_DECL_POKE( 8000 ); Sound::Player* const sound; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardJalecoSs88006.cpp000066400000000000000000000221671411157722000232220ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "../NstTimer.hpp" #include "../NstSoundPlayer.hpp" #include "NstBoardJalecoSs88006.hpp" namespace Nes { namespace Core { namespace Boards { namespace Jaleco { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Ss88006::Irq::Reset(const bool hard) { if (hard) { mask = 0xFFFF; count = 0; latch = 0; } } Ss88006::Ss88006(const Context& c) : Board (c), irq (*c.cpu), sound ( Sound::Player::Create ( *c.apu, c.chips, L"D7756C", board == Type::JALECO_JF24 ? Sound::Player::GAME_TERAO_NO_DOSUKOI_OOZUMOU : board == Type::JALECO_JF23 ? Sound::Player::GAME_MOERO_PRO_YAKYUU_88 : board == Type::JALECO_JF29 ? Sound::Player::GAME_MOERO_PRO_YAKYUU_88 : board == Type::JALECO_JF33 ? Sound::Player::GAME_MOERO_PRO_YAKYUU_88 : Sound::Player::GAME_UNKNOWN, 32 ) ) {} Ss88006::~Ss88006() { Sound::Player::Destroy( sound ); } void Ss88006::SubReset(const bool hard) { if (hard) wrk.Source().SetSecurity( false, false ); reg = 0; irq.Reset( hard, hard ? false : irq.Connected() ); for (uint i=0x0000; i < 0x1000; i += 0x4) { Map( 0x8000 + i, &Ss88006::Poke_8000 ); Map( 0x8001 + i, &Ss88006::Poke_8001 ); Map( 0x8002 + i, &Ss88006::Poke_8002 ); Map( 0x8003 + i, &Ss88006::Poke_8003 ); Map( 0x9000 + i, &Ss88006::Poke_9000 ); Map( 0x9001 + i, &Ss88006::Poke_9001 ); Map( 0x9002 + i, &Ss88006::Poke_9002 ); Map( 0xA000 + i, &Ss88006::Poke_A000 ); Map( 0xA001 + i, &Ss88006::Poke_A001 ); Map( 0xA002 + i, &Ss88006::Poke_A002 ); Map( 0xA003 + i, &Ss88006::Poke_A003 ); Map( 0xB000 + i, &Ss88006::Poke_B000 ); Map( 0xB001 + i, &Ss88006::Poke_B001 ); Map( 0xB002 + i, &Ss88006::Poke_B002 ); Map( 0xB003 + i, &Ss88006::Poke_B003 ); Map( 0xC000 + i, &Ss88006::Poke_C000 ); Map( 0xC001 + i, &Ss88006::Poke_C001 ); Map( 0xC002 + i, &Ss88006::Poke_C002 ); Map( 0xC003 + i, &Ss88006::Poke_C003 ); Map( 0xD000 + i, &Ss88006::Poke_D000 ); Map( 0xD001 + i, &Ss88006::Poke_D001 ); Map( 0xD002 + i, &Ss88006::Poke_D002 ); Map( 0xD003 + i, &Ss88006::Poke_D003 ); Map( 0xE000 + i, &Ss88006::Poke_E000 ); Map( 0xE001 + i, &Ss88006::Poke_E001 ); Map( 0xE002 + i, &Ss88006::Poke_E002 ); Map( 0xE003 + i, &Ss88006::Poke_E003 ); Map( 0xF000 + i, &Ss88006::Poke_F000 ); Map( 0xF001 + i, &Ss88006::Poke_F001 ); Map( 0xF002 + i, NMT_SWAP_HV01 ); if (sound) Map( 0xF003 + i, &Ss88006::Poke_F003 ); } } void Ss88006::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'J','S','8'>::V) ); if (sound) sound->Stop(); if (baseChunk == AsciiId<'J','S','8'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'I','R','Q'>::V: { State::Loader::Data<5> data( state ); irq.Connect( data[0] & 0x1 ); if (data[0] & 0x8) irq.unit.mask = 0x000F; else if (data[0] & 0x4) irq.unit.mask = 0x00FF; else if (data[0] & 0x2) irq.unit.mask = 0x0FFF; else irq.unit.mask = 0xFFFF; irq.unit.latch = data[1] | data[2] << 8; irq.unit.count = data[3] | data[4] << 8; break; } case AsciiId<'R','E','G'>::V: NST_VERIFY( sound ); reg = state.Read8(); break; } state.End(); } } } void Ss88006::SubSave(State::Saver& state) const { state.Begin( AsciiId<'J','S','8'>::V ); const byte data[5] = { (irq.Connected() ? 0x1U : 0x0U) | ( irq.unit.mask == 0x000F ? 0x8U : irq.unit.mask == 0x00FF ? 0x4U : irq.unit.mask == 0x0FFF ? 0x2U : 0x0U ), irq.unit.latch & 0xFF, irq.unit.latch >> 8, irq.unit.count & 0xFF, irq.unit.count >> 8 }; state.Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End(); if (sound) state.Begin( AsciiId<'R','E','G'>::V ).Write8( reg ).End(); state.End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif template void Ss88006::SwapPrg(const uint address,const uint data) { prg.SwapBank( address, (prg.GetBank(address) & MASK) | (data & 0xF) << SHIFT ); } NES_POKE_D(Ss88006,8000) { SwapPrg<0xF0,0>( 0x0000, data ); } NES_POKE_D(Ss88006,8001) { SwapPrg<0x0F,4>( 0x0000, data ); } NES_POKE_D(Ss88006,8002) { SwapPrg<0xF0,0>( 0x2000, data ); } NES_POKE_D(Ss88006,8003) { SwapPrg<0x0F,4>( 0x2000, data ); } NES_POKE_D(Ss88006,9000) { SwapPrg<0xF0,0>( 0x4000, data ); } NES_POKE_D(Ss88006,9001) { SwapPrg<0x0F,4>( 0x4000, data ); } NES_POKE_D(Ss88006,9002) { NST_VERIFY( data == 0x3 || data == 0x0 ); wrk.Source().SetSecurity( data & 0x1, data & 0x2 ); } template void Ss88006::SwapChr(const uint address,const uint data) const { ppu.Update(); chr.SwapBank( address, (chr.GetBank(address) & MASK) | (data & 0xF) << SHIFT ); } NES_POKE_D(Ss88006,A000) { SwapChr<0xF0,0>( 0x0000, data ); } NES_POKE_D(Ss88006,A001) { SwapChr<0x0F,4>( 0x0000, data ); } NES_POKE_D(Ss88006,A002) { SwapChr<0xF0,0>( 0x0400, data ); } NES_POKE_D(Ss88006,A003) { SwapChr<0x0F,4>( 0x0400, data ); } NES_POKE_D(Ss88006,B000) { SwapChr<0xF0,0>( 0x0800, data ); } NES_POKE_D(Ss88006,B001) { SwapChr<0x0F,4>( 0x0800, data ); } NES_POKE_D(Ss88006,B002) { SwapChr<0xF0,0>( 0x0C00, data ); } NES_POKE_D(Ss88006,B003) { SwapChr<0x0F,4>( 0x0C00, data ); } NES_POKE_D(Ss88006,C000) { SwapChr<0xF0,0>( 0x1000, data ); } NES_POKE_D(Ss88006,C001) { SwapChr<0x0F,4>( 0x1000, data ); } NES_POKE_D(Ss88006,C002) { SwapChr<0xF0,0>( 0x1400, data ); } NES_POKE_D(Ss88006,C003) { SwapChr<0x0F,4>( 0x1400, data ); } NES_POKE_D(Ss88006,D000) { SwapChr<0xF0,0>( 0x1800, data ); } NES_POKE_D(Ss88006,D001) { SwapChr<0x0F,4>( 0x1800, data ); } NES_POKE_D(Ss88006,D002) { SwapChr<0xF0,0>( 0x1C00, data ); } NES_POKE_D(Ss88006,D003) { SwapChr<0x0F,4>( 0x1C00, data ); } NES_POKE_D(Ss88006,E000) { irq.Update(); irq.unit.latch = (irq.unit.latch & 0xFFF0) | (data & 0xF) << 0; } NES_POKE_D(Ss88006,E001) { irq.Update(); irq.unit.latch = (irq.unit.latch & 0xFF0F) | (data & 0xF) << 4; } NES_POKE_D(Ss88006,E002) { irq.Update(); irq.unit.latch = (irq.unit.latch & 0xF0FF) | (data & 0xF) << 8; } NES_POKE_D(Ss88006,E003) { irq.Update(); irq.unit.latch = (irq.unit.latch & 0x0FFF) | (data & 0xF) << 12; } NES_POKE(Ss88006,F000) { irq.Update(); irq.unit.count = irq.unit.latch; irq.ClearIRQ(); } NES_POKE_D(Ss88006,F001) { irq.Update(); if (data & 0x8) irq.unit.mask = 0x000F; else if (data & 0x4) irq.unit.mask = 0x00FF; else if (data & 0x2) irq.unit.mask = 0x0FFF; else irq.unit.mask = 0xFFFF; irq.Connect( data & 0x1 ); irq.ClearIRQ(); } NES_POKE_D(Ss88006,F003) { NST_ASSERT( sound ); uint tmp = reg; reg = data; if ((data & 0x2) < (tmp & 0x2) && (data & 0x1D) == (tmp & 0x1D)) sound->Play( data >> 2 & 0x1F ); } bool Ss88006::Irq::Clock() { return (count & mask) && !(--count & mask); } void Ss88006::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardJalecoSs88006.hpp000066400000000000000000000054431411157722000232250ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_JALECO_SS88006_H #define NST_BOARD_JALECO_SS88006_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Sound { class Player; } namespace Boards { namespace Jaleco { class Ss88006 : public Board { public: explicit Ss88006(const Context&); private: ~Ss88006(); void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Sync(Event,Input::Controllers*); template void SwapPrg(uint,uint); template void SwapChr(uint,uint) const; NES_DECL_POKE( 8000 ); NES_DECL_POKE( 8001 ); NES_DECL_POKE( 8002 ); NES_DECL_POKE( 8003 ); NES_DECL_POKE( 9000 ); NES_DECL_POKE( 9001 ); NES_DECL_POKE( 9002 ); NES_DECL_POKE( A000 ); NES_DECL_POKE( A001 ); NES_DECL_POKE( A002 ); NES_DECL_POKE( A003 ); NES_DECL_POKE( B000 ); NES_DECL_POKE( B001 ); NES_DECL_POKE( B002 ); NES_DECL_POKE( B003 ); NES_DECL_POKE( C000 ); NES_DECL_POKE( C001 ); NES_DECL_POKE( C002 ); NES_DECL_POKE( C003 ); NES_DECL_POKE( D000 ); NES_DECL_POKE( D001 ); NES_DECL_POKE( D002 ); NES_DECL_POKE( D003 ); NES_DECL_POKE( E000 ); NES_DECL_POKE( E001 ); NES_DECL_POKE( E002 ); NES_DECL_POKE( E003 ); NES_DECL_POKE( F000 ); NES_DECL_POKE( F001 ); NES_DECL_POKE( F003 ); struct Irq { void Reset(bool); bool Clock(); uint mask; uint count; uint latch; }; Timer::M2 irq; uint reg; Sound::Player* const sound; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardJxRom.hpp000066400000000000000000000024301411157722000221440ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_JXROM_H #define NST_BOARD_JXROM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardSunsoftFme7.hpp" namespace Nes { namespace Core { namespace Boards { typedef Sunsoft::Fme7 JxRom; } } } #endif nestopia-1.51.1/source/core/board/NstBoardJyCompany.cpp000066400000000000000000000515201411157722000230150ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstTimer.hpp" #include "../NstDipSwitches.hpp" #include "NstBoard.hpp" #include "NstBoardJyCompany.hpp" namespace Nes { namespace Core { namespace Boards { namespace JyCompany { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Standard::CartSwitches::CartSwitches(uint d,bool l) : data(d), ppuLatched(l) {} inline bool Standard::CartSwitches::IsPpuLatched() const { return ppuLatched; } Standard::Irq::A12::A12(Irq& irq) : base(irq) {} Standard::Irq::M2::M2(Irq& irq) : base(irq) {} #if NST_MSVC >= 1200 #pragma warning( push ) #pragma warning( disable : 4355 ) #endif Standard::Irq::Irq(Cpu& cpu,Ppu& ppu) : a12(cpu,ppu,*this), m2(cpu,*this) {} #if NST_MSVC >= 1200 #pragma warning( pop ) #endif Standard::Standard(const Context& c) : Board (c), irq (*c.cpu,*c.ppu), cartSwitches ( board == Type::JYCOMPANY_TYPE_A ? DEFAULT_DIP_NMT_OFF : board == Type::JYCOMPANY_TYPE_B ? DEFAULT_DIP_NMT_CONTROLLED : DEFAULT_DIP_NMT_ON, board == Type::JYCOMPANY_TYPE_B ) { } void Standard::Regs::Reset() { mul[0] = 0; mul[1] = 0; tmp = 0; ctrl[0] = 0; ctrl[1] = 0; ctrl[2] = 0; ctrl[3] = 0; } void Standard::Banks::Reset() { for (uint i=0; i < 4; ++i) prg[i] = 0xFF; for (uint i=0; i < 8; ++i) chr[i] = 0xFFFF; for (uint i=0; i < 4; ++i) nmt[i] = 0x00; prg6 = NULL; chrLatch[0] = 0; chrLatch[1] = 4; } void Standard::Irq::A12::Reset(bool) { } void Standard::Irq::M2::Reset(bool) { } void Standard::Irq::Reset() { enabled = false; mode = 0; prescaler = 0; scale = 0xFF; count = 0; flip = 0; a12.Reset( true ); m2.Reset( true, true ); } void Standard::SubReset(bool) { for (uint i=0x5000; i < 0x5800; i += 0x4) Map( i, &Standard::Peek_5000 ); for (uint i=0x5800; i < 0x6000; i += 0x4) { cpu.Map( i + 0x0 ).Set( ®s, &Regs::Peek_5800, &Regs::Poke_5800 ); cpu.Map( i + 0x1 ).Set( ®s, &Regs::Peek_5801, &Regs::Poke_5801 ); cpu.Map( i + 0x3 ).Set( ®s, &Regs::Peek_5803, &Regs::Poke_5803 ); } Map( 0x6000U, 0x7FFFU, &Standard::Peek_6000 ); Map( 0x8000U, 0x8FFFU, &Standard::Poke_8000 ); Map( 0x9000U, 0x9FFFU, &Standard::Poke_9000 ); Map( 0xA000U, 0xAFFFU, &Standard::Poke_A000 ); for (uint i=0x0000; i < 0x1000; i += 0x8) { Map( 0xB000 + i, 0xB003 + i, &Standard::Poke_B000 ); Map( 0xB004 + i, 0xB007 + i, &Standard::Poke_B004 ); Map( 0xC000 + i, &Standard::Poke_C000 ); Map( 0xC001 + i, &Standard::Poke_C001 ); Map( 0xC002 + i, &Standard::Poke_C002 ); Map( 0xC003 + i, &Standard::Poke_C003 ); Map( 0xC004 + i, &Standard::Poke_C004 ); Map( 0xC005 + i, &Standard::Poke_C005 ); Map( 0xC006 + i, &Standard::Poke_C006 ); } for (uint i=0x0000; i < 0x1000; i += 0x4) { Map( 0xD000 + i, &Standard::Poke_D000 ); Map( 0xD001 + i, &Standard::Poke_D001 ); Map( 0xD002 + i, &Standard::Poke_D002 ); Map( 0xD003 + i, &Standard::Poke_D003 ); } regs.Reset(); banks.Reset(); irq.Reset(); ppu.SetHActiveHook( Hook(this,&Standard::Hook_HActive) ); ppu.SetHBlankHook( Hook(this,&Standard::Hook_HBlank) ); if (cartSwitches.IsPpuLatched()) chr.SetAccessor( this, &Standard::Access_Chr ); UpdatePrg(); UpdateExChr(); UpdateChr(); UpdateNmt(); } void Standard::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'J','Y','C'>::V) ); if (baseChunk == AsciiId<'J','Y','C'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: { State::Loader::Data<35> data( state ); regs.ctrl[0] = data[0]; regs.ctrl[1] = data[1]; regs.ctrl[2] = data[2]; regs.ctrl[3] = data[3]; regs.mul[0] = data[4]; regs.mul[1] = data[5]; regs.tmp = data[6]; banks.prg[0] = data[7]; banks.prg[1] = data[8]; banks.prg[2] = data[9]; banks.prg[3] = data[10]; banks.chr[0] = data[11] | data[12] << 8; banks.chr[1] = data[13] | data[14] << 8; banks.chr[2] = data[15] | data[16] << 8; banks.chr[3] = data[17] | data[18] << 8; banks.chr[4] = data[19] | data[20] << 8; banks.chr[5] = data[21] | data[22] << 8; banks.chr[6] = data[23] | data[24] << 8; banks.chr[7] = data[25] | data[26] << 8; banks.nmt[0] = data[27] | data[28] << 8; banks.nmt[1] = data[29] | data[30] << 8; banks.nmt[2] = data[31] | data[32] << 8; banks.nmt[3] = data[33] | data[34] << 8; UpdatePrg(); UpdateExChr(); UpdateChr(); UpdateNmt(); break; } case AsciiId<'L','A','T'>::V: NST_VERIFY( cartSwitches.IsPpuLatched() ); if (cartSwitches.IsPpuLatched()) { banks.chrLatch[0] = state.Read8(); banks.chrLatch[1] = banks.chrLatch[0] >> 3 & 0x7; banks.chrLatch[0] &= 0x7; UpdateChr(); } break; case AsciiId<'I','R','Q'>::V: { byte data[5]; state.Read( data ); irq.enabled = data[0] & 0x1U; irq.mode = data[1]; irq.prescaler = data[2]; irq.count = data[3]; irq.flip = data[4]; irq.scale = (irq.mode & Irq::MODE_SCALE_3BIT) ? 0x7 : 0xFF; break; } } state.End(); } } } void Standard::SubSave(State::Saver& state) const { state.Begin( AsciiId<'J','Y','C'>::V ); { const byte data[35] = { regs.ctrl[0], regs.ctrl[1], regs.ctrl[2], regs.ctrl[3], regs.mul[0], regs.mul[1], regs.tmp, banks.prg[0], banks.prg[1], banks.prg[2], banks.prg[3], banks.chr[0] & 0xFF, banks.chr[0] >> 8, banks.chr[1] & 0xFF, banks.chr[1] >> 8, banks.chr[2] & 0xFF, banks.chr[2] >> 8, banks.chr[3] & 0xFF, banks.chr[3] >> 8, banks.chr[4] & 0xFF, banks.chr[4] >> 8, banks.chr[5] & 0xFF, banks.chr[5] >> 8, banks.chr[6] & 0xFF, banks.chr[6] >> 8, banks.chr[7] & 0xFF, banks.chr[7] >> 8, banks.nmt[0] & 0xFF, banks.nmt[0] >> 8, banks.nmt[1] & 0xFF, banks.nmt[1] >> 8, banks.nmt[2] & 0xFF, banks.nmt[2] >> 8, banks.nmt[3] & 0xFF, banks.nmt[3] >> 8 }; state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End(); } if (cartSwitches.IsPpuLatched()) state.Begin( AsciiId<'L','A','T'>::V ).Write8( banks.chrLatch[0] | banks.chrLatch[1] << 3 ).End(); { const byte data[5] = { irq.enabled != 0, irq.mode, irq.prescaler & 0xFF, irq.count, irq.flip }; state.Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End(); } state.End(); } uint Standard::CartSwitches::NumDips() const { return 2; } uint Standard::CartSwitches::NumValues(uint i) const { NST_ASSERT( i < 2 ); return (i == 0) ? 4 : 3; } cstring Standard::CartSwitches::GetDipName(uint dip) const { NST_ASSERT( dip < 2 ); return (dip == 0) ? "Game Select" : "Extended Mirroring"; } cstring Standard::CartSwitches::GetValueName(uint dip,uint value) const { NST_ASSERT( dip < 2 ); if (dip == 0) { NST_ASSERT( value < 4 ); return (value == 0) ? "1" : (value == 1) ? "2" : (value == 2) ? "3" : "4"; } else { NST_ASSERT( value < 3 ); return (value == 0) ? "Off" : (value == 1) ? "Controlled" : "On"; } } uint Standard::CartSwitches::GetValue(uint dip) const { NST_ASSERT( dip < 2 ); if (dip == 0) return data >> 6; else return data & DIPSWITCH_NMT; } void Standard::CartSwitches::SetValue(uint dip,uint value) { NST_ASSERT( dip < 2 ); if (dip == 0) { NST_ASSERT( value < 4 ); data = (data & ~uint(DIPSWITCH_GAME)) | (value << 6); } else { NST_ASSERT( value < 3 ); data = (data & ~uint(DIPSWITCH_NMT)) | (value << 0); } } Standard::Device Standard::QueryDevice(DeviceType type) { if (type == DEVICE_DIP_SWITCHES) return &cartSwitches; else return Board::QueryDevice( type ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif inline uint Standard::CartSwitches::GetSetting() const { return data; } inline void Standard::Irq::Update() { a12.Update(); m2.Update(); } bool Standard::Irq::IsEnabled() const { return enabled && ( (mode & MODE_COUNT_ENABLE) == MODE_COUNT_DOWN || (mode & MODE_COUNT_ENABLE) == MODE_COUNT_UP ); } bool Standard::Irq::IsEnabled(uint checkMode) const { return (mode & MODE_SOURCE) == checkMode && IsEnabled(); } bool Standard::Irq::Clock() { NST_ASSERT( IsEnabled() ); if (mode & MODE_COUNT_DOWN) return (--prescaler & scale) == scale && (count-- & 0xFF) == 0x00; else return (++prescaler & scale) == 0x00 && (++count & 0xFF) == 0x00; } bool Standard::Irq::A12::Clock() { return base.IsEnabled(MODE_PPU_A12) && base.Clock(); } bool Standard::Irq::M2::Clock() { return base.IsEnabled(MODE_M2) && base.Clock(); } uint Standard::Banks::Unscramble(const uint bank) { return ( (bank & 0x01) << 6 | (bank & 0x02) << 4 | (bank & 0x04) << 2 | (bank & 0x10) >> 2 | (bank & 0x20) >> 4 | (bank & 0x40) >> 6 ); } NES_HOOK(Standard,HActive) { if (irq.IsEnabled(Irq::MODE_PPU_READ) && ppu.IsEnabled()) { for (uint i=0, hit=false; i < (32*4) * 2; i += 2) { if (irq.Clock() && !hit) { hit = true; cpu.DoIRQ( Cpu::IRQ_EXT, cpu.GetCycles() + ppu.GetClock() * i ); } } } } NES_HOOK(Standard,HBlank) { if (irq.IsEnabled(Irq::MODE_PPU_READ) && ppu.IsEnabled()) { for (uint i=0, hit=false; i < (8*4+2*4+2) * 2; i += 2) { if (irq.Clock() && !hit) { hit = true; cpu.DoIRQ( Cpu::IRQ_EXT, cpu.GetCycles() + ppu.GetClock() * i ); } } } } NES_ACCESSOR(Standard,Chr) { const uint data = chr.Peek( address ); switch (address & 0xFF8) { case 0xFD8: case 0xFE8: banks.chrLatch[address >> 12] = address >> 4 & ((address >> 10 & 0x4) | 0x2); if ((regs.ctrl[0] & Regs::CTRL0_CHR_MODE) == Regs::CTRL0_CHR_SWAP_4K) UpdateChrLatch(); break; } return data; } NES_PEEK_A(Standard,5000) { return (cartSwitches.GetSetting() & DIPSWITCH_GAME) | (address >> 8 & ~uint(DIPSWITCH_GAME)); } NES_POKE_D(Standard::Regs,5800) { mul[0] = data; } NES_POKE_D(Standard::Regs,5801) { mul[1] = data; } NES_POKE_D(Standard::Regs,5803) { tmp = data; } NES_PEEK(Standard::Regs,5800) { return (mul[0] * mul[1]) & 0xFF; } NES_PEEK(Standard::Regs,5801) { return (mul[0] * mul[1]) >> 8; } NES_PEEK(Standard::Regs,5803) { return tmp; } NES_PEEK_A(Standard,6000) { NST_VERIFY( banks.prg6 ); return banks.prg6 ? banks.prg6[address - 0x6000] : (address >> 8); } NES_POKE_AD(Standard,8000) { address &= 0x3; data &= 0x3F; if (banks.prg[address] != data) { banks.prg[address] = data; UpdatePrg(); } } NES_POKE_AD(Standard,9000) { address &= 0x7; data |= banks.chr[address] & 0xFF00; if (banks.chr[address] != data) { banks.chr[address] = data; UpdateChr(); } } NES_POKE_AD(Standard,A000) { address &= 0x7; data = data << 8 | (banks.chr[address] & 0x00FF); if (banks.chr[address] != data) { banks.chr[address] = data; UpdateChr(); } } NES_POKE_AD(Standard,B000) { address &= 0x3; data |= banks.nmt[address] & 0xFF00; if (banks.nmt[address] != data) { banks.nmt[address] = data; UpdateNmt(); } } NES_POKE_AD(Standard,B004) { address &= 0x3; data = data << 8 | (banks.nmt[address] & 0x00FF); if (banks.nmt[address] != data) { banks.nmt[address] = data; UpdateNmt(); } } NES_POKE_D(Standard,C000) { data &= Irq::TOGGLE; if (irq.enabled != data) { irq.Update(); irq.enabled = data; if (!data) cpu.ClearIRQ(); } } NES_POKE_D(Standard,C001) { if (irq.mode != data) { irq.Update(); NST_VERIFY ( (data & Irq::MODE_SCALE_ADJUST) == 0 && ( (data & Irq::MODE_SOURCE) == Irq::MODE_M2 || (data & Irq::MODE_SOURCE) == Irq::MODE_PPU_A12 || (data & Irq::MODE_SOURCE) == Irq::MODE_PPU_READ ) ); irq.mode = data; irq.scale = (data & Irq::MODE_SCALE_3BIT) ? 0x7 : 0xFF; } } NES_POKE(Standard,C002) { if (irq.enabled) { irq.Update(); irq.enabled = false; cpu.ClearIRQ(); } } NES_POKE(Standard,C003) { if (!irq.enabled) { irq.Update(); irq.enabled = true; } } NES_POKE_D(Standard,C004) { irq.Update(); irq.prescaler = data ^ irq.flip; } NES_POKE_D(Standard,C005) { irq.Update(); irq.count = data ^ irq.flip; } NES_POKE_D(Standard,C006) { irq.flip = data; } NES_POKE_D(Standard,D000) { if (regs.ctrl[0] != data) { regs.ctrl[0] = data; UpdatePrg(); UpdateExChr(); UpdateChr(); UpdateNmt(); } } NES_POKE_D(Standard,D001) { if (regs.ctrl[1] != data) { regs.ctrl[1] = data; UpdateNmt(); } } NES_POKE_D(Standard,D002) { if (regs.ctrl[2] != data) { regs.ctrl[2] = data; UpdateNmt(); } } NES_POKE_D(Standard,D003) { if (regs.ctrl[3] != data) { regs.ctrl[3] = data; UpdatePrg(); UpdateExChr(); UpdateChr(); } } void Standard::UpdatePrg() { NST_VERIFY( (regs.ctrl[0] & Regs::CTRL0_PRG_MODE) != Regs::CTRL0_PRG_SWAP_8K_R ); const uint exPrg = (regs.ctrl[3] & Regs::CTRL3_EX_PRG) << 5; if (!(regs.ctrl[0] & Regs::CTRL0_PRG6_ENABLE)) { banks.prg6 = NULL; } else { uint bank = banks.prg[3]; switch (regs.ctrl[0] & Regs::CTRL0_PRG_MODE) { case Regs::CTRL0_PRG_SWAP_32K: bank = bank << 2 | 0x3; break; case Regs::CTRL0_PRG_SWAP_16K: bank = bank << 1 | 0x1; break; case Regs::CTRL0_PRG_SWAP_8K_R: bank = banks.Unscramble( bank ); break; } banks.prg6 = prg.Source().Mem( ((bank & 0x3FUL) | exPrg) * SIZE_8K ); } const uint last = (regs.ctrl[0] & Regs::CTRL0_PRG_NOT_LAST) ? banks.prg[3] : 0x3F; switch (regs.ctrl[0] & Regs::CTRL0_PRG_MODE) { case Regs::CTRL0_PRG_SWAP_32K: prg.SwapBank ( (last & 0xF) | (exPrg >> 2) ); break; case Regs::CTRL0_PRG_SWAP_16K: prg.SwapBanks ( (banks.prg[1] & 0x1F) | (exPrg >> 1), (last & 0x1F) | (exPrg >> 1) ); break; case Regs::CTRL0_PRG_SWAP_8K: prg.SwapBanks ( (banks.prg[0] & 0x3F) | exPrg, (banks.prg[1] & 0x3F) | exPrg, (banks.prg[2] & 0x3F) | exPrg, (last & 0x3F) | exPrg ); break; case Regs::CTRL0_PRG_SWAP_8K_R: prg.SwapBanks ( (banks.Unscramble( banks.prg[0] ) & 0x3F) | exPrg, (banks.Unscramble( banks.prg[1] ) & 0x3F) | exPrg, (banks.Unscramble( banks.prg[2] ) & 0x3F) | exPrg, (banks.Unscramble( last ) & 0x3F) | exPrg ); break; } } void Standard::UpdateExChr() { if (regs.ctrl[3] & Regs::CTRL3_NO_EX_CHR) { banks.exChr.mask = 0xFFFF; banks.exChr.bank = 0x0000; } else { const uint mode = (regs.ctrl[0] & Regs::CTRL0_CHR_MODE) >> 3; banks.exChr.mask = 0x00FFU >> (mode ^ 0x3); banks.exChr.bank = ((regs.ctrl[3] & Regs::CTRL3_EX_CHR_0) | ((regs.ctrl[3] & Regs::CTRL3_EX_CHR_1) >> 2)) << (mode + 5); } } void Standard::UpdateChr() const { ppu.Update(); switch (regs.ctrl[0] & Regs::CTRL0_CHR_MODE) { case Regs::CTRL0_CHR_SWAP_8K: chr.SwapBank ( (banks.chr[0] & banks.exChr.mask) | banks.exChr.bank ); break; case Regs::CTRL0_CHR_SWAP_4K: UpdateChrLatch(); break; case Regs::CTRL0_CHR_SWAP_2K: chr.SwapBanks ( (banks.chr[0] & banks.exChr.mask) | banks.exChr.bank, (banks.chr[2] & banks.exChr.mask) | banks.exChr.bank, (banks.chr[4] & banks.exChr.mask) | banks.exChr.bank, (banks.chr[6] & banks.exChr.mask) | banks.exChr.bank ); break; case Regs::CTRL0_CHR_SWAP_1K: chr.SwapBanks ( (banks.chr[0] & banks.exChr.mask) | banks.exChr.bank, (banks.chr[1] & banks.exChr.mask) | banks.exChr.bank, (banks.chr[2] & banks.exChr.mask) | banks.exChr.bank, (banks.chr[3] & banks.exChr.mask) | banks.exChr.bank, (banks.chr[4] & banks.exChr.mask) | banks.exChr.bank, (banks.chr[5] & banks.exChr.mask) | banks.exChr.bank, (banks.chr[6] & banks.exChr.mask) | banks.exChr.bank, (banks.chr[7] & banks.exChr.mask) | banks.exChr.bank ); break; } } void Standard::UpdateChrLatch() const { NST_ASSERT( (regs.ctrl[0] & Regs::CTRL0_CHR_MODE) == Regs::CTRL0_CHR_SWAP_4K ); chr.SwapBanks ( (banks.chr[banks.chrLatch[0]] & banks.exChr.mask) | banks.exChr.bank, (banks.chr[banks.chrLatch[1]] & banks.exChr.mask) | banks.exChr.bank ); } void Standard::UpdateNmt() { if ((regs.ctrl[0] >> 5 & cartSwitches.GetSetting() & 0x1) | (cartSwitches.GetSetting() & 0x2)) { ppu.Update(); for (uint i=0; i < 4; ++i) nmt.Source( (regs.ctrl[0] & Regs::CTRL0_NMT_CHR_ROM) || ((banks.nmt[i] ^ regs.ctrl[2]) & Regs::CTRL2_NMT_USE_RAM) ).SwapBank( i * 0x0400, banks.nmt[i] ); } else { SetMirroringVH01( regs.ctrl[1] ); } } void Standard::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) { irq.a12.VSync(); irq.m2.VSync(); } Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardJyCompany.hpp000066400000000000000000000126751411157722000230320ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_JYCOMPANY_H #define NST_BOARD_JYCOMPANY_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace JyCompany { class Standard : public Board { public: Standard(const Context&); private: enum DefaultDipSwitch { DEFAULT_DIP_NMT_OFF, DEFAULT_DIP_NMT_CONTROLLED, DEFAULT_DIP_NMT_ON }; class CartSwitches : public DipSwitches { public: CartSwitches(uint,bool); inline uint GetSetting() const; inline bool IsPpuLatched() const; private: uint NumDips() const; uint NumValues(uint) const; cstring GetDipName(uint) const; cstring GetValueName(uint,uint) const; uint GetValue(uint) const; void SetValue(uint,uint); uint data; const ibool ppuLatched; }; enum { DIPSWITCH_NMT = 0x03, DIPSWITCH_GAME = 0xC0 }; void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void UpdatePrg(); void UpdateChr() const; void UpdateChrLatch() const; void UpdateExChr(); void UpdateNmt(); Device QueryDevice(DeviceType); void Sync(Event,Input::Controllers*); NES_DECL_HOOK( HActive ); NES_DECL_HOOK( HBlank ); NES_DECL_ACCESSOR( Chr ); NES_DECL_PEEK( 5000 ); NES_DECL_PEEK( 6000 ); NES_DECL_POKE( 8000 ); NES_DECL_POKE( 9000 ); NES_DECL_POKE( A000 ); NES_DECL_POKE( B000 ); NES_DECL_POKE( B004 ); NES_DECL_POKE( C000 ); NES_DECL_POKE( C001 ); NES_DECL_POKE( C002 ); NES_DECL_POKE( C003 ); NES_DECL_POKE( C004 ); NES_DECL_POKE( C005 ); NES_DECL_POKE( C006 ); NES_DECL_POKE( D000 ); NES_DECL_POKE( D001 ); NES_DECL_POKE( D002 ); NES_DECL_POKE( D003 ); struct Regs { void Reset(); enum { CTRL0_PRG_MODE = 0x03, CTRL0_PRG_SWAP_32K = 0x00, CTRL0_PRG_SWAP_16K = 0x01, CTRL0_PRG_SWAP_8K = 0x02, CTRL0_PRG_SWAP_8K_R = 0x03, CTRL0_PRG_NOT_LAST = 0x04, CTRL0_CHR_MODE = 0x18, CTRL0_CHR_SWAP_8K = 0x00, CTRL0_CHR_SWAP_4K = 0x08, CTRL0_CHR_SWAP_2K = 0x10, CTRL0_CHR_SWAP_1K = 0x18, CTRL0_NMT_CHR = 0x20, CTRL0_NMT_CHR_ROM = 0x40, CTRL0_PRG6_ENABLE = 0x80, CTRL1_MIRRORING = 0x03, CTRL2_NMT_USE_RAM = 0x80, CTRL3_NO_EX_CHR = 0x20, CTRL3_EX_CHR_0 = 0x01, CTRL3_EX_CHR_1 = 0x18, CTRL3_EX_PRG = 0x06 }; NES_DECL_PEEK( 5001 ); NES_DECL_PEEK( 5800 ); NES_DECL_POKE( 5800 ); NES_DECL_POKE( 5801 ); NES_DECL_PEEK( 5801 ); NES_DECL_POKE( 5803 ); NES_DECL_PEEK( 5803 ); uint mul[2]; uint tmp; uint ctrl[4]; }; struct Banks { void Reset(); static uint Unscramble(uint); uint prg[4]; uint chr[8]; uint nmt[4]; struct { uint mask; uint bank; } exChr; const byte* prg6; uint chrLatch[2]; }; struct Irq { struct A12 { explicit A12(Irq&); void Reset(bool); bool Clock(); Irq& base; }; struct M2 { explicit M2(Irq&); void Reset(bool); bool Clock(); Irq& base; }; Irq(Cpu&,Ppu&); void Reset(); bool IsEnabled() const; bool IsEnabled(uint) const; bool Clock(); inline void Update(); enum { TOGGLE = 0x01, MODE_SOURCE = 0x03, MODE_M2 = 0x00, MODE_PPU_A12 = 0x01, MODE_PPU_READ = 0x02, MODE_CPU_WRITE = 0x03, MODE_SCALE_3BIT = 0x04, MODE_SCALE_ADJUST = 0x08, MODE_COUNT_ENABLE = 0xC0, MODE_COUNT_UP = 0x40, MODE_COUNT_DOWN = 0x80 }; uint enabled; uint mode; uint prescaler; uint scale; uint count; uint flip; Timer::A12 a12; Timer::M2 m2; }; Regs regs; Banks banks; Irq irq; CartSwitches cartSwitches; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardKaiser.cpp000066400000000000000000000420521411157722000223220ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // Copyright (C) 2021 Rupert Carmichael // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstTimer.hpp" #include "NstBoard.hpp" #include "NstBoardKaiser.hpp" namespace Nes { namespace Core { namespace Boards { namespace Kaiser { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Ks202::Ks202(const Context& c) : Board(c), irq(*c.cpu) {} void Ks202::Irq::Reset(const bool hard) { if (hard) { count = 0; latch = 0; ctrl = 0; } } void Ks202::SubReset(const bool hard) { Map( 0x8000U, 0x8FFFU, &Ks202::Poke_8000 ); Map( 0x9000U, 0x9FFFU, &Ks202::Poke_9000 ); Map( 0xA000U, 0xAFFFU, &Ks202::Poke_A000 ); Map( 0xB000U, 0xBFFFU, &Ks202::Poke_B000 ); Map( 0xC000U, 0xCFFFU, &Ks202::Poke_C000 ); Map( 0xD000U, 0xDFFFU, &Ks202::Poke_D000 ); Map( 0xE000U, 0xEFFFU, &Ks202::Poke_E000 ); Map( 0xF000U, 0xFFFFU, &Ks202::Poke_F000 ); if (hard) ctrl = 0; irq.Reset( hard, hard ? false : irq.Connected() ); } void Ks7010::SubReset(const bool hard) { prg.SwapBank( 0x0000, 0x5 ); prg.SwapBank( 0x4000, 0x3 ); // At the time of writing, the true mask for bankswitching is unknown Map( 0x6000U, 0x7FFFU, &Ks7010::Peek_6000 ); Map( 0xCAB6U, 0xCAD6U, &Ks7010::Peek_FFFC ); Map( 0xEBE2U, 0xEBE3U, &Ks7010::Peek_FFFC ); Map( 0xEE32U, &Ks7010::Peek_FFFC ); Map( 0xFFFCU, &Ks7010::Peek_FFFC ); reg = 0; } void Ks7013b::SubReset(const bool hard) { prg.SwapBank( 0x4000, 0x7 ); Map( 0x6000U, 0x7FFFU, &Ks7013b::Poke_6000 ); Map( 0x8000U, 0xFFFFU, &Ks7013b::Poke_8000 ); } void Ks7016::SubReset(const bool hard) { reg = 8; prg.SwapBank( 0x0000, 0x3 ); Map( 0x6000U, 0x7FFFU, &Ks7016::Peek_6000 ); Map( 0x8000U, 0xFFFFU, &Ks7016::Poke_8000 ); } void Ks7022::SubReset(const bool hard) { reg = 0; if (hard) prg.SwapBanks( 0, 0 ); Map( 0x8000, &Ks7022::Poke_8000 ); Map( 0xA000, &Ks7022::Poke_A000 ); Map( 0xFFFC, &Ks7022::Peek_FFFC ); } void Ks7031::SubReset(const bool hard) { Map( 0x6000U, 0xFFFEU, &Ks7031::Peek_6000 ); Map( 0x8000U, 0xFFFFU, &Ks7031::Poke_8000 ); regs[0] = 0; regs[1] = 0; regs[2] = 0; regs[3] = 0; } void Ks7032::SubReset(const bool hard) { Ks202::SubReset( hard ); Map( 0x6000U, 0x7FFFU, &Ks7032::Peek_6000 ); } void Ks7037::SubReset(const bool hard) { if (hard) { regNum = 0; for (uint i = 0; i < 8; ++i) regs[i] = 0; } Map( 0x6000U, 0x6FFFU, &Ks7037::Peek_6000 ); Map( 0x6000U, 0x6FFFU, &Ks7037::Poke_6000 ); Map( 0x7000U, 0x7FFFU, &Ks7037::Peek_7000 ); Map( 0x8000U, 0x9FFFU, &Ks7037::Peek_8000 ); for (uint i = 0x0000; i < 0x2000; i += 0x2) { Map( 0x8000 + i, &Ks7037::Poke_8000 ); Map( 0x8001 + i, &Ks7037::Poke_8001 ); } Map( 0xA000U, 0xAFFFU, &Ks7037::Peek_A000 ); Map( 0xB000U, 0xBFFFU, &Ks7037::Peek_B000 ); Map( 0xB000U, 0xBFFFU, &Ks7037::Poke_B000 ); Map( 0xC000U, 0xDFFFU, &Ks7037::Peek_C000 ); Map( 0xE000U, 0xEFFFU, &Ks7037::Peek_E000 ); } void Ks7057::SubReset(const bool hard) { prg.SwapBank( 0x2000, 0xD ); prg.SwapBank( 0x4000, 0x7 ); Map( 0x6000U, 0x9FFFU, &Ks7057::Peek_6000 ); Map( 0x8000U, 0x9FFFU, &Ks7057::Poke_8000 ); Map( 0xB000U, 0xE003U, &Ks7057::Poke_B000 ); if (hard) { for (uint i = 0; i < 8; ++i) regs[i] = 0; } } void Ks7058::SubReset(bool) { for (uint i=0x000; i < 0x1000; i += 0x100) { Map( 0xF000+i, 0xF07F+i, CHR_SWAP_4K_0 ); Map( 0xF080+i, 0xF0FF+i, CHR_SWAP_4K_1 ); } } void Ks202::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( (baseChunk == AsciiId<'K','0','2'>::V) ); if (baseChunk == AsciiId<'K','0','2'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: ctrl = state.Read8(); break; case AsciiId<'I','R','Q'>::V: { State::Loader::Data<5> data( state ); irq.unit.ctrl = data[0]; irq.unit.count = data[1] | data[2] << 8; irq.unit.latch = data[3] | data[4] << 8; irq.Connect( data[0] & 0xF ); break; } } state.End(); } } } void Ks7010::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( (baseChunk == AsciiId<'K','7','0'>::V) ); if (baseChunk == AsciiId<'K','7','0'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) reg = state.Read8(); state.End(); } } } void Ks7016::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( (baseChunk == AsciiId<'K','7','6'>::V) ); if (baseChunk == AsciiId<'K','7','6'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) reg = state.Read8(); state.End(); } } } void Ks7022::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( (baseChunk == AsciiId<'K','7','2'>::V) ); if (baseChunk == AsciiId<'K','7','2'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) reg = state.Read8(); state.End(); } } } void Ks7031::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( (baseChunk == AsciiId<'K','7','1'>::V) ); if (baseChunk == AsciiId<'K','7','1'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<4> data( state ); regs[0] = data[0]; regs[1] = data[1]; regs[2] = data[2]; regs[3] = data[3]; } state.End(); } } } void Ks7037::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( (baseChunk == AsciiId<'K','7','7'>::V) ); if (baseChunk == AsciiId<'K','7','7'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<9> data( state ); regs[0] = data[0]; regs[1] = data[1]; regs[2] = data[2]; regs[3] = data[3]; regs[4] = data[4]; regs[5] = data[5]; regs[6] = data[6]; regs[7] = data[7]; regNum = data[8]; } state.End(); } } } void Ks7057::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( (baseChunk == AsciiId<'K','5','7'>::V) ); if (baseChunk == AsciiId<'K','5','7'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<8> data( state ); regs[0] = data[0]; regs[1] = data[1]; regs[2] = data[2]; regs[3] = data[3]; regs[4] = data[4]; regs[5] = data[5]; regs[6] = data[6]; regs[7] = data[7]; } state.End(); } } } void Ks202::SubSave(State::Saver& state) const { state.Begin( AsciiId<'K','0','2'>::V ); state.Begin( AsciiId<'R','E','G'>::V ).Write8( ctrl ).End(); const byte data[5] = { irq.unit.ctrl, irq.unit.count & 0xFF, irq.unit.count >> 8, irq.unit.latch & 0xFF, irq.unit.latch >> 8 }; state.Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End(); state.End(); } void Ks7010::SubSave(State::Saver& state) const { state.Begin( AsciiId<'K','7','0'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( reg ).End().End(); } void Ks7016::SubSave(State::Saver& state) const { state.Begin( AsciiId<'K','7','6'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( reg ).End().End(); } void Ks7022::SubSave(State::Saver& state) const { state.Begin( AsciiId<'K','7','2'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( reg ).End().End(); } void Ks7031::SubSave(State::Saver& state) const { state.Begin( AsciiId<'K','7','1'>::V ); state.Begin( AsciiId<'R','E','G'>::V ).Write( regs ).End(); state.End(); } void Ks7037::SubSave(State::Saver& state) const { state.Begin( AsciiId<'K','7','7'>::V ); const byte data[9] = { regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6], regs[7], regNum }; state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End(); state.End(); } void Ks7057::SubSave(State::Saver& state) const { state.Begin( AsciiId<'K','5','7'>::V ); const byte data[8] = { regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6], regs[7] }; state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End(); state.End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Ks202,8000) { irq.Update(); irq.unit.latch = (irq.unit.latch & 0xFFF0) | (data & 0xF) << 0; } NES_POKE_D(Ks202,9000) { irq.Update(); irq.unit.latch = (irq.unit.latch & 0xFF0F) | (data & 0xF) << 4; } NES_POKE_D(Ks202,A000) { irq.Update(); irq.unit.latch = (irq.unit.latch & 0xF0FF) | (data & 0xF) << 8; } NES_POKE_D(Ks202,B000) { irq.Update(); irq.unit.latch = (irq.unit.latch & 0x0FFF) | (data & 0xF) << 12; } NES_POKE_D(Ks202,C000) { irq.Update(); irq.unit.ctrl = data; if (irq.Connect( data & 0xF )) irq.unit.count = irq.unit.latch; irq.ClearIRQ(); } NES_POKE(Ks202,D000) { irq.Update(); irq.ClearIRQ(); } NES_POKE_D(Ks202,E000) { ctrl = data; } NES_POKE_AD(Ks202,F000) { { uint offset = (ctrl & 0xF) - 1; if (offset < 3) { offset <<= 13; prg.SwapBank( offset, (data & 0x0F) | (prg.GetBank(offset) & 0x10) ); } else if (offset < 4) { wrk.SwapBank( data ); } } switch (address & 0xC00) { case 0x000: address &= 0x3; if (address < 3) { address <<= 13; prg.SwapBank( address, (prg.GetBank(address) & 0x0F) | (data & 0x10) ); } break; case 0x800: ppu.SetMirroring( (data & 0x1) ? Ppu::NMT_V : Ppu::NMT_H ); break; case 0xC00: ppu.Update(); chr.SwapBank( (address & 0x7) << 10, data ); break; } } bool Ks202::Irq::Clock() { return (count++ == 0xFFFF) ? (count=latch, true) : false; } void Ks202::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } NES_PEEK_A(Ks7010,6000) { return *(prg.Source().Mem(reg * SIZE_8K) + (address & 0x1FFF)); } NES_PEEK_A(Ks7010,FFFC) { reg = (address >> 2) & 0xF; chr.SwapBank( reg ); ppu.Update(); return prg.Peek(address & 0x7FFF); } NES_POKE_D(Ks7013b,6000) { prg.SwapBank( 0x0000, data & 0x7 ); } NES_POKE_D(Ks7013b,8000) { ppu.SetMirroring( (data & 0x1) ? Ppu::NMT_H : Ppu::NMT_V ); } NES_PEEK_A(Ks7016,6000) { return *(prg.Source().Mem(reg * SIZE_8K) + (address & 0x1FFF)); } NES_POKE_A(Ks7016,8000) { bool mode = (address & 0x30) == 0x30; switch(address & 0xD943) { case 0xD943: reg = mode ? 0xB : (address >> 2) & 0xF; break; case 0xD903: reg = mode ? 0x8 | ((address >> 2) & 0x3) : reg = 0xB; break; } } NES_POKE_D(Ks7022,8000) { ppu.SetMirroring( (data & 0x4) ? Ppu::NMT_H : Ppu::NMT_V ); } NES_POKE_D(Ks7022,A000) { reg = data & 0xF; } NES_PEEK(Ks7022,FFFC) { ppu.Update(); chr.SwapBank( reg ); prg.SwapBanks( reg, reg ); return prg.Peek(0x7FFC); } NES_POKE_AD(Ks7031,8000) { regs[(address >> 11) & 0x03] = data; } NES_PEEK_A(Ks7031,6000) { int bank, new_addr; if (address < 0x8000) bank = regs[(address >> 11) & 0x03]; else bank = 0x0f - ((address >> 11) & 0x0f); new_addr = ((bank << 11) % prg.Source(0).Size()) | (address & 0x07ff); return prg[0][new_addr]; } NES_PEEK_A(Ks7032,6000) { return wrk[0][address - 0x6000]; } NES_PEEK_A(Ks7037,6000) { NST_VERIFY( wrk.Readable(0) ); return wrk.Readable(0) ? wrk[0][address - 0x6000] : (address >> 8); } NES_POKE_AD(Ks7037,6000) { NST_VERIFY( wrk.Writable(0) ); if (wrk.Writable(0)) wrk[0][address- 0x6000] = data; } NES_PEEK_A(Ks7037,7000) { return *(prg.Source().Mem(SIZE_4K * 15) + (address & 0xFFF)); } NES_PEEK_A(Ks7037,8000) { return *(prg.Source().Mem(regs[6] * SIZE_8K) + (address & 0x1FFF)); } NES_POKE_D(Ks7037,8000) { regNum = data & 0x7U; byte mirror[4] = { regs[2], regs[4], regs[3], regs[5] }; ppu.SetMirroring(mirror); } NES_POKE_D(Ks7037,8001) { regs[regNum] = data; } NES_PEEK_A(Ks7037,A000) { return *(prg.Source().Mem(SIZE_4K * 28) + (address & 0xFFF)); } NES_PEEK_A(Ks7037,B000) { NST_VERIFY( wrk.Readable(0) ); return wrk.Readable(0) ? wrk[0][address - 0xA000] : (address >> 8); } NES_POKE_AD(Ks7037,B000) { NST_VERIFY( wrk.Writable(0) ); if (wrk.Writable(0)) wrk[0][address- 0xA000] = data; } NES_PEEK_A(Ks7037,C000) { return *(prg.Source().Mem(regs[7] * SIZE_8K) + (address & 0x1FFF)); } NES_PEEK_A(Ks7037,E000) { return *(prg.Source().Mem(SIZE_8K * 15) + (address & 0x1FFF)); } NES_PEEK_A(Ks7057,6000) { return *(prg.Source().Mem(regs[(address >> 11) - 0xC] * SIZE_2K) + (address & 0x7FF)); } NES_POKE_D(Ks7057,8000) { ppu.SetMirroring( (data & 0x1) ? Ppu::NMT_V : Ppu::NMT_H ); } NES_POKE_AD(Ks7057,B000) { switch(address & 0xF003) { case 0xB000: regs[4] = (regs[4] & 0xF0) | (data & 0xF); break; case 0xB001: regs[4] = (regs[4] & 0xF) | (data << 4); break; case 0xB002: regs[5] = (regs[5] & 0xF0) | (data & 0xF); break; case 0xB003: regs[5] = (regs[5] & 0xF) | (data << 4); break; case 0xC000: regs[6] = (regs[6] & 0xF0) | (data & 0xF); break; case 0xC001: regs[6] = (regs[6] & 0xF) | (data << 4); break; case 0xC002: regs[7] = (regs[7] & 0xF0) | (data & 0xF); break; case 0xC003: regs[7] = (regs[7] & 0xF) | (data << 4); break; case 0xD000: regs[0] = (regs[0] & 0xF0) | (data & 0xF); break; case 0xD001: regs[0] = (regs[0] & 0xF) | (data << 4); break; case 0xD002: regs[1] = (regs[1] & 0xF0) | (data & 0xF); break; case 0xD003: regs[1] = (regs[1] & 0xF) | (data << 4); break; case 0xE000: regs[2] = (regs[2] & 0xF0) | (data & 0xF); break; case 0xE001: regs[2] = (regs[2] & 0xF) | (data << 4); break; case 0xE002: regs[3] = (regs[3] & 0xF0) | (data & 0xF); break; case 0xE003: regs[3] = (regs[3] & 0xF) | (data << 4); break; } } } } } } nestopia-1.51.1/source/core/board/NstBoardKaiser.hpp000066400000000000000000000115311411157722000223250ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // Copyright (C) 2021 Rupert Carmichael // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_KAISER_H #define NST_BOARD_KAISER_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Kaiser { class Ks202 : public Board { public: explicit Ks202(const Context&); protected: void SubReset(bool); private: void SubLoad(State::Loader&,dword); void SubSave(State::Saver&) const; void Sync(Event,Input::Controllers*); NES_DECL_POKE( 8000 ); NES_DECL_POKE( 9000 ); NES_DECL_POKE( A000 ); NES_DECL_POKE( B000 ); NES_DECL_POKE( C000 ); NES_DECL_POKE( D000 ); NES_DECL_POKE( E000 ); NES_DECL_POKE( F000 ); struct Irq { void Reset(bool); bool Clock(); uint count; uint latch; uint ctrl; }; uint ctrl; Timer::M2 irq; }; class Ks7010 : public Board { public: explicit Ks7010(const Context& c) : Board(c) {} private: void SubReset(bool); void SubLoad(State::Loader&,dword); void SubSave(State::Saver&) const; NES_DECL_PEEK( 6000 ); NES_DECL_PEEK( FFFC ); uint reg; }; class Ks7013b : public Board { public: explicit Ks7013b(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 6000 ); NES_DECL_POKE( 8000 ); }; class Ks7016 : public Board { public: explicit Ks7016(const Context& c) : Board(c) {} private: void SubReset(bool); void SubLoad(State::Loader&,dword); void SubSave(State::Saver&) const; NES_DECL_PEEK( 6000 ); NES_DECL_POKE( 8000 ); uint reg; }; class Ks7022 : public Board { public: explicit Ks7022(const Context& c) : Board(c) {} private: void SubReset(bool); void SubLoad(State::Loader&,dword); void SubSave(State::Saver&) const; NES_DECL_POKE( 8000 ); NES_DECL_POKE( A000 ); NES_DECL_PEEK( FFFC ); uint reg; }; class Ks7031 : public Board { public: explicit Ks7031(const Context& c) : Board(c) {} private: void SubReset(bool); void SubLoad(State::Loader&,dword); void SubSave(State::Saver&) const; byte regs[4]; NES_DECL_POKE( 8000 ); NES_DECL_PEEK( 6000 ); }; class Ks7032 : public Ks202 { public: explicit Ks7032(const Context& c) : Ks202(c) {} private: void SubReset(bool); NES_DECL_PEEK( 6000 ); }; class Ks7037 : public Board { public: explicit Ks7037(const Context& c) : Board(c) {} private: void SubReset(bool); void SubLoad(State::Loader&,dword); void SubSave(State::Saver&) const; byte regNum; byte regs[8]; NES_DECL_PEEK( 6000 ); NES_DECL_POKE( 6000 ); NES_DECL_PEEK( 7000 ); NES_DECL_PEEK( 8000 ); NES_DECL_POKE( 8000 ); NES_DECL_POKE( 8001 ); NES_DECL_PEEK( A000 ); NES_DECL_PEEK( B000 ); NES_DECL_POKE( B000 ); NES_DECL_PEEK( C000 ); NES_DECL_PEEK( E000 ); }; class Ks7057 : public Board { public: explicit Ks7057(const Context& c) : Board(c) {} private: void SubReset(bool); void SubLoad(State::Loader&,dword); void SubSave(State::Saver&) const; byte regs[8]; NES_DECL_PEEK( 6000 ); NES_DECL_POKE( 8000 ); NES_DECL_POKE( B000 ); }; class Ks7058 : public Board { public: explicit Ks7058(const Context& c) : Board(c) {} private: void SubReset(bool); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardKasing.cpp000066400000000000000000000057051411157722000223240ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardKasing.hpp" namespace Nes { namespace Core { namespace Boards { namespace Kasing { void Standard::SubReset(const bool hard) { if (hard) { exRegs[0] = 0; exRegs[1] = 0; } Mmc3::SubReset( hard ); Map( 0x6000U, &Standard::Poke_6000 ); Map( 0x6001U, &Standard::Poke_6001 ); } void Standard::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'K','A','S'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<2> data( state ); exRegs[0] = data[0]; exRegs[1] = data[1]; } state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void Standard::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); const byte data[2] = { exRegs[0], exRegs[1] }; state.Begin( AsciiId<'K','A','S'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void NST_FASTCALL Standard::UpdatePrg(uint address,uint bank) { if (exRegs[0] & 0x80) prg.SwapBank( exRegs[0] >> 1 ); else Mmc3::UpdatePrg( address, bank ); } void NST_FASTCALL Standard::UpdateChr(uint address,uint bank) const { chr.SwapBank( address, (exRegs[1] << 8 & 0x100) | bank ); } NES_POKE_D(Standard,6000) { if (exRegs[0] != data) { exRegs[0] = data; Mmc3::UpdatePrg(); } } NES_POKE_D(Standard,6001) { if (exRegs[1] != data) { exRegs[1] = data; Mmc3::UpdateChr(); } } } } } } nestopia-1.51.1/source/core/board/NstBoardKasing.hpp000066400000000000000000000032511411157722000223230ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_KASING_H #define NST_BOARD_KASING_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Kasing { class Standard : public Mmc3 { public: explicit Standard(const Context& c) : Mmc3(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void NST_FASTCALL UpdatePrg(uint,uint); void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_POKE( 6000 ); NES_DECL_POKE( 6001 ); uint exRegs[2]; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardKay.hpp000066400000000000000000000023111411157722000216270ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_KAY_H #define NST_BOARD_KAY_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardKayH2288.hpp" #include "NstBoardKayPandaPrince.hpp" #endif nestopia-1.51.1/source/core/board/NstBoardKayH2288.cpp000066400000000000000000000065641411157722000222740ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardKay.hpp" namespace Nes { namespace Core { namespace Boards { namespace Kay { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void H2288::SubReset(const bool hard) { if (hard) { exRegs[0] = 0; exRegs[1] = 0; } Mmc3::SubReset( hard ); Map( 0x5000U, 0x57FFU, &H2288::Peek_5000 ); Map( 0x5800U, 0x5FFFU, &H2288::Peek_5000, &H2288::Poke_5800 ); for (uint i=0x8000; i < 0x9000; i += 0x2) Map( i, &H2288::Poke_8000 ); } void H2288::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'K','H','2'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<2> data( state ); exRegs[0] = data[0]; exRegs[1] = data[1]; } state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void H2288::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); const byte data[2] = { exRegs[0], exRegs[1] }; state.Begin( AsciiId<'K','H','2'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void NST_FASTCALL H2288::UpdatePrg(uint address,uint bank) { if (!(exRegs[0] & 0x40)) Mmc3::UpdatePrg( address, bank ); } NES_PEEK_A(H2288,5000) { return (address >> 8 & 0xFE) | (((~address & 0x1) & (address >> 8 & 0x1)) ^ 0x1); } NES_POKE_AD(H2288,5800) { address &= 0x1; if (exRegs[address] != data) { exRegs[address] = data; if (exRegs[0] & 0x40) { data = (exRegs[0] & 0x5) | (exRegs[0] >> 2 & 0x2) | (exRegs[0] >> 2 & 0x8); address = exRegs[0] >> 1 & 0x1; prg.SwapBanks( data & ~address, data | address ); } else { Mmc3::UpdatePrg(); } } } NES_POKE_AD(H2288,8000) { static const byte security[8] = {0,3,1,5,6,7,2,4}; Mmc3::NES_DO_POKE(8000,address,(data & 0xC0) | security[data & 0x07]); } } } } } nestopia-1.51.1/source/core/board/NstBoardKayH2288.hpp000066400000000000000000000032171411157722000222710ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_KAY_H2288_H #define NST_BOARD_KAY_H2288_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Kay { class H2288 : public Mmc3 { public: explicit H2288(const Context& c) : Mmc3(c) {} private: void SubReset(bool); void SubLoad(State::Loader&,dword); void SubSave(State::Saver&) const; void NST_FASTCALL UpdatePrg(uint,uint); NES_DECL_PEEK( 5000 ); NES_DECL_POKE( 5800 ); NES_DECL_POKE( 8000 ); uint exRegs[2]; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardKayPandaPrince.cpp000066400000000000000000000073321411157722000237370ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardKay.hpp" namespace Nes { namespace Core { namespace Boards { namespace Kay { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void PandaPrince::SubReset(const bool hard) { exRegs[0] = 0; exRegs[1] = 0; exRegs[2] = 0; Mmc3::SubReset( hard ); Map( 0x5000U, 0x5FFFU, &PandaPrince::Peek_5000, &PandaPrince::Poke_5000 ); Map( 0x8000U, 0x9FFFU, &PandaPrince::Poke_8000 ); } void PandaPrince::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'K','P','P'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<3> data( state ); exRegs[0] = data[0]; exRegs[1] = data[1]; exRegs[2] = data[2]; } state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void PandaPrince::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); const byte data[] = { exRegs[0], exRegs[1], exRegs[2] }; state.Begin( AsciiId<'K','P','P'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void NST_FASTCALL PandaPrince::UpdatePrg(uint address,uint bank) { if (address == 0x4000) { if (exRegs[0]) bank = exRegs[0]; } else if (address == 0x6000) { if (exRegs[1]) bank = exRegs[1]; } prg.SwapBank( address, bank ); } NES_PEEK(PandaPrince,5000) { return exRegs[2]; } NES_POKE_D(PandaPrince,5000) { static const byte lut[] = { 0x00, 0x83, 0x42, 0x00 }; exRegs[2] = lut[data & 0x3]; } NES_POKE_AD(PandaPrince,8000) { if ((address & 0x3) == 0x3) { switch (data) { case 0x28: exRegs[0] = 0x0C; break; case 0x26: exRegs[1] = 0x08; break; case 0xAB: exRegs[1] = 0x07; break; case 0xEC: exRegs[1] = 0x0D; break; case 0xEF: exRegs[1] = 0x0D; break; case 0xFF: exRegs[1] = 0x09; break; case 0x20: exRegs[1] = 0x13; break; case 0x29: exRegs[1] = 0x1B; break; default: exRegs[0] = 0x0; exRegs[1] = 0x0; break; } } else if (address & 0x1) { Mmc3::NES_DO_POKE(8001,address,data); } else { Mmc3::NES_DO_POKE(8000,address,data); } Mmc3::UpdatePrg(); } } } } } nestopia-1.51.1/source/core/board/NstBoardKayPandaPrince.hpp000066400000000000000000000032471411157722000237450ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_KAY_PANDAPRINCE_H #define NST_BOARD_KAY_PANDAPRINCE_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Kay { class PandaPrince : public Mmc3 { public: explicit PandaPrince(const Context& c) : Mmc3(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void NST_FASTCALL UpdatePrg(uint,uint); NES_DECL_PEEK( 5000 ); NES_DECL_POKE( 5000 ); NES_DECL_POKE( 8000 ); uint exRegs[3]; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardKonami.hpp000066400000000000000000000026001411157722000223220ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_KONAMI_H #define NST_BOARD_KONAMI_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardKonamiVrc1.hpp" #include "NstBoardKonamiVrc2.hpp" #include "NstBoardKonamiVrc3.hpp" #include "NstBoardKonamiVrc4.hpp" #include "NstBoardKonamiVrc6.hpp" #include "NstBoardKonamiVrc7.hpp" #include "NstBoardKonamiVsSystem.hpp" #endif nestopia-1.51.1/source/core/board/NstBoardKonamiVrc1.cpp000066400000000000000000000044071411157722000230600ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardKonamiVrc1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Konami { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Vrc1::SubReset(bool) { Map( 0x8000U, 0x8FFFU, PRG_SWAP_8K_0 ); Map( 0x9000U, 0x9FFFU, &Vrc1::Poke_9000 ); Map( 0xA000U, 0xAFFFU, PRG_SWAP_8K_1 ); Map( 0xC000U, 0xCFFFU, PRG_SWAP_8K_2 ); Map( 0xE000U, 0xEFFFU, &Vrc1::Poke_E000 ); Map( 0xF000U, 0xFFFFU, &Vrc1::Poke_F000 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Vrc1,9000) { ppu.SetMirroring( (data & 0x1) ? Ppu::NMT_H : Ppu::NMT_V ); chr.SwapBanks ( (data << 3 & 0x10) | (chr.GetBank() & 0xF), (data << 2 & 0x10) | (chr.GetBank() & 0xF) ); } NES_POKE_D(Vrc1,E000) { ppu.Update(); chr.SwapBank( (chr.GetBank() & 0x10) | (data & 0xF) ); } NES_POKE_D(Vrc1,F000) { ppu.Update(); chr.SwapBank( (chr.GetBank() & 0x10) | (data & 0xF) ); } } } } } nestopia-1.51.1/source/core/board/NstBoardKonamiVrc1.hpp000066400000000000000000000027731411157722000230710ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_KONAMI_VRC1_H #define NST_BOARD_KONAMI_VRC1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Konami { class Vrc1 : public Board { public: explicit Vrc1(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 9000 ); NES_DECL_POKE( E000 ); NES_DECL_POKE( F000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardKonamiVrc2.cpp000066400000000000000000000132751411157722000230640ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardKonamiVrc2.hpp" namespace Nes { namespace Core { namespace Boards { namespace Konami { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif uint Vrc2::GetPrgLineShift(const Context& c,const uint pin,const uint def) { if (const Chips::Type* const vrc2 = c.chips.Find(L"Konami VRC II")) { const uint line = *vrc2->Pin(pin).C(L"PRG").A(); NST_VERIFY( line < 8 ); if (line < 8) return line; } return def; } uint Vrc2::GetChrLineShift(const Context& c) { if (const Chips::Type* const vrc2 = c.chips.Find(L"Konami VRC II")) { if (vrc2->Pin(21).C(L"CHR").A() != 10) return 1; } return 0; } Vrc2::Vrc2(const Context& c) : Board (c), chrShift (GetChrLineShift(c)), prgLineA (GetPrgLineShift(c,3,1)), prgLineB (GetPrgLineShift(c,4,0)) { } void Vrc2::SubReset(const bool hard) { if (hard) security = 0; if (!board.GetWram()) Map( 0x6000U, &Vrc2::Peek_6000, &Vrc2::Poke_6000 ); Map( 0x8000U, 0x8FFFU, PRG_SWAP_8K_0 ); //Map( 0x9000U, 0x9FFFU, NMT_SWAP_VH01 ); Map( 0x9000U, 0x9FFFU, NMT_SWAP_HV ); Map( 0xA000U, 0xAFFFU, PRG_SWAP_8K_1 ); for (uint i=0xB000, a=9-prgLineA, b=8-prgLineB; i < 0xF000; ++i) { switch ((i & 0xF000) | (i << a & 0x0200) | (i << b & 0x0100)) { case 0xB000: Map( i, &Vrc2::Poke_B000 ); break; case 0xB100: Map( i, &Vrc2::Poke_B001 ); break; case 0xB200: Map( i, &Vrc2::Poke_B002 ); break; case 0xB300: Map( i, &Vrc2::Poke_B003 ); break; case 0xC000: Map( i, &Vrc2::Poke_C000 ); break; case 0xC100: Map( i, &Vrc2::Poke_C001 ); break; case 0xC200: Map( i, &Vrc2::Poke_C002 ); break; case 0xC300: Map( i, &Vrc2::Poke_C003 ); break; case 0xD000: Map( i, &Vrc2::Poke_D000 ); break; case 0xD100: Map( i, &Vrc2::Poke_D001 ); break; case 0xD200: Map( i, &Vrc2::Poke_D002 ); break; case 0xD300: Map( i, &Vrc2::Poke_D003 ); break; case 0xE000: Map( i, &Vrc2::Poke_E000 ); break; case 0xE100: Map( i, &Vrc2::Poke_E001 ); break; case 0xE200: Map( i, &Vrc2::Poke_E002 ); break; case 0xE300: Map( i, &Vrc2::Poke_E003 ); break; } } } void Vrc2::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'K','V','2'>::V) ); if (baseChunk == AsciiId<'K','V','2'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'S','E','C'>::V) { NST_VERIFY( !board.GetWram() ); security = state.Read8() & 0x1; } state.End(); } } } void Vrc2::SubSave(State::Saver& state) const { if (!board.GetWram()) state.Begin( AsciiId<'K','V','2'>::V ).Begin( AsciiId<'S','E','C'>::V ).Write8( security ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Vrc2,6000) { NST_DEBUG_MSG( "VRC security write" ); security = data & 0x1; } NES_PEEK(Vrc2,6000) { NST_DEBUG_MSG( "VRC security read" ); return security; } template void Vrc2::SwapChr(uint address,uint subBank) const { ppu.Update(); chr.SwapBank( address, chrShift ? OFFSET ? (chr.GetBank(address) & 0x07U) | ((subBank & 0xFU) << 3) : (chr.GetBank(address) & 0xF8U) | ((subBank >> 1) & 0x7U) : (chr.GetBank(address) & 0xF0U >> OFFSET) | ((subBank & 0xFU) << OFFSET) ); } NES_POKE_D(Vrc2,B000) { SwapChr<0>( 0x0000, data ); } NES_POKE_D(Vrc2,B001) { SwapChr<4>( 0x0000, data ); } NES_POKE_D(Vrc2,B002) { SwapChr<0>( 0x0400, data ); } NES_POKE_D(Vrc2,B003) { SwapChr<4>( 0x0400, data ); } NES_POKE_D(Vrc2,C000) { SwapChr<0>( 0x0800, data ); } NES_POKE_D(Vrc2,C001) { SwapChr<4>( 0x0800, data ); } NES_POKE_D(Vrc2,C002) { SwapChr<0>( 0x0C00, data ); } NES_POKE_D(Vrc2,C003) { SwapChr<4>( 0x0C00, data ); } NES_POKE_D(Vrc2,D000) { SwapChr<0>( 0x1000, data ); } NES_POKE_D(Vrc2,D001) { SwapChr<4>( 0x1000, data ); } NES_POKE_D(Vrc2,D002) { SwapChr<0>( 0x1400, data ); } NES_POKE_D(Vrc2,D003) { SwapChr<4>( 0x1400, data ); } NES_POKE_D(Vrc2,E000) { SwapChr<0>( 0x1800, data ); } NES_POKE_D(Vrc2,E001) { SwapChr<4>( 0x1800, data ); } NES_POKE_D(Vrc2,E002) { SwapChr<0>( 0x1C00, data ); } NES_POKE_D(Vrc2,E003) { SwapChr<4>( 0x1C00, data ); } } } } } nestopia-1.51.1/source/core/board/NstBoardKonamiVrc2.hpp000066400000000000000000000044111411157722000230610ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_KONAMI_VRC2_H #define NST_BOARD_KONAMI_VRC2_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Konami { class Vrc2 : public Board { public: explicit Vrc2(const Context&); private: static uint GetPrgLineShift(const Context&,uint,uint); static uint GetChrLineShift(const Context&); void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); template void SwapChr(uint,uint) const; NES_DECL_PEEK( 6000 ); NES_DECL_POKE( 6000 ); NES_DECL_POKE( B000 ); NES_DECL_POKE( B001 ); NES_DECL_POKE( B002 ); NES_DECL_POKE( B003 ); NES_DECL_POKE( C000 ); NES_DECL_POKE( C001 ); NES_DECL_POKE( C002 ); NES_DECL_POKE( C003 ); NES_DECL_POKE( D000 ); NES_DECL_POKE( D001 ); NES_DECL_POKE( D002 ); NES_DECL_POKE( D003 ); NES_DECL_POKE( E000 ); NES_DECL_POKE( E001 ); NES_DECL_POKE( E002 ); NES_DECL_POKE( E003 ); uint security; const uint chrShift; const uint prgLineA; const uint prgLineB; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardKonamiVrc3.cpp000066400000000000000000000076511411157722000230660ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "../NstTimer.hpp" #include "NstBoardKonamiVrc3.hpp" namespace Nes { namespace Core { namespace Boards { namespace Konami { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Vrc3::Vrc3(const Context& c) : Board(c), irq(*c.cpu) {} void Vrc3::Irq::Reset(const bool hard) { if (hard) { enabled = false; count = 0; } } void Vrc3::SubReset(const bool hard) { irq.Reset( hard, true ); Map( 0x8000U, 0x8FFFU, &Vrc3::Poke_8000 ); Map( 0x9000U, 0x9FFFU, &Vrc3::Poke_9000 ); Map( 0xA000U, 0xAFFFU, &Vrc3::Poke_A000 ); Map( 0xB000U, 0xBFFFU, &Vrc3::Poke_B000 ); Map( 0xC000U, 0xCFFFU, &Vrc3::Poke_C000 ); Map( 0xD000U, 0xDFFFU, &Vrc3::Poke_D000 ); Map( 0xF000U, 0xFFFFU, PRG_SWAP_16K_0 ); } void Vrc3::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'K','V','3'>::V) ); if (baseChunk == AsciiId<'K','V','3'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'I','R','Q'>::V) { State::Loader::Data<3> data( state ); irq.unit.enabled = data[0] & 0x1; irq.unit.count = data[1] | data[2] << 8; } state.End(); } } } void Vrc3::SubSave(State::Saver& state) const { const byte data[3] = { irq.unit.enabled != 0, irq.unit.count & 0xFF, irq.unit.count >> 8 }; state.Begin( AsciiId<'K','V','3'>::V ).Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif bool Vrc3::Irq::Clock() { if (enabled) { count = (count + 1) & 0xFFFF; if (!count) { enabled = false; return true; } } return false; } NES_POKE_D(Vrc3,8000) { irq.Update(); irq.unit.count = (irq.unit.count & 0xFFF0) | (data & 0xF) << 0; } NES_POKE_D(Vrc3,9000) { irq.Update(); irq.unit.count = (irq.unit.count & 0xFF0F) | (data & 0xF) << 4; } NES_POKE_D(Vrc3,A000) { irq.Update(); irq.unit.count = (irq.unit.count & 0xF0FF) | (data & 0xF) << 8; } NES_POKE_D(Vrc3,B000) { irq.Update(); irq.unit.count = (irq.unit.count & 0x0FFF) | (data & 0xF) << 12; } NES_POKE_D(Vrc3,C000) { irq.Update(); irq.unit.enabled = data & 0x2; irq.ClearIRQ(); } NES_POKE(Vrc3,D000) { irq.Update(); irq.unit.enabled = false; irq.ClearIRQ(); } void Vrc3::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardKonamiVrc3.hpp000066400000000000000000000035251411157722000230670ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_KONAMI_VRC3_H #define NST_BOARD_KONAMI_VRC3_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Konami { class Vrc3 : public Board { public: explicit Vrc3(const Context&); private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Sync(Event,Input::Controllers*); NES_DECL_POKE( 8000 ); NES_DECL_POKE( 9000 ); NES_DECL_POKE( A000 ); NES_DECL_POKE( B000 ); NES_DECL_POKE( C000 ); NES_DECL_POKE( D000 ); struct Irq { void Reset(bool); bool Clock(); ibool enabled; uint count; }; Timer::M2 irq; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardKonamiVrc4.cpp000066400000000000000000000204631411157722000230630ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstTimer.hpp" #include "NstBoard.hpp" #include "NstBoardKonamiVrc4.hpp" namespace Nes { namespace Core { namespace Boards { namespace Konami { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif uint Vrc4::GetPrgLineShift(const Context& c,const uint pin,const uint def) { if (const Chips::Type* const vrc4 = c.chips.Find(L"Konami VRC IV")) { const uint line = *vrc4->Pin(pin).C(L"PRG").A(); NST_VERIFY( line < 8 ); if (line < 8) return line; } return def; } Vrc4::Vrc4(const Context& c) : Board (c), irq (*c.cpu), prgLineA (GetPrgLineShift(c,3,1)), prgLineB (GetPrgLineShift(c,4,0)) { } void Vrc4::BaseIrq::Reset(bool) { ctrl = 0; count[0] = 0; count[1] = 0; latch = 0; } void Vrc4::SubReset(const bool hard) { if (hard) prgSwap = 0; irq.Reset( hard, hard ? false : irq.Connected() ); if (const uint wram = board.GetWram()) Map( 0x6000U, 0x6000 + NST_MIN(wram,SIZE_8K) - 1, &Vrc4::Peek_6000, &Vrc4::Poke_6000 ); Map( 0x8000U, 0x8FFFU, &Vrc4::Poke_8000 ); Map( 0xA000U, 0xAFFFU, PRG_SWAP_8K_1 ); for (dword i=0x9000, a=9-prgLineA, b=8-prgLineB; i <= 0xFFFF; ++i) { switch ((i & 0xF000) | (i << a & 0x0200) | (i << b & 0x0100)) { case 0x9000: case 0x9100: Map( i, NMT_SWAP_VH01 ); break; case 0x9200: case 0x9300: Map( i, &Vrc4::Poke_9000 ); break; case 0xB000: Map( i, &Vrc4::Poke_B000 ); break; case 0xB100: Map( i, &Vrc4::Poke_B001 ); break; case 0xB200: Map( i, &Vrc4::Poke_B002 ); break; case 0xB300: Map( i, &Vrc4::Poke_B003 ); break; case 0xC000: Map( i, &Vrc4::Poke_C000 ); break; case 0xC100: Map( i, &Vrc4::Poke_C001 ); break; case 0xC200: Map( i, &Vrc4::Poke_C002 ); break; case 0xC300: Map( i, &Vrc4::Poke_C003 ); break; case 0xD000: Map( i, &Vrc4::Poke_D000 ); break; case 0xD100: Map( i, &Vrc4::Poke_D001 ); break; case 0xD200: Map( i, &Vrc4::Poke_D002 ); break; case 0xD300: Map( i, &Vrc4::Poke_D003 ); break; case 0xE000: Map( i, &Vrc4::Poke_E000 ); break; case 0xE100: Map( i, &Vrc4::Poke_E001 ); break; case 0xE200: Map( i, &Vrc4::Poke_E002 ); break; case 0xE300: Map( i, &Vrc4::Poke_E003 ); break; case 0xF000: Map( i, &Vrc4::Poke_F000 ); break; case 0xF100: Map( i, &Vrc4::Poke_F001 ); break; case 0xF200: Map( i, &Vrc4::Poke_F002 ); break; case 0xF300: Map( i, &Vrc4::Poke_F003 ); break; } } } void Vrc4::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( (baseChunk == AsciiId<'K','V','4'>::V) ); if (baseChunk == AsciiId<'K','V','4'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: prgSwap = state.Read8() & 0x2; break; case AsciiId<'I','R','Q'>::V: irq.LoadState( state ); break; } state.End(); } } } void Vrc4::SubSave(State::Saver& state) const { state.Begin( AsciiId<'K','V','4'>::V ); state.Begin( AsciiId<'R','E','G'>::V ).Write8( prgSwap ).End(); irq.SaveState( state, AsciiId<'I','R','Q'>::V ); state.End(); } void Vrc4::Irq::LoadState(State::Loader& state) { State::Loader::Data<5> data( state ); unit.ctrl = data[0] & (BaseIrq::ENABLE_1|BaseIrq::NO_PPU_SYNC); Connect( data[0] & BaseIrq::ENABLE_0 ); unit.latch = data[1]; unit.count[0] = NST_MIN(340,data[2] | data[3] << 8); unit.count[1] = data[4]; } void Vrc4::Irq::SaveState(State::Saver& state,const dword chunk) const { const byte data[5] = { unit.ctrl | (Connected() ? BaseIrq::ENABLE_0 : 0), unit.latch, unit.count[0] & 0xFF, unit.count[0] >> 8, unit.count[1] }; state.Begin( chunk ).Write( data ).End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(Vrc4,6000) { return wrk[0][address - 0x6000]; } NES_POKE_AD(Vrc4,6000) { wrk[0][address - 0x6000] = data; } NES_POKE_D(Vrc4,8000) { prg.SwapBank( prgSwap << 13, data ); } NES_POKE_D(Vrc4,9000) { data &= 0x2; if (prgSwap != data) { prgSwap = data; prg.SwapPages(); } } template void Vrc4::SwapChr(uint address,uint subBank) const { ppu.Update(); chr.SwapBank( address, (chr.GetBank(address) & 0xF0U >> OFFSET) | ((subBank & 0xF) << OFFSET) ); } NES_POKE_D(Vrc4,B000) { SwapChr<0>( 0x0000, data ); } NES_POKE_D(Vrc4,B001) { SwapChr<4>( 0x0000, data ); } NES_POKE_D(Vrc4,B002) { SwapChr<0>( 0x0400, data ); } NES_POKE_D(Vrc4,B003) { SwapChr<4>( 0x0400, data ); } NES_POKE_D(Vrc4,C000) { SwapChr<0>( 0x0800, data ); } NES_POKE_D(Vrc4,C001) { SwapChr<4>( 0x0800, data ); } NES_POKE_D(Vrc4,C002) { SwapChr<0>( 0x0C00, data ); } NES_POKE_D(Vrc4,C003) { SwapChr<4>( 0x0C00, data ); } NES_POKE_D(Vrc4,D000) { SwapChr<0>( 0x1000, data ); } NES_POKE_D(Vrc4,D001) { SwapChr<4>( 0x1000, data ); } NES_POKE_D(Vrc4,D002) { SwapChr<0>( 0x1400, data ); } NES_POKE_D(Vrc4,D003) { SwapChr<4>( 0x1400, data ); } NES_POKE_D(Vrc4,E000) { SwapChr<0>( 0x1800, data ); } NES_POKE_D(Vrc4,E001) { SwapChr<4>( 0x1800, data ); } NES_POKE_D(Vrc4,E002) { SwapChr<0>( 0x1C00, data ); } NES_POKE_D(Vrc4,E003) { SwapChr<4>( 0x1C00, data ); } void Vrc4::Irq::WriteLatch0(const uint data) { Update(); unit.latch = (unit.latch & 0xF0) | (data << 0 & 0x0F); } void Vrc4::Irq::WriteLatch1(const uint data) { Update(); unit.latch = (unit.latch & 0x0F) | (data << 4 & 0xF0); } void Vrc4::Irq::Toggle(const uint data) { Update(); unit.ctrl = data & (BaseIrq::ENABLE_1|BaseIrq::NO_PPU_SYNC); if (Connect( data & BaseIrq::ENABLE_0 )) { unit.count[0] = 0; unit.count[1] = unit.latch; } ClearIRQ(); } void Vrc4::Irq::Toggle() { Update(); Connect( unit.ctrl & BaseIrq::ENABLE_1 ); ClearIRQ(); } NES_POKE_D(Vrc4,F000) { irq.WriteLatch0( data ); } NES_POKE_D(Vrc4,F001) { irq.WriteLatch1( data ); } NES_POKE_D(Vrc4,F002) { irq.Toggle( data ); } NES_POKE(Vrc4,F003) { irq.Toggle(); } bool Vrc4::BaseIrq::Clock() { if (!(ctrl & NO_PPU_SYNC)) { if (count[0] < 341-3) { count[0] += 3; return false; } count[0] -= 341-3; } if (count[1] != 0xFF) { count[1]++; return false; } count[1] = latch; return true; } void Vrc4::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardKonamiVrc4.hpp000066400000000000000000000061241411157722000230660ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_KONAMI_VRC4_H #define NST_BOARD_KONAMI_VRC4_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Konami { class Vrc4 : public Board { public: explicit Vrc4(const Context&); protected: void SubReset(bool); private: struct BaseIrq { void Reset(bool); bool Clock(); enum { ENABLE_0 = 0x2, ENABLE_1 = 0x1, NO_PPU_SYNC = 0x4, CTRL = 0x1U|0x2U|0x4U }; uint ctrl; uint count[2]; uint latch; }; public: struct Irq : Timer::M2 { void WriteLatch0(uint); void WriteLatch1(uint); void Toggle(uint); void Toggle(); void LoadState(State::Loader&); void SaveState(State::Saver&,dword) const; explicit Irq(Cpu& c) : Timer::M2(c) {} }; private: static uint GetPrgLineShift(const Context&,uint,uint); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Sync(Event,Input::Controllers*); template void SwapChr(uint,uint) const; NES_DECL_PEEK( 6000 ); NES_DECL_POKE( 6000 ); NES_DECL_POKE( 8000 ); NES_DECL_POKE( 9000 ); NES_DECL_POKE( B000 ); NES_DECL_POKE( B001 ); NES_DECL_POKE( B002 ); NES_DECL_POKE( B003 ); NES_DECL_POKE( C000 ); NES_DECL_POKE( C001 ); NES_DECL_POKE( C002 ); NES_DECL_POKE( C003 ); NES_DECL_POKE( D000 ); NES_DECL_POKE( D001 ); NES_DECL_POKE( D002 ); NES_DECL_POKE( D003 ); NES_DECL_POKE( E000 ); NES_DECL_POKE( E001 ); NES_DECL_POKE( E002 ); NES_DECL_POKE( E003 ); NES_DECL_POKE( F000 ); NES_DECL_POKE( F001 ); NES_DECL_POKE( F002 ); NES_DECL_POKE( F003 ); Irq irq; const uint prgLineA; const uint prgLineB; protected: uint prgSwap; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardKonamiVrc6.cpp000066400000000000000000000330141411157722000230610ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "../NstTimer.hpp" #include "NstBoardKonamiVrc4.hpp" #include "NstBoardKonamiVrc6.hpp" namespace Nes { namespace Core { namespace Boards { namespace Konami { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Vrc6::Sound::Sound(Apu& a,bool connect) : Channel(a) { Reset(); bool audible = UpdateSettings(); if (connect) Connect( audible ); } uint Vrc6::GetPrgLineShift(const Context& c,const uint pin,const uint def) { if (const Chips::Type* const vrc6 = c.chips.Find(L"Konami VRC VI")) { const uint line = *vrc6->Pin(pin).C(L"PRG").A(); NST_VERIFY( line < 8 ); if (line < 8) return line; } return def; } Vrc6::Vrc6(const Context& c) : Board (c), irq (*c.cpu), sound (*c.apu), prgLineA (GetPrgLineShift(c, 9,1)), prgLineB (GetPrgLineShift(c,10,0)) {} void Vrc6::Sound::BaseChannel::Reset() { enabled = false; waveLength = 1; active = false; timer = 0; frequency = 0; step = 0; } void Vrc6::Sound::Square::Reset() { BaseChannel::Reset(); duty = 1; volume = 0; digitized = false; } void Vrc6::Sound::Saw::Reset() { BaseChannel::Reset(); phase = 0; amp = 0; frequency = 0; } void Vrc6::Sound::Reset() { for (uint i=0; i < 2; ++i) square[i].Reset(); saw.Reset(); dcBlocker.Reset(); } void Vrc6::SubReset(const bool hard) { irq.Reset( hard, hard ? false : irq.Connected() ); Map( 0x8000U, 0x8FFFU, PRG_SWAP_16K_0 ); Map( 0xC000U, 0xCFFFU, PRG_SWAP_8K_2 ); for (dword i=0x9000, a=9-prgLineA, b=8-prgLineB; i <= 0xFFFF; ++i) { switch ((i & 0xF000) | (i << a & 0x0200) | (i << b & 0x0100)) { case 0x9000: Map( i, &Vrc6::Poke_9000 ); break; case 0x9100: Map( i, &Vrc6::Poke_9001 ); break; case 0x9200: Map( i, &Vrc6::Poke_9002 ); break; case 0xA000: Map( i, &Vrc6::Poke_A000 ); break; case 0xA100: Map( i, &Vrc6::Poke_A001 ); break; case 0xA200: Map( i, &Vrc6::Poke_A002 ); break; case 0xB000: Map( i, &Vrc6::Poke_B000 ); break; case 0xB100: Map( i, &Vrc6::Poke_B001 ); break; case 0xB200: Map( i, &Vrc6::Poke_B002 ); break; case 0xB300: Map( i, &Vrc6::Poke_B003 ); break; case 0xD000: Map( i, CHR_SWAP_1K_0 ); break; case 0xD100: Map( i, CHR_SWAP_1K_1 ); break; case 0xD200: Map( i, CHR_SWAP_1K_2 ); break; case 0xD300: Map( i, CHR_SWAP_1K_3 ); break; case 0xE000: Map( i, CHR_SWAP_1K_4 ); break; case 0xE100: Map( i, CHR_SWAP_1K_5 ); break; case 0xE200: Map( i, CHR_SWAP_1K_6 ); break; case 0xE300: Map( i, CHR_SWAP_1K_7 ); break; case 0xF000: Map( i, &Vrc6::Poke_F000 ); break; case 0xF100: Map( i, &Vrc6::Poke_F001 ); break; case 0xF200: Map( i, &Vrc6::Poke_F002 ); break; } } } bool Vrc6::Sound::Square::CanOutput() const { return volume && enabled && !digitized && waveLength >= MIN_FRQ; } bool Vrc6::Sound::Saw::CanOutput() const { return enabled && phase && waveLength >= MIN_FRQ; } void Vrc6::Sound::Square::UpdateSettings(const uint fixed) { active = CanOutput(); frequency = (waveLength + 1U) * fixed; } void Vrc6::Sound::Saw::UpdateSettings(const uint fixed) { active = CanOutput(); frequency = ((waveLength + 1UL) << FRQ_SHIFT) * fixed; } bool Vrc6::Sound::UpdateSettings() { uint volume = GetVolume(EXT_VRC6); output = IsMuted() ? 0 : volume; GetOscillatorClock( rate, fixed ); for (uint i=0; i < 2; ++i) square[i].UpdateSettings( fixed ); saw.UpdateSettings( fixed ); dcBlocker.Reset(); return volume; } void Vrc6::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'K','V','6'>::V) ); if (baseChunk == AsciiId<'K','V','6'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'I','R','Q'>::V: irq.LoadState( state ); break; case AsciiId<'S','N','D'>::V: sound.LoadState( state ); break; } state.End(); } } } void Vrc6::SubSave(State::Saver& state) const { state.Begin( AsciiId<'K','V','6'>::V ); irq.SaveState( state, AsciiId<'I','R','Q'>::V ); sound.SaveState( state, AsciiId<'S','N','D'>::V ); state.End(); } void Vrc6::Sound::SaveState(State::Saver& state,const dword baseChunk) const { state.Begin( baseChunk ); square[0].SaveState( state, AsciiId<'S','Q','0'>::V ); square[1].SaveState( state, AsciiId<'S','Q','1'>::V ); saw.SaveState( state, AsciiId<'S','A','W'>::V ); state.End(); } void Vrc6::Sound::LoadState(State::Loader& state) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'S','Q','0'>::V: square[0].LoadState( state, fixed ); break; case AsciiId<'S','Q','1'>::V: square[1].LoadState( state, fixed ); break; case AsciiId<'S','A','W'>::V: saw.LoadState( state, fixed ); break; } state.End(); } } void Vrc6::Sound::Square::SaveState(State::Saver& state,const dword chunk) const { const byte data[4] = { (enabled ? 0x1U : 0x0U) | (digitized ? 0x2U : 0x0U), waveLength & 0xFF, waveLength >> 8, (duty - 1) | ((volume / VOLUME) << 3) }; state.Begin( chunk ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } void Vrc6::Sound::Square::LoadState(State::Loader& state,const uint fixed) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<4> data( state ); enabled = data[0] & 0x1; digitized = data[0] & 0x2; waveLength = data[1] | (data[2] << 8 & 0xF00); duty = (data[3] & 0x7) + 1; volume = (data[3] >> 3 & 0xF) * VOLUME; timer = 0; step = 0; UpdateSettings( fixed ); } state.End(); } } void Vrc6::Sound::Saw::SaveState(State::Saver& state,const dword chunk) const { const byte data[3] = { (enabled != 0) | (phase << 1), waveLength & 0xFF, waveLength >> 8 }; state.Begin( chunk ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } void Vrc6::Sound::Saw::LoadState(State::Loader& state,const uint fixed) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<3> data( state ); enabled = data[0] & 0x1; phase = data[0] >> 1 & 0x3F; waveLength = data[1] | (data[2] << 8 & 0xF00); timer = 0; step = 0; amp = 0; UpdateSettings( fixed ); } state.End(); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NST_SINGLE_CALL void Vrc6::Sound::Square::WriteReg0(const uint data) { volume = (data & REG0_VOLUME) * VOLUME; duty = ((data & REG0_DUTY) >> REG0_DUTY_SHIFT) + 1; digitized = data & REG0_DIGITIZED; NST_VERIFY( !digitized ); active = CanOutput(); } NST_SINGLE_CALL void Vrc6::Sound::Square::WriteReg1(const uint data,const dword fixed) { waveLength &= uint(REG2_WAVELENGTH_HIGH) << 8; waveLength |= data; frequency = (waveLength + 1U) * fixed; active = CanOutput(); } NST_SINGLE_CALL void Vrc6::Sound::Square::WriteReg2(const uint data,const dword fixed) { waveLength &= REG1_WAVELENGTH_LOW; waveLength |= (data & REG2_WAVELENGTH_HIGH) << 8; frequency = (waveLength + 1U) * fixed; enabled = data & REG2_ENABLE; active = CanOutput(); } NST_SINGLE_CALL void Vrc6::Sound::Saw::WriteReg0(const uint data) { phase = data & REG0_PHASE; active = CanOutput(); } NST_SINGLE_CALL void Vrc6::Sound::Saw::WriteReg1(const uint data,const dword fixed) { waveLength &= uint(REG2_WAVELENGTH_HIGH) << 8; waveLength |= data; frequency = ((waveLength + 1UL) << FRQ_SHIFT) * fixed; active = CanOutput(); } NST_SINGLE_CALL void Vrc6::Sound::Saw::WriteReg2(const uint data,const dword fixed) { waveLength &= REG1_WAVELENGTH_LOW; waveLength |= (data & REG2_WAVELENGTH_HIGH) << 8; frequency = ((waveLength + 1UL) << FRQ_SHIFT) * fixed; enabled = data & REG2_ENABLE; active = CanOutput(); } void Vrc6::Sound::WriteSquareReg0(uint i,uint data) { Update(); square[i].WriteReg0( data ); } void Vrc6::Sound::WriteSquareReg1(uint i,uint data) { Update(); square[i].WriteReg1( data, fixed ); } void Vrc6::Sound::WriteSquareReg2(uint i,uint data) { Update(); square[i].WriteReg2( data, fixed ); } void Vrc6::Sound::WriteSawReg0(uint data) { Update(); saw.WriteReg0( data ); } void Vrc6::Sound::WriteSawReg1(uint data) { Update(); saw.WriteReg1( data, fixed ); } void Vrc6::Sound::WriteSawReg2(uint data) { Update(); saw.WriteReg2( data, fixed ); } NES_POKE_D(Vrc6,9000) { sound.WriteSquareReg0 ( 0, data ); } NES_POKE_D(Vrc6,9001) { sound.WriteSquareReg1 ( 0, data ); } NES_POKE_D(Vrc6,9002) { sound.WriteSquareReg2 ( 0, data ); } NES_POKE_D(Vrc6,A000) { sound.WriteSquareReg0 ( 1, data ); } NES_POKE_D(Vrc6,A001) { sound.WriteSquareReg1 ( 1, data ); } NES_POKE_D(Vrc6,A002) { sound.WriteSquareReg2 ( 1, data ); } NES_POKE_D(Vrc6,B000) { sound.WriteSawReg0 ( data ); } NES_POKE_D(Vrc6,B001) { sound.WriteSawReg1 ( data ); } NES_POKE_D(Vrc6,B002) { sound.WriteSawReg2 ( data ); } NST_SINGLE_CALL dword Vrc6::Sound::Square::GetSample(const Cycle rate) { NST_VERIFY( bool(active) == CanOutput() && timer >= 0 ); if (active) { dword sum = timer; timer -= idword(rate); if (timer >= 0) { return step < duty ? volume : 0; } else { if (step >= duty) sum = 0; do { step = (step + 1) & 0xF; if (step < duty) sum += NST_MIN(dword(-timer),frequency); timer += idword(frequency); } while (timer < 0); return (sum * volume + (rate/2)) / rate; } } return 0; } NST_SINGLE_CALL dword Vrc6::Sound::Saw::GetSample(const Cycle rate) { NST_VERIFY( bool(active) == CanOutput() && timer >= 0 ); if (active) { dword sum = timer; timer -= idword(rate); if (timer >= 0) { return (amp >> 3) * VOLUME; } else { sum *= amp; do { if (++step >= 0x7) { step = 0; amp = 0; } amp = (amp + phase) & 0xFF; sum += NST_MIN(dword(-timer),frequency) * amp; timer += idword(frequency); } while (timer < 0); return ((sum >> 3) * VOLUME + (rate / 2)) / rate; } } return 0; } Vrc6::Sound::Sample Vrc6::Sound::GetSample() { if (output) { dword sample = 0; for (uint i=0; i < 2; ++i) sample += square[i].GetSample( rate ); sample += saw.GetSample( rate ); return dcBlocker.Apply( sample * output / DEFAULT_VOLUME ); } else { return 0; } } NES_POKE_D(Vrc6,B003) { SetMirroringVH01( data >> 2 ); } NES_POKE_D(Vrc6,F000) { irq.Update(); irq.unit.latch = data; } NES_POKE_D(Vrc6,F001) { irq.Toggle( data ); } NES_POKE(Vrc6,F002) { irq.Toggle(); } void Vrc6::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardKonamiVrc6.hpp000066400000000000000000000112361411157722000230700ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_KONAMI_VRC6_H #define NST_BOARD_KONAMI_VRC6_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Konami { class Vrc6 : public Board { public: explicit Vrc6(const Context&); class Sound : public Apu::Channel { public: explicit Sound(Apu&,bool=true); void WriteSquareReg0 (uint,uint); void WriteSquareReg1 (uint,uint); void WriteSquareReg2 (uint,uint); void WriteSawReg0 (uint); void WriteSawReg1 (uint); void WriteSawReg2 (uint); void SaveState(State::Saver&,dword) const; void LoadState(State::Loader&); protected: void Reset(); bool UpdateSettings(); Sample GetSample(); private: class BaseChannel { protected: void Reset(); ibool enabled; uint waveLength; ibool active; idword timer; Cycle frequency; uint step; }; class Square : BaseChannel { public: void Reset(); NST_SINGLE_CALL dword GetSample(Cycle); NST_SINGLE_CALL void WriteReg0(uint); NST_SINGLE_CALL void WriteReg1(uint,dword); NST_SINGLE_CALL void WriteReg2(uint,dword); void SaveState(State::Saver&,dword) const; void LoadState(State::Loader&,uint); void UpdateSettings(uint); private: bool CanOutput() const; enum { VOLUME = OUTPUT_MUL * 2, MIN_FRQ = 0x04 }; enum { REG0_VOLUME = 0x0F, REG0_DUTY = 0x70, REG0_DIGITIZED = 0x80, REG1_WAVELENGTH_LOW = 0xFF, REG2_WAVELENGTH_HIGH = 0x0F, REG2_ENABLE = 0x80, REG0_DUTY_SHIFT = 4 }; uint duty; dword volume; ibool digitized; }; class Saw : BaseChannel { public: void Reset(); NST_SINGLE_CALL dword GetSample(Cycle); NST_SINGLE_CALL void WriteReg0(uint); NST_SINGLE_CALL void WriteReg1(uint,dword); NST_SINGLE_CALL void WriteReg2(uint,dword); void SaveState(State::Saver&,dword) const; void LoadState(State::Loader&,uint); void UpdateSettings(uint); private: bool CanOutput() const; enum { VOLUME = OUTPUT_MUL * 2, MIN_FRQ = 0x4, FRQ_SHIFT = 1 }; enum { REG0_PHASE = 0x3F, REG1_WAVELENGTH_LOW = 0xFF, REG2_WAVELENGTH_HIGH = 0x0F, REG2_ENABLE = 0x80 }; uint phase; dword amp; }; uint output; Cycle rate; uint fixed; Square square[2]; Saw saw; DcBlocker dcBlocker; }; private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Sync(Event,Input::Controllers*); static uint GetPrgLineShift(const Context&,uint,uint); NES_DECL_POKE( 9000 ); NES_DECL_POKE( 9001 ); NES_DECL_POKE( 9002 ); NES_DECL_POKE( A000 ); NES_DECL_POKE( A001 ); NES_DECL_POKE( A002 ); NES_DECL_POKE( B000 ); NES_DECL_POKE( B001 ); NES_DECL_POKE( B002 ); NES_DECL_POKE( B003 ); NES_DECL_POKE( F000 ); NES_DECL_POKE( F001 ); NES_DECL_POKE( F002 ); Vrc4::Irq irq; Sound sound; const uint prgLineA; const uint prgLineB; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardKonamiVrc7.cpp000066400000000000000000000644711411157722000230750ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include #include "NstBoard.hpp" #include "../NstTimer.hpp" #include "../NstFpuPrecision.hpp" #include "NstBoardKonamiVrc4.hpp" #include "NstBoardKonamiVrc7.hpp" //////////////////////////////////////////////////////////////////////////////////////// // // VRC7 Sound Reference: // // emu2413.c -- a YM2413 emulator : written by Mitsutaka Okazaki 2001 // // 2019-03-19 -- VRC7 instrument patchset dumped by Nuke.YKT */ // https://siliconpr0n.org/archive/doku.php?id=vendor:yamaha:opl2#vrc7_instrument_rom_dump // //////////////////////////////////////////////////////////////////////////////////////// namespace Nes { namespace Core { namespace Boards { namespace Konami { const byte Vrc7::Sound::OpllChannel::Patch::preset[15][8] = { {0x03,0x21,0x05,0x06,0xE8,0x81,0x42,0x27 }, // Violin {0x13,0x41,0x14,0x0D,0xD8,0xF6,0x23,0x12 }, // Guitar {0x11,0x11,0x08,0x08,0xFA,0xB2,0x20,0x12 }, // Piano {0x31,0x61,0x0C,0x07,0xA8,0x64,0x61,0x27 }, // Flute {0x32,0x21,0x1E,0x06,0xE1,0x76,0x01,0x28 }, // Clarinet {0x02,0x01,0x06,0x00,0xA3,0xE2,0xF4,0xF4 }, // Oboe {0x21,0x61,0x1D,0x07,0x82,0x81,0x11,0x07 }, // Trumpet {0x23,0x21,0x22,0x17,0xA2,0x72,0x01,0x17 }, // Organ {0x35,0x11,0x25,0x00,0x40,0x73,0x72,0x01 }, // Horn {0xB5,0x01,0x0F,0x0F,0xA8,0xA5,0x51,0x02 }, // Synthesizer {0x17,0xC1,0x24,0x07,0xF8,0xF8,0x22,0x12 }, // Harpsichord {0x71,0x23,0x11,0x06,0x65,0x74,0x18,0x16 }, // Vibraphone {0x01,0x02,0xD3,0x05,0xC9,0x95,0x03,0x02 }, // Synthesizer Bass {0x61,0x63,0x0C,0x00,0x94,0xC0,0x33,0xF6 }, // Acoustic Bass {0x21,0x72,0x0D,0x00,0xC1,0xD5,0x56,0x06 } // Electric Guitar }; #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Vrc7::Sound::Tables::Tables() { FpuPrecision precision; const double pi2 = 6.2831853071795863; for (uint i=0; i < PITCH_SIZE; ++i) pitch[i] = AMP_SIZE * powf( 2, 13.75 * std::sin( pi2 * i / PITCH_SIZE ) / 1200 ); for (uint i=0; i < AMP_SIZE; ++i) amp[i] = 4.8 / 2 / 0.1875 * (1 + std::sin( pi2 * i / AMP_SIZE )); lin2log[0] = 128; for (uint i=1; i < LIN2LOG_SIZE; ++i) lin2log[i] = 128 - 1 - 128 * std::log( double(i) ) / std::log( 128.0 ); for (uint i=0; i < 16; ++i) { for (uint j=0; j < 16; ++j) { uint rm = i + (j >> 2); uint rl = j & 3; if (rm > 15) rm = 15; // Attack if (i == 0 || i == 15) adr[0][i][j] = 0; else adr[0][i][j] = (3UL * (rl + 4)) << (rm + 1); // Decay & Release if (i == 0) adr[1][i][j] = 0; else adr[1][i][j] = (1UL * (rl + 4)) << (rm - 1); } } for (uint i=0; i < WAVE_SIZE/4; ++i) { uint v = EG_MUTE; const double d = std::sin( pi2 * i / WAVE_SIZE ); if (d > DBL_EPSILON) { const long m = -(20 * std::log10( d ) / 0.1875); if (m < EG_MUTE) v = m; } wave[0][i] = v; } for (uint i=0; i < WAVE_SIZE/4; ++i) wave[0][WAVE_SIZE/2-1 - i] = wave[0][i]; for (uint i=0; i < WAVE_SIZE/2; ++i) wave[0][WAVE_SIZE/2 + i] = (DB2LIN_SIZE/2 + wave[0][i]); for (uint i=0; i < WAVE_SIZE/2; ++i) wave[1][i] = wave[0][i]; for (uint i=WAVE_SIZE/2; i < WAVE_SIZE; ++i) wave[1][i] = wave[0][0]; for (uint i=0; i < DB2LIN_SIZE/2; ++i) { if (i < EG_MUTE) db2lin[i] = 0x7FF * std::pow( 10.0, -(i * 0.1875 / 20) ); else db2lin[i] = 0; db2lin[DB2LIN_SIZE/2 + i] = -db2lin[i]; } for (uint i=0; i < 2; ++i) { for (uint j=0; j < 8; ++j) { for (uint k=0; k < 2; ++k) { sl[i][j][k] = k ? (j << 1) + i : (j >> 1); } } } for (uint i=0; i < 16; ++i) { for (uint j=0; j < 8; ++j) { for (uint t=0; t < 64; ++t) { for (uint k=0; k < 4; ++k) { uint val = t * 2; if (k) { static const word lut[16] = { 0, 18000, 24000, 27750, 30000, 32250, 33750, 35250, 36000, 37500, 38250, 39000, 39750, 40500, 41250, 42000 }; const idword tmp = idword(lut[i]) - 6000 * (7 - idword(j)); if (tmp > 0) val += ((tmp / 1000UL) >> (3-k)) * 1000 / 375; } tl[i][j][t][k] = val; } } } } for (uint i=0; i < 512; ++i) { for (uint j=0; j < 8; ++j) { for (uint ml=0; ml < 16; ++ml) { static const byte lut[16] = { 1 * 1, 1 * 2, 2 * 2, 3 * 2, 4 * 2, 5 * 2, 6 * 2, 7 * 2, 8 * 2, 9 * 2, 10 * 2, 10 * 2, 12 * 2, 12 * 2, 15 * 2, 15 * 2 }; phase[i][j][ml] = (dword(i * lut[ml]) << j) >> 2; } } } } Vrc7::Sound::Sound(Apu& a,bool connect) : Channel(a) { Reset(); bool audible = UpdateSettings(); if (connect) Connect( audible ); } Vrc7::Vrc7(const Context& c) : Board (c), irq (*c.cpu), sound (*c.apu) {} void Vrc7::SubReset(const bool hard) { for (dword i=0x8000; i <= 0xFFFF; ++i) { switch (i & 0xF038) { case 0x8000: Map( i, PRG_SWAP_8K_0 ); break; case 0x8008: case 0x8010: Map( i, PRG_SWAP_8K_1 ); break; case 0x9000: Map( i, PRG_SWAP_8K_2 ); break; case 0x9010: case 0x9018: Map( i, &Vrc7::Poke_9010 ); break; case 0x9030: case 0x9038: Map( i, &Vrc7::Poke_9030 ); break; case 0xA000: Map( i, CHR_SWAP_1K_0 ); break; case 0xA008: case 0xA010: Map( i, CHR_SWAP_1K_1 ); break; case 0xB000: Map( i, CHR_SWAP_1K_2 ); break; case 0xB008: case 0xB010: Map( i, CHR_SWAP_1K_3 ); break; case 0xC000: Map( i, CHR_SWAP_1K_4 ); break; case 0xC008: case 0xC010: Map( i, CHR_SWAP_1K_5 ); break; case 0xD000: Map( i, CHR_SWAP_1K_6 ); break; case 0xD008: case 0xD010: Map( i, CHR_SWAP_1K_7 ); break; case 0xE000: Map( i, NMT_SWAP_VH01 ); break; case 0xE008: case 0xE010: Map( i, &Vrc7::Poke_E008 ); break; case 0xF000: Map( i, &Vrc7::Poke_F000 ); break; case 0xF008: case 0xF010: Map( i, &Vrc7::Poke_F008 ); break; } } irq.Reset( hard, hard ? false : irq.Connected() ); if (hard) prg.SwapBanks(0U,0U,0U,~0U); } void Vrc7::Sound::OpllChannel::Reset() { frequency = 0; key = 0; sustain = 0; block = 0; volume = 0; feedback = 0; patch.instrument = 0; std::memset( patch.tone, 0, sizeof(patch.tone) ); std::memset( patch.custom, 0, sizeof(patch.tone) ); for (uint i=0; i < NUM_SLOTS; ++i) { slots[i].pg.phase = 0; slots[i].pg.counter = 0; slots[i].eg.mode = EG_SETTLE; slots[i].eg.counter = EG_BEGIN; slots[i].eg.phase = 0; slots[i].tl = 0; slots[i].sl = 0; slots[i].output = 0; } } void Vrc7::Sound::Reset() { regSelect = 0; for (uint i=0; i < NUM_OPLL_CHANNELS; ++i) channels[i].Reset(); ResetClock(); } void Vrc7::Sound::ResetClock() { sampleRate = 0x80000000UL / GetSampleRate(); samplePhase = 0; prevSample = 0; nextSample = 0; ampPhase = 0; pitchPhase = 0; } void Vrc7::Sound::Refresh() { ResetClock(); for (uint i=0; i < NUM_OPLL_CHANNELS; ++i) channels[i].Update( tables ); } bool Vrc7::Sound::UpdateSettings() { uint volume = GetVolume(EXT_VRC7); output = IsMuted() ? 0 : volume; Refresh(); return volume; } void Vrc7::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'K','V','7'>::V) ); if (baseChunk == AsciiId<'K','V','7'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'I','R','Q'>::V: irq.LoadState( state ); break; case AsciiId<'S','N','D'>::V: sound.LoadState( state ); break; } state.End(); } } } void Vrc7::SubSave(State::Saver& state) const { state.Begin( AsciiId<'K','V','7'>::V ); irq.SaveState( state, AsciiId<'I','R','Q'>::V ); sound.SaveState( state, AsciiId<'S','N','D'>::V ); state.End(); } void Vrc7::Sound::SaveState(State::Saver& state,const dword baseChunk) const { state.Begin( baseChunk ); state.Begin( AsciiId<'R','E','G'>::V ).Write8( regSelect ).End(); for (uint i=0; i < NUM_OPLL_CHANNELS; ++i) channels[i].SaveState( state, AsciiId<'C','H','0'>::R(0,0,i) ); state.End(); } void Vrc7::Sound::LoadState(State::Loader& state) { Refresh(); while (dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: regSelect = state.Read8(); break; case AsciiId<'C','H','0'>::V: case AsciiId<'C','H','1'>::V: case AsciiId<'C','H','2'>::V: case AsciiId<'C','H','3'>::V: case AsciiId<'C','H','4'>::V: case AsciiId<'C','H','5'>::V: chunk = (chunk >> 16 & 0xFF) - Ascii<'0'>::V; if (chunk < NUM_OPLL_CHANNELS) channels[chunk].LoadState( state, tables ); break; } state.End(); } } void Vrc7::Sound::OpllChannel::SaveState(State::Saver& state,const dword chunk) const { const byte data[11] = { patch.custom[0], patch.custom[1], patch.custom[2], patch.custom[3], patch.custom[4], patch.custom[5], patch.custom[6], patch.custom[7], frequency & REG8_FRQ_LO, (frequency >> 8) | (block << 1) | (sustain ? REG9_SUSTAIN : 0) | (key ? REG9_KEY : 0), (volume >> 2) | (patch.instrument << 4) }; state.Begin( chunk ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } void Vrc7::Sound::OpllChannel::LoadState(State::Loader& state,const Tables& tables) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<11> data( state ); for (uint i=0; i < 8; ++i) patch.custom[i] = data[i]; frequency = (data[8] & REG8_FRQ_LO) | (data[9] & REG9_FRQ_HI) << 8; block = (data[9] & REG9_BLOCK) >> 1; sustain = data[9] & REG9_SUSTAIN; key = data[9] & REG9_KEY; volume = (data[10] & REGA_VOLUME) << 2; patch.instrument = (data[10] & REGA_INSTRUMENT) >> 4; std::memcpy( patch.tone, patch.instrument == Patch::CUSTOM ? patch.custom : Patch::preset[patch.instrument-1], 8 ); feedback = 0; Update( tables ); } state.End(); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Vrc7,9010) { sound.SelectReg( data ); } NES_POKE_D(Vrc7,9030) { sound.WriteReg( data ); } NES_POKE_D(Vrc7,E008) { irq.Update(); irq.unit.latch = data; } NES_POKE_D(Vrc7,F000) { irq.Toggle( data ); } NES_POKE(Vrc7,F008) { irq.Toggle(); } void Vrc7::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } inline uint Vrc7::Sound::Tables::GetAmp(uint i) const { NST_ASSERT( i < AMP_SIZE ); return amp[i]; } inline uint Vrc7::Sound::Tables::GetPitch(uint i) const { NST_ASSERT( i < PITCH_SIZE ); return pitch[i]; } inline uint Vrc7::Sound::Tables::GetTotalLevel(uint frequency,uint block,uint volume,uint tone) const { NST_ASSERT( (frequency >> 5) < 16 && block < 8 && volume < TL_SIZE && tone < 4 ); return tl[frequency >> 5][block][volume][tone]; } inline uint Vrc7::Sound::Tables::GetSustainLevel(uint frequency,uint block,uint rate) const { NST_ASSERT( (frequency >> 8) < 2 && block < 8 && rate < 2 ); return sl[frequency >> 8][block][rate]; } inline uint Vrc7::Sound::Tables::GetLog(uint egOut) const { NST_ASSERT( egOut < LIN2LOG_SIZE ); return lin2log[egOut]; } inline dword Vrc7::Sound::Tables::GetAttack(uint tone,uint pos) const { NST_ASSERT( tone < 16 && pos < 16 ); return adr[0][tone][pos]; } inline dword Vrc7::Sound::Tables::GetDecay(uint tone,uint pos) const { NST_ASSERT( tone < 16 && pos < 16 ); return adr[1][tone][pos]; } inline dword Vrc7::Sound::Tables::GetSustain(uint tone,uint pos) const { return GetDecay( tone, pos ); } inline dword Vrc7::Sound::Tables::GetRelease(uint tone,uint pos) const { return GetDecay( tone, pos ); } inline dword Vrc7::Sound::Tables::GetPhase(uint frequency,uint block,uint tone) const { NST_ASSERT( frequency < 512 && block < 8 && tone < 16 ); return phase[frequency][block][tone]; } inline Vrc7::Sound::Sample Vrc7::Sound::Tables::GetOutput(uint form,uint pgOut,uint egOut) const { NST_ASSERT( form < 2 && pgOut < WAVE_SIZE && wave[form][pgOut] + egOut < DB2LIN_SIZE ); return db2lin[wave[form][pgOut] + egOut]; } void Vrc7::Sound::OpllChannel::UpdateEgPhase(const Tables& tables,const uint i) { NST_ASSERT( i < NUM_SLOTS ); switch (slots[i].eg.mode) { case EG_ATTACK: slots[i].eg.phase = tables.GetAttack( patch.tone[4+i] >> 4, slots[i].sl ); break; case EG_DECAY: slots[i].eg.phase = tables.GetDecay( patch.tone[4+i] & uint(REG45_DECAY), slots[i].sl ); break; case EG_SUSTAIN: slots[i].eg.phase = tables.GetSustain( patch.tone[6+i] & uint(REG67_RELEASE), slots[i].sl ); break; case EG_RELEASE: if (i != MODULATOR && sustain) { slots[i].eg.phase = tables.GetRelease( 5, slots[i].sl ); } else if (patch.tone[0+i] & uint(REG01_HOLD)) { slots[i].eg.phase = tables.GetRelease( patch.tone[6+i] & uint(REG67_RELEASE), slots[i].sl ); } else { slots[i].eg.phase = tables.GetRelease( 7, slots[i].sl ); } break; default: slots[i].eg.phase = 0; break; } } void Vrc7::Sound::OpllChannel::UpdatePhase(const Tables& tables,const uint i) { NST_ASSERT( i < NUM_SLOTS ); slots[i].pg.phase = tables.GetPhase( frequency, block, patch.tone[0+i] & uint(REG01_MULTIPLE) ); } void Vrc7::Sound::OpllChannel::UpdateSustainLevel(const Tables& tables,const uint i) { NST_ASSERT( i < NUM_SLOTS ); slots[i].sl = tables.GetSustainLevel( frequency, block, (patch.tone[0+i] & uint(REG01_RATE)) >> 4 ); } void Vrc7::Sound::OpllChannel::UpdateTotalLevel(const Tables& tables,const uint i) { NST_ASSERT( i < NUM_SLOTS ); slots[i].tl = tables.GetTotalLevel( frequency, block, (i != MODULATOR) ? volume : (patch.tone[2] & uint(REG2_TOTAL_LEVEL)), patch.tone[2+i] >> 6 ); } void Vrc7::Sound::OpllChannel::Update(const Tables& tables) { for (uint i=0; i < NUM_SLOTS; ++i) { UpdateSustainLevel( tables, i ); UpdateTotalLevel( tables, i ); UpdateEgPhase( tables, i ); UpdatePhase( tables, i ); } } NST_SINGLE_CALL void Vrc7::Sound::OpllChannel::WriteReg0(const uint data,const Tables& tables) { patch.custom[0] = data; if (patch.instrument == Patch::CUSTOM) { patch.tone[0] = data; UpdateSustainLevel( tables, 0 ); UpdateEgPhase( tables, 0 ); UpdatePhase( tables, 0 ); } } NST_SINGLE_CALL void Vrc7::Sound::OpllChannel::WriteReg1(const uint data,const Tables& tables) { patch.custom[1] = data; if (patch.instrument == Patch::CUSTOM) { patch.tone[1] = data; UpdateSustainLevel( tables, 1 ); UpdateEgPhase( tables, 1 ); UpdatePhase( tables, 1 ); } } NST_SINGLE_CALL void Vrc7::Sound::OpllChannel::WriteReg2(const uint data,const Tables& tables) { patch.custom[2] = data; if (patch.instrument == Patch::CUSTOM) { patch.tone[2] = data; UpdateTotalLevel( tables, 0 ); } } NST_SINGLE_CALL void Vrc7::Sound::OpllChannel::WriteReg3(const uint data) { patch.custom[3] = data; if (patch.instrument == Patch::CUSTOM) patch.tone[3] = data; } NST_SINGLE_CALL void Vrc7::Sound::OpllChannel::WriteReg4(const uint data,const Tables& tables) { patch.custom[4] = data; if (patch.instrument == Patch::CUSTOM) { patch.tone[4] = data; UpdateEgPhase( tables, 0 ); } } NST_SINGLE_CALL void Vrc7::Sound::OpllChannel::WriteReg5(const uint data,const Tables& tables) { patch.custom[5] = data; if (patch.instrument == Patch::CUSTOM) { patch.tone[5] = data; UpdateEgPhase( tables, 1 ); } } NST_SINGLE_CALL void Vrc7::Sound::OpllChannel::WriteReg6(const uint data,const Tables& tables) { patch.custom[6] = data; if (patch.instrument == Patch::CUSTOM) { patch.tone[6] = data; UpdateEgPhase( tables, 0 ); } } NST_SINGLE_CALL void Vrc7::Sound::OpllChannel::WriteReg7(const uint data,const Tables& tables) { patch.custom[7] = data; if (patch.instrument == Patch::CUSTOM) { patch.tone[7] = data; UpdateEgPhase( tables, 1 ); } } NST_SINGLE_CALL void Vrc7::Sound::OpllChannel::WriteReg8(const uint data,const Tables& tables) { frequency = (frequency & (uint(REG9_FRQ_HI) << 8)) | data; Update( tables ); } NST_SINGLE_CALL void Vrc7::Sound::OpllChannel::WriteReg9(const uint data,const Tables& tables) { frequency = (frequency & REG8_FRQ_LO) | ((data & REG9_FRQ_HI) << 8); block = (data & REG9_BLOCK) >> 1; sustain = data & REG9_SUSTAIN; if ((data ^ key) & REG9_KEY) { key = data & REG9_KEY; if (key) { for (uint i=0; i < NUM_SLOTS; ++i) { slots[i].eg.mode = EG_ATTACK; slots[i].eg.counter = 0; slots[i].pg.counter = 0; } } else { if (slots[CARRIER].eg.mode == EG_ATTACK) slots[CARRIER].eg.counter = dword(tables.GetLog( slots[CARRIER].eg.counter >> EG_PHASE_SHIFT )) << EG_PHASE_SHIFT; slots[CARRIER].eg.mode = EG_RELEASE; } } Update( tables ); } NST_SINGLE_CALL void Vrc7::Sound::OpllChannel::WriteRegA(uint data,const Tables& tables) { volume = (data & REGA_VOLUME) << 2; data >>= 4; if (patch.instrument != data) { patch.instrument = data; std::memcpy( patch.tone, patch.instrument == Patch::CUSTOM ? patch.custom : Patch::preset[patch.instrument-1], 8 ); } Update( tables ); } void Vrc7::Sound::WriteReg(const uint data) { Update(); switch (regSelect & 0x3F) { case 0x00: for (uint i=0; i < NUM_OPLL_CHANNELS; ++i) channels[i].WriteReg0( data, tables ); break; case 0x01: for (uint i=0; i < NUM_OPLL_CHANNELS; ++i) channels[i].WriteReg1( data, tables ); break; case 0x02: for (uint i=0; i < NUM_OPLL_CHANNELS; ++i) channels[i].WriteReg2( data, tables ); break; case 0x03: for (uint i=0; i < NUM_OPLL_CHANNELS; ++i) channels[i].WriteReg3( data ); break; case 0x04: for (uint i=0; i < NUM_OPLL_CHANNELS; ++i) channels[i].WriteReg4( data, tables ); break; case 0x05: for (uint i=0; i < NUM_OPLL_CHANNELS; ++i) channels[i].WriteReg5( data, tables ); break; case 0x06: for (uint i=0; i < NUM_OPLL_CHANNELS; ++i) channels[i].WriteReg6( data, tables ); break; case 0x07: for (uint i=0; i < NUM_OPLL_CHANNELS; ++i) channels[i].WriteReg7( data, tables ); break; case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: channels[regSelect - 0x10].WriteReg8( data, tables ); break; case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: channels[regSelect - 0x20].WriteReg9( data, tables ); break; case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: channels[regSelect - 0x30].WriteRegA( data, tables ); break; } } NST_SINGLE_CALL Vrc7::Sound::Sample Vrc7::Sound::OpllChannel::GetSample(const uint pitch,const uint amp,const Tables& tables) { uint pgOut[NUM_SLOTS], egOut[NUM_SLOTS]; for (uint i=0; i < NUM_SLOTS; ++i) { if (patch.tone[i] & uint(REG01_USE_VIBRATO)) slots[i].pg.counter += (slots[i].pg.phase * pitch) >> AMP_SHIFT; else slots[i].pg.counter += slots[i].pg.phase; slots[i].pg.counter &= PG_PHASE_RANGE; pgOut[i] = slots[i].pg.counter >> PG_PHASE_SHIFT; egOut[i] = slots[i].eg.counter >> EG_PHASE_SHIFT; switch (slots[i].eg.mode) { case EG_ATTACK: egOut[i] = tables.GetLog( egOut[i] ); slots[i].eg.counter += slots[i].eg.phase; if (slots[i].eg.counter >= EG_BEGIN || (patch.tone[4+i] & uint(REG45_ATTACK)) == REG45_ATTACK) { egOut[i] = 0; slots[i].eg.counter = 0; slots[i].eg.mode = EG_DECAY; UpdateEgPhase( tables, i ); } break; case EG_DECAY: { slots[i].eg.counter += slots[i].eg.phase; dword level = patch.tone[6+i] & uint(REG67_SUSTAIN_LEVEL); if (level == REG67_SUSTAIN_LEVEL) level = SUSTAIN_LEVEL_MAX; level <<= (EG_PHASE_SHIFT-1); if (slots[i].eg.counter >= level) { slots[i].eg.counter = level; slots[i].eg.mode = (patch.tone[0+i] & uint(REG01_HOLD)) ? EG_HOLD : EG_SUSTAIN; UpdateEgPhase( tables, i ); } break; } case EG_HOLD: if (!(patch.tone[0+i] & uint(REG01_HOLD))) { slots[i].eg.mode = EG_SUSTAIN; UpdateEgPhase( tables, i ); } break; case EG_SUSTAIN: case EG_RELEASE: slots[i].eg.counter += slots[i].eg.phase; if (egOut[i] <= EG_END) break; slots[i].eg.mode = EG_FINISH; default: egOut[i] = EG_END; break; } egOut[i] = (egOut[i] + slots[i].tl) * 2; if (patch.tone[i+0] & uint(REG01_USE_AMP)) egOut[i] += amp; } if (slots[CARRIER].eg.mode == EG_FINISH) return 0; Sample output = slots[MODULATOR].output; if (egOut[MODULATOR] >= EG_MUTE) { slots[MODULATOR].output = 0; } else { if (const uint fb = (patch.tone[3] & uint(REG3_FEEDBACK))) pgOut[MODULATOR] = uint(int(pgOut[MODULATOR]) + signed_shr(feedback,FEEDBACK_SHIFT-fb)) & WAVE_RANGE; slots[MODULATOR].output = tables.GetOutput( (patch.tone[3] & uint(REG3_MODULATED_WAVE)) >> 3, pgOut[MODULATOR], egOut[MODULATOR] ); } feedback = (output + slots[MODULATOR].output) / 2; output = slots[CARRIER].output; if (egOut[CARRIER] >= EG_MUTE) slots[CARRIER].output = 0; else slots[CARRIER].output = tables.GetOutput( (patch.tone[3] & uint(REG3_CARRIER_WAVE)) >> 4, uint(int(pgOut[CARRIER]) + feedback) & WAVE_RANGE, egOut[CARRIER] ); return (output + slots[CARRIER].output) / 2; } Vrc7::Sound::Sample Vrc7::Sound::GetSample() { if (output) { while (samplePhase < sampleRate) { samplePhase += CLOCK_RATE; pitchPhase = (pitchPhase + PITCH_RATE) & PITCH_RANGE; ampPhase = (ampPhase + AMP_RATE) & AMP_RANGE; const uint lfo[2] = { tables.GetPitch( pitchPhase >> PITCH_SHIFT ), tables.GetAmp( ampPhase >> AMP_SHIFT ) }; prevSample = nextSample; nextSample = 0; for (uint i=0; i < NUM_OPLL_CHANNELS; ++i) nextSample += channels[i].GetSample( lfo[0], lfo[1], tables ); } samplePhase -= sampleRate; return signed_shl( (prevSample * idword(samplePhase) + nextSample * idword(CLOCK_RATE - samplePhase)) / idword(CLOCK_RATE), 3 ) * idword(output) / DEFAULT_VOLUME; } else { return 0; } } } } } } nestopia-1.51.1/source/core/board/NstBoardKonamiVrc7.hpp000066400000000000000000000162171411157722000230750ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_KONAMI_VRC7_H #define NST_BOARD_KONAMI_VRC7_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Konami { class Vrc7 : public Board { public: explicit Vrc7(const Context&); class Sound : public Apu::Channel { public: explicit Sound(Apu&,bool=true); void WriteReg(uint); void SaveState(State::Saver&,dword) const; void LoadState(State::Loader&); protected: void Reset(); bool UpdateSettings(); Sample GetSample(); private: void ResetClock(); void Refresh(); enum { EG_PHASE_SHIFT = 15, EG_MUTE = 0xFF, EG_END = 0x7F, PG_PHASE_SHIFT = 9, WAVE_SIZE = 0x200, WAVE_RANGE = WAVE_SIZE-1, PITCH_SHIFT = 8, PITCH_SIZE = 0x100, PITCH_RANGE = 0xFFFF, AMP_SHIFT = 8, AMP_SIZE = 0x100, AMP_RANGE = 0xFFFF, LIN2LOG_SIZE = 0x80, DB2LIN_SIZE = 0x400, TL_SIZE = 0x40, FEEDBACK_SHIFT = 8, CLOCK_DIV = 3579545 / 72, CLOCK_RATE = (1UL << 31) / CLOCK_DIV, PG_PHASE_RANGE = (1UL << 18) - 1, EG_BEGIN = 1UL << 22, PITCH_RATE = 64UL * (1UL << 16) / CLOCK_DIV / 10, AMP_RATE = 37UL * (1UL << 16) / CLOCK_DIV / 10 }; class Tables { public: Tables(); inline uint GetAmp(uint) const; inline uint GetPitch(uint) const; inline uint GetSustainLevel(uint,uint,uint) const; inline uint GetTotalLevel(uint,uint,uint,uint) const; inline uint GetLog(uint) const; inline dword GetAttack(uint,uint) const; inline dword GetDecay(uint,uint) const; inline dword GetSustain(uint,uint) const; inline dword GetRelease(uint,uint) const; inline dword GetPhase(uint,uint,uint) const; inline Sample GetOutput(uint,uint,uint) const; private: word pitch[PITCH_SIZE]; byte amp[AMP_SIZE]; byte lin2log[LIN2LOG_SIZE]; dword adr[2][16][16]; word wave[2][WAVE_SIZE]; iword db2lin[DB2LIN_SIZE]; byte sl[2][8][2]; byte tl[16][8][TL_SIZE][4]; dword phase[512][8][16]; }; enum { NUM_OPLL_CHANNELS = 6 }; class OpllChannel { public: void Reset(); void Update(const Tables&); void SaveState(State::Saver&,dword) const; void LoadState(State::Loader&,const Tables&); NST_SINGLE_CALL void WriteReg0 (uint,const Tables&); NST_SINGLE_CALL void WriteReg1 (uint,const Tables&); NST_SINGLE_CALL void WriteReg2 (uint,const Tables&); NST_SINGLE_CALL void WriteReg3 (uint); NST_SINGLE_CALL void WriteReg4 (uint,const Tables&); NST_SINGLE_CALL void WriteReg5 (uint,const Tables&); NST_SINGLE_CALL void WriteReg6 (uint,const Tables&); NST_SINGLE_CALL void WriteReg7 (uint,const Tables&); NST_SINGLE_CALL void WriteReg8 (uint,const Tables&); NST_SINGLE_CALL void WriteReg9 (uint,const Tables&); NST_SINGLE_CALL void WriteRegA (uint,const Tables&); NST_SINGLE_CALL Sample GetSample(uint,uint,const Tables&); private: void UpdatePhase (const Tables&,uint); void UpdateSustainLevel (const Tables&,uint); void UpdateTotalLevel (const Tables&,uint); void UpdateEgPhase (const Tables&,uint); enum Mode { EG_SETTLE, EG_ATTACK, EG_DECAY, EG_HOLD, EG_SUSTAIN, EG_RELEASE, EG_FINISH }; enum { REG01_MULTIPLE = 0x0F, REG01_RATE = 0x10, REG01_HOLD = 0x20, REG01_USE_VIBRATO = 0x40, REG01_USE_AMP = 0x80, REG2_TOTAL_LEVEL = 0x3F, REG3_FEEDBACK = 0x07, REG3_MODULATED_WAVE = 0x08, REG3_CARRIER_WAVE = 0x10, REG45_DECAY = 0x0F, REG45_ATTACK = 0xF0, REG67_RELEASE = 0x0F, REG67_SUSTAIN_LEVEL = 0xF0, REG8_FRQ_LO = 0xFF, REG9_FRQ_HI = 0x01, REG9_BLOCK = 0x0E, REG9_KEY = 0x10, REG9_SUSTAIN = 0x20, REGA_VOLUME = 0x0F, REGA_INSTRUMENT = 0xF0, SUSTAIN_LEVEL_MAX = 0x100 }; struct Patch { enum { CUSTOM }; uint instrument; byte tone[8]; byte custom[8]; static const byte preset[15][8]; }; enum { MODULATOR, CARRIER, NUM_SLOTS }; uint frequency; uint key; uint sustain; uint block; uint volume; Patch patch; struct { struct { dword phase; dword counter; } pg; struct { Mode mode; dword phase; dword counter; } eg; uint tl; uint sl; Sample output; } slots[NUM_SLOTS]; Sample feedback; }; uint output; uint regSelect; dword sampleRate; dword samplePhase; dword pitchPhase; dword ampPhase; Sample prevSample; Sample nextSample; OpllChannel channels[NUM_OPLL_CHANNELS]; const Tables tables; public: void SelectReg(uint data) { regSelect = data; } }; private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Sync(Event,Input::Controllers*); NES_DECL_POKE( 9010 ); NES_DECL_POKE( 9030 ); NES_DECL_POKE( E000 ); NES_DECL_POKE( E008 ); NES_DECL_POKE( F000 ); NES_DECL_POKE( F008 ); Vrc4::Irq irq; Sound sound; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardKonamiVsSystem.cpp000066400000000000000000000031561411157722000240420ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardKonamiVsSystem.hpp" namespace Nes { namespace Core { namespace Boards { namespace Konami { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void VsSystem::SubReset(bool) { Map( 0x8000U, 0x8FFFU, PRG_SWAP_8K_0 ); Map( 0xA000U, 0xAFFFU, PRG_SWAP_8K_1 ); Map( 0xC000U, 0xCFFFU, PRG_SWAP_8K_2 ); Map( 0xE000U, 0xEFFFU, CHR_SWAP_4K_0 ); Map( 0xF000U, 0xFFFFU, CHR_SWAP_4K_1 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } } } nestopia-1.51.1/source/core/board/NstBoardKonamiVsSystem.hpp000066400000000000000000000026641411157722000240520ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_KONAMI_VSSYSTEM_H #define NST_BOARD_KONAMI_VSSYSTEM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Konami { class VsSystem : public Board { public: explicit VsSystem(const Context& c) : Board(c) {} private: void SubReset(bool); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardMagicKidGoogoo.cpp000066400000000000000000000035751411157722000237350ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMagicKidGoogoo.hpp" namespace Nes { namespace Core { namespace Boards { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void MagicKidGoogoo::SubReset(const bool hard) { Map( 0x8000U, 0x9FFFU, &MagicKidGoogoo::Poke_8000 ); Map( 0xC000U, 0xDFFFU, &MagicKidGoogoo::Poke_8000 ); for (uint i=0x0000; i < 0x2000; i += 0x04) { Map( 0xA000U + i, CHR_SWAP_2K_0 ); Map( 0xA001U + i, CHR_SWAP_2K_1 ); Map( 0xA002U + i, CHR_SWAP_2K_2 ); Map( 0xA003U + i, CHR_SWAP_2K_3 ); } if (hard) prg.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(MagicKidGoogoo, 8000) { prg.SwapBank( (address >> 11) | (data & 0x07) ); } } } } nestopia-1.51.1/source/core/board/NstBoardMagicKidGoogoo.hpp000066400000000000000000000026601411157722000237340ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_MAGICKIDGOOGOO_H #define NST_BOARD_MAGICKIDGOOGOO_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { class MagicKidGoogoo : public Board { public: explicit MagicKidGoogoo(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardMagicSeries.cpp000066400000000000000000000032571411157722000233030ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMagicSeries.hpp" namespace Nes { namespace Core { namespace Boards { namespace MagicSeries { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void MagicDragon::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &MagicDragon::Poke_8000 ); if (hard) prg.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(MagicDragon,8000) { ppu.Update(); prg.SwapBank( data >> 1 ); chr.SwapBank( data ); } } } } } nestopia-1.51.1/source/core/board/NstBoardMagicSeries.hpp000066400000000000000000000027241411157722000233060ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_MAGICSERIES_H #define NST_BOARD_MAGICSERIES_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace MagicSeries { class MagicDragon : public Board { public: explicit MagicDragon(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardMmc1.cpp000066400000000000000000000147021411157722000217020ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstLog.hpp" #include "NstBoard.hpp" #include "NstBoardMmc1.hpp" #include "../NstFile.hpp" namespace Nes { namespace Core { namespace Boards { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Mmc1::Mmc1(const Context& c,Revision rev) : Board(c), revision(rev) { switch (rev) { case REV_A: Log::Flush( "Board: MMC rev. A" NST_LINEBREAK ); break; case REV_B1: Log::Flush( "Board: MMC rev. B1" NST_LINEBREAK ); break; case REV_B2: Log::Flush( "Board: MMC rev. B2" NST_LINEBREAK ); break; case REV_B3: Log::Flush( "Board: MMC rev. B3" NST_LINEBREAK ); break; } } void Mmc1::ResetRegisters() { serial.buffer = 0; serial.shifter = 0; regs[CTRL] = CTRL_HARD_RESET; regs[CHR0] = 0; regs[CHR1] = 0; regs[PRG0] = (revision == REV_B3 ? PRG0_WRAM_DISABLED : 0); } void Mmc1::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &Mmc1::Poke_8000 ); serial.ready = cpu.GetClock(Serial::RESET_CYCLES); if (hard) { ResetRegisters(); for (uint i=0; i < 4; ++i) UpdateRegisters( i ); } } void Mmc1::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'M','M','1'>::V) ); serial.ready = 0; if (baseChunk == AsciiId<'M','M','1'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<4+2> data( state ); for (uint i=0; i < 4; ++i) regs[i] = data[i] & 0x1F; serial.buffer = data[4] & 0x1F; serial.shifter = NST_MIN(data[5],5); } state.End(); } } } void Mmc1::SubSave(State::Saver& state) const { const byte data[4+2] = { regs[0], regs[1], regs[2], regs[3], serial.buffer, serial.shifter }; state.Begin( AsciiId<'M','M','1'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Mmc1::Save(File& file) const { uint offset = (board.GetWram() == SIZE_16K) ? SIZE_8K : 0; // SOROM if (board.HasBattery() && board.GetSavableWram()) file.Save( File::BATTERY, wrk.Source().Mem(offset), board.GetSavableWram() ); } void Mmc1::Load(File& file) { uint offset = (board.GetWram() == SIZE_16K) ? SIZE_8K : 0; // SOROM if (board.HasBattery() && board.GetSavableWram()) file.Load( File::BATTERY, wrk.Source().Mem(offset), board.GetSavableWram() ); } void Mmc1::UpdatePrg() { prg.SwapBanks ( (regs[CHR0] & 0x10U) | ((regs[PRG0] | 0x0U) & ((regs[CTRL] & uint(CTRL_PRG_SWAP_16K)) ? (regs[CTRL] & uint(CTRL_PRG_SWAP_LOW)) ? 0xF : 0x0 : 0xE)), (regs[CHR0] & 0x10U) | ((regs[PRG0] & 0xFU) | ((regs[CTRL] & uint(CTRL_PRG_SWAP_16K)) ? (regs[CTRL] & uint(CTRL_PRG_SWAP_LOW)) ? 0xF : 0x0 : 0x1)) ); } void Mmc1::UpdateWrk() { const dword size = board.GetWram(); if (revision != REV_A) { const uint enable = ~uint(regs[PRG0]) & PRG0_WRAM_DISABLED; wrk.Source().SetSecurity( enable, enable && size ); } if (size >= SIZE_16K) wrk.SwapBank( regs[CHR0] >> (2 + (size == SIZE_16K)) ); } void Mmc1::UpdateChr() const { ppu.Update(); const uint mode = regs[CTRL] >> 4 & 0x1U; chr.SwapBanks ( regs[CHR0] & (0x1E | mode), (regs[CHR0+mode] & 0x1FU) | (mode^1) ); } void Mmc1::UpdateNmt() { static const byte lut[4][4] = { {0,0,0,0}, {1,1,1,1}, {0,1,0,1}, {0,0,1,1} }; ppu.SetMirroring( lut[regs[CTRL] & uint(CTRL_MIRRORING)] ); } void Mmc1::UpdateRegisters(const uint index) { NST_ASSERT( index < 4 ); if (index != CHR1) { UpdatePrg(); UpdateWrk(); } if (index != PRG0) { if (index == CTRL) UpdateNmt(); UpdateChr(); } } NES_POKE_AD(Mmc1,8000) { if (cpu.GetCycles() >= serial.ready) { if (!(data & Serial::RESET_BIT)) { serial.buffer |= (data & 0x1) << serial.shifter++; if (serial.shifter != 5) return; serial.shifter = 0; data = serial.buffer; serial.buffer = 0; address = address >> 13 & 0x3; if (regs[address] != data) { regs[address] = data; UpdateRegisters( address ); } } else { serial.ready = cpu.GetCycles() + cpu.GetClock(Serial::RESET_CYCLES); serial.buffer = 0; serial.shifter = 0; if ((regs[CTRL] & uint(CTRL_WRITE_RESET)) != CTRL_WRITE_RESET) { regs[CTRL] |= uint(CTRL_WRITE_RESET); UpdateRegisters( CTRL ); } } } else { // looks like there's some protection from rapid writes on register // reset, otherwise games like 'AD&D Hillsfar' and 'Bill & Ted' will break NST_DEBUG_MSG("MMC1 PRG write ignored!"); } } void Mmc1::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) { if (serial.ready <= cpu.GetFrameCycles()) serial.ready = 0; else serial.ready -= cpu.GetFrameCycles(); } Board::Sync( event, controllers ); } } } } nestopia-1.51.1/source/core/board/NstBoardMmc1.hpp000066400000000000000000000047661411157722000217200ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_MMC1_H #define NST_BOARD_MMC1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { class NST_NO_VTABLE Mmc1 : public Board { public: enum Revision { REV_A, REV_B1, REV_B2, REV_B3 }; protected: explicit Mmc1(const Context&,Revision=REV_B2); void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void UpdatePrg(); void UpdateWrk(); void UpdateChr() const; void UpdateNmt(); void Sync(Event,Input::Controllers*); enum { CTRL, CHR0, CHR1, PRG0 }; enum { CTRL_MIRRORING = 0x03, CTRL_PRG_SWAP_LOW = 0x04, CTRL_PRG_SWAP_16K = 0x08, CTRL_CHR_SWAP_4K = 0x10, CTRL_WRITE_RESET = CTRL_PRG_SWAP_LOW|CTRL_PRG_SWAP_16K, CTRL_HARD_RESET = CTRL_WRITE_RESET|CTRL_MIRRORING, PRG0_WRAM_DISABLED = 0x10 }; private: void Save(File&) const; void Load(File&); void ResetRegisters(); virtual void NST_FASTCALL UpdateRegisters(uint); NES_DECL_POKE( 8000 ); struct Serial { enum { RESET_BIT = 0x80, RESET_CYCLES = 2 }; uint buffer; uint shifter; Cycle ready; }; Serial serial; protected: byte regs[4]; const Revision revision; }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardMmc2.cpp000066400000000000000000000063451411157722000217070ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc2.hpp" namespace Nes { namespace Core { namespace Boards { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Mmc2::SubReset(const bool hard) { if (hard) { selector[0] = 0; selector[1] = 2; banks[0] = 0; banks[1] = 0; banks[2] = 0; banks[3] = 0; prg.SwapBank(~0U); } chr.SetAccessor( this, &Mmc2::Access_Chr ); Map( 0xA000U, 0xAFFFU, PRG_SWAP_8K_0 ); Map( 0xB000U, 0xEFFFU, &Mmc2::Poke_B000 ); Map( 0xF000U, 0xFFFFU, NMT_SWAP_HV ); } void Mmc2::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'M','M','2'>::V) ); if (baseChunk == AsciiId<'M','M','2'>::V) { while (const dword subId = state.Begin()) { if (subId == AsciiId<'R','E','G'>::V) { State::Loader::Data<4+1> data( state ); banks[0] = data[0]; banks[1] = data[1]; banks[2] = data[2]; banks[3] = data[3]; selector[0] = 0 + (data[4] >> 0 & 0x1); selector[1] = 2 + (data[4] >> 1 & 0x1); } state.End(); } } } void Mmc2::SubSave(State::Saver& state) const { const byte data[4+1] = { banks[0], banks[1], banks[2], banks[3], selector[0] | (selector[1] - 2) << 1 }; state.Begin( AsciiId<'M','M','2'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_ACCESSOR(Mmc2,Chr) { const uint data = chr.Peek( address ); uint bank; switch (address & 0xFF8) { case 0xFD8: bank = (address >> 11 & 0x2) | 0x0; break; case 0xFE8: bank = (address >> 11 & 0x2) | 0x1; break; default: return data; } selector[address >> 12] = bank; chr.SwapBank( address & 0x1000, banks[bank] ); return data; } NES_POKE_AD(Mmc2,B000) { ppu.Update(); banks[(address - 0xB000) >> 12] = data; chr.SwapBanks( banks[selector[0]], banks[selector[1]] ); } } } } nestopia-1.51.1/source/core/board/NstBoardMmc2.hpp000066400000000000000000000030711411157722000217050ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_MMC2_H #define NST_BOARD_MMC2_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { class NST_NO_VTABLE Mmc2 : public Board { protected: explicit Mmc2(const Context& c) : Board(c) {} void SubReset(bool); private: void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); NES_DECL_POKE( B000 ); NES_DECL_ACCESSOR( Chr ); uint selector[2]; byte banks[4]; }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardMmc3.cpp000066400000000000000000000162641411157722000217110ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstLog.hpp" #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" namespace Nes { namespace Core { namespace Boards { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Mmc3::Mmc3(const Context& c,Revision revision) : Board (c), irq (*c.cpu,*c.ppu,revision != REV_A) { switch (revision) { case Mmc3::REV_A: Log::Flush( "Board: MMC rev. A" NST_LINEBREAK ); break; case Mmc3::REV_B: Log::Flush( "Board: MMC rev. B" NST_LINEBREAK ); break; case Mmc3::REV_C: Log::Flush( "Board: MMC rev. C" NST_LINEBREAK ); break; } } void Mmc3::BaseIrq::Reset(const bool hard) { if (hard) { count = 0; latch = 0; reload = false; enabled = false; } } void Mmc3::SubReset(const bool hard) { if (hard) { regs.ctrl0 = 0; regs.ctrl1 = 0; banks.prg[0] = 0x00; banks.prg[1] = 0x01; banks.prg[2] = 0x3E; banks.prg[3] = 0x3F; for (uint i=0; i < 8; ++i) banks.chr[i] = i; wrk.Source().SetSecurity( false, false ); } irq.Reset( hard ); for (uint i=0x0000; i < 0x2000; i += 0x2) { Map( 0x8000 + i, &Mmc3::Poke_8000 ); Map( 0x8001 + i, &Mmc3::Poke_8001 ); Map( 0xA001 + i, &Mmc3::Poke_A001 ); Map( 0xC000 + i, &Mmc3::Poke_C000 ); Map( 0xC001 + i, &Mmc3::Poke_C001 ); Map( 0xE000 + i, &Mmc3::Poke_E000 ); Map( 0xE001 + i, &Mmc3::Poke_E001 ); } if (board.GetNmt() != Type::NMT_FOURSCREEN) { for (uint i=0x0000; i < 0x2000; i += 0x2) Map( 0xA000 + i, NMT_SWAP_HV ); } UpdatePrg(); UpdateChr(); } void Mmc3::BaseIrq::LoadState(State::Loader& state) { State::Loader::Data<3> data( state ); enabled = data[0] & 0x1; reload = data[0] & 0x2; count = data[1]; latch = data[2]; } void Mmc3::BaseIrq::SaveState(State::Saver& state,const dword chunk) const { const byte data[3] = { (enabled ? 0x1U : 0x0U) | (reload ? 0x2U : 0x0U), count, latch }; state.Begin( chunk ).Write( data ).End(); } void Mmc3::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'M','M','3'>::V) ); if (baseChunk == AsciiId<'M','M','3'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: { State::Loader::Data<12> data( state ); regs.ctrl0 = data[0]; regs.ctrl1 = data[1]; banks.prg[0] = data[2] & 0x3FU; banks.prg[1] = data[3] & 0x3FU; banks.chr[0] = (data[6] & 0x7FU) << 1; banks.chr[1] = banks.chr[0] | 0x01U; banks.chr[2] = (data[7] & 0x7FU) << 1; banks.chr[3] = banks.chr[2] | 0x01U; banks.chr[4] = data[8]; banks.chr[5] = data[9]; banks.chr[6] = data[10]; banks.chr[7] = data[11]; break; } case AsciiId<'I','R','Q'>::V: irq.unit.LoadState( state ); break; } state.End(); } } } void Mmc3::SubSave(State::Saver& state) const { state.Begin( AsciiId<'M','M','3'>::V ); const byte data[12] = { regs.ctrl0, regs.ctrl1, banks.prg[0], banks.prg[1], 0x3E, 0x3F, banks.chr[0] >> 1, banks.chr[2] >> 1, banks.chr[4], banks.chr[5], banks.chr[6], banks.chr[7] }; state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End(); irq.unit.SaveState( state, AsciiId<'I','R','Q'>::V ); state.End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Mmc3,8000) { const uint diff = regs.ctrl0 ^ data; regs.ctrl0 = data; if (diff & 0x40) { const uint v[2] = { banks.prg[(data >> 5 & 0x2) ^ 0], banks.prg[(data >> 5 & 0x2) ^ 2] }; UpdatePrg( 0x0000, v[0] ); UpdatePrg( 0x4000, v[1] ); } if (diff & 0x80) UpdateChr(); } NES_POKE_D(Mmc3,8001) { uint address = regs.ctrl0 & 0x7; if (address < 6) { ppu.Update(); uint base = regs.ctrl0 << 5 & 0x1000; if (address < 2) { address <<= 1; base |= address << 10; UpdateChr( base | 0x0000, (banks.chr[address+0] = data & 0xFE) ); UpdateChr( base | 0x0400, (banks.chr[address+1] = data | 0x01) ); } else { UpdateChr( (base ^ 0x1000) | (address-2) << 10, (banks.chr[address+2] = data) ); } } else { UpdatePrg( (address == 6) ? (regs.ctrl0 << 8 & 0x4000) : 0x2000, (banks.prg[address-6] = data & 0x3F) ); } } NES_POKE_D(Mmc3,A001) { regs.ctrl1 = data; wrk.Source().SetSecurity ( (data & CTRL1_WRAM_ENABLED), (data & CTRL1_WRAM) == CTRL1_WRAM_ENABLED && board.GetWram() ); } NES_POKE_D(Mmc3,C000) { irq.Update(); irq.unit.SetLatch( data ); } NES_POKE(Mmc3,C001) { irq.Update(); irq.unit.Reload(); } NES_POKE(Mmc3,E000) { irq.Update(); irq.unit.Disable( cpu ); } NES_POKE(Mmc3,E001) { irq.Update(); irq.unit.Enable(); } void NST_FASTCALL Mmc3::UpdatePrg(uint address,uint bank) { prg.SwapBank( address, bank ); } void NST_FASTCALL Mmc3::UpdateChr(uint address,uint bank) const { chr.SwapBank( address, bank ); } void Mmc3::UpdatePrg() { const uint x = regs.ctrl0 >> 5 & 0x2; UpdatePrg( 0x0000, banks.prg[0^x] ); UpdatePrg( 0x2000, banks.prg[1^0] ); UpdatePrg( 0x4000, banks.prg[2^x] ); UpdatePrg( 0x6000, banks.prg[3^0] ); } void Mmc3::UpdateChr() const { ppu.Update(); const uint x = regs.ctrl0 >> 5 & 0x4; for (uint i=0; i < 8; ++i) UpdateChr( i * SIZE_1K, banks.chr[i^x] ); } void Mmc3::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } } } } nestopia-1.51.1/source/core/board/NstBoardMmc3.hpp000066400000000000000000000067741411157722000217230ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_MMC3_H #define NST_BOARD_MMC3_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "../NstTimer.hpp" namespace Nes { namespace Core { namespace Boards { class NST_NO_VTABLE Mmc3 : public Board { class BaseIrq { public: enum { CLOCK_FILTER = 16 }; void Reset(bool); void LoadState(State::Loader&); void SaveState(State::Saver&,dword) const; private: uint count; uint latch; ibool reload; ibool enabled; const ibool persistent; public: explicit BaseIrq(bool p) : persistent(p) {} NST_FORCE_INLINE bool Clock() { const bool tmp = count || reload; if (!count || reload) { count = latch; } else { --count; } reload = false; return (tmp | persistent) && !count && enabled; } void SetLatch(uint data) { latch = data; } void Reload() { reload = true; } void Enable() { enabled = true; } void Disable(Cpu& cpu) { enabled = false; cpu.ClearIRQ(); } }; public: enum Revision { REV_A, REV_B, REV_C }; template struct Irq : Timer::A12 { Irq(Cpu& c,Ppu& p,bool persistent) : Timer::A12(c,p,persistent) {} }; protected: explicit Mmc3(const Context&,Revision=REV_B); void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Sync(Event,Input::Controllers*); void UpdatePrg(); void UpdateChr() const; virtual void NST_FASTCALL UpdatePrg(uint,uint); virtual void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_POKE( 8000 ); NES_DECL_POKE( 8001 ); NES_DECL_POKE( A001 ); NES_DECL_POKE( C000 ); NES_DECL_POKE( C001 ); NES_DECL_POKE( E000 ); NES_DECL_POKE( E001 ); enum { CTRL1_WRAM_READONLY = 0x40, CTRL1_WRAM_ENABLED = 0x80, CTRL1_WRAM = CTRL1_WRAM_ENABLED|CTRL1_WRAM_READONLY }; struct Regs { uint ctrl0; uint ctrl1; } regs; struct { byte prg[4]; byte chr[8]; } banks; private: Irq<> irq; }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardMmc4.cpp000066400000000000000000000026461411157722000217110ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc4.hpp" namespace Nes { namespace Core { namespace Boards { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Mmc4::SubReset(const bool hard) { Mmc2::SubReset( hard ); Map( 0xA000U, 0xAFFFU, PRG_SWAP_16K_0 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } } nestopia-1.51.1/source/core/board/NstBoardMmc4.hpp000066400000000000000000000026311411157722000217100ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_MMC4_H #define NST_BOARD_MMC4_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardMmc2.hpp" namespace Nes { namespace Core { namespace Boards { class NST_NO_VTABLE Mmc4 : public Mmc2 { protected: explicit Mmc4(const Context& c) : Mmc2(c) {} private: void SubReset(bool); }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardMmc5.cpp000066400000000000000000001207401411157722000217060ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstBoard.hpp" #include "NstBoardMmc5.hpp" namespace Nes { namespace Core { namespace Boards { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif const byte Mmc5::Filler::squared[4] = {0x00,0x55,0xAA,0xFF}; Mmc5::Sound::Sound(Apu& a,bool connect) : Channel(a) { Reset(); bool audible = UpdateSettings(); if (connect) Connect( audible ); } Mmc5::Banks::Wrk::Wrk(dword s) { enum {X = INVALID}; static const byte access[6][8] = { {X,X,X,X,X,X,X,X}, {0,0,0,0,X,X,X,X}, {0,0,0,0,1,1,1,1}, {0,1,2,3,X,X,X,X}, {0,1,2,3,4,4,4,4}, {0,1,2,3,4,5,6,7} }; std::memcpy( banks, access[s==SIZE_16K ? 2 : s==SIZE_32K ? 3 : s==SIZE_40K ? 4 : s==SIZE_64K ? 5 : s ? 1 : 0], 8 ); } Mmc5::Banks::Banks(uint wrkSize) : wrk(wrkSize) {} Mmc5::Mmc5(const Context& c) : Board (c), banks (board.GetWram()), sound (*c.apu) { nmt.Source(1).Set( Ram::RAM, true, true, sizeof(exRam.mem), exRam.mem ); } void Mmc5::Flow::Reset() { cycles = 0; phase = &Mmc5::VBlank; scanline = 240; } void Mmc5::Irq::Reset() { state = 0; count = 0U-2U; target = 0; } void Mmc5::Regs::Reset() { prgMode = PRG_MODE_8K; chrMode = CHR_MODE_8K; exRamMode = EXRAM_MODE_PPU_NT; mul[0] = 0; mul[1] = 0; } void Mmc5::Banks::Reset() { nmt = 0; for (uint i=0; i < 8; ++i) chrA[i] = i; for (uint i=0; i < 4; ++i) chrB[i] = i; chrHigh = 0; lastChr = LAST_CHR_A; fetchMode = FETCH_MODE_NONE; security = 0; for (uint i=0; i < 4; ++i) prg[i] = 0xFF; } void Mmc5::Filler::Reset() { tile = 0; attribute = 0; } void Mmc5::Spliter::Reset() { ctrl = 0; tile = 0; inside = false; yStart = 0; chrBank = 0; x = 0; y = 0; } void Mmc5::ExRam::Reset(bool hard) { tile = 0; if (hard) std::memset( mem, 0x00, sizeof(mem) ); } void Mmc5::Sound::Square::Reset() { waveLength = 0; active = false; frequency = 0; timer = 0; step = 0; duty = 0; lengthCounter.Reset(); envelope.Reset(); } void Mmc5::Sound::Pcm::Reset() { sample = 0; enabled = false; amp = 0; } void Mmc5::Sound::Reset() { atHalfClock = 0; for (uint i=0; i < NUM_SQUARES; ++i) square[i].Reset(); pcm.Reset(); dcBlocker.Reset(); } void Mmc5::SubReset(const bool hard) { cpu.AddHook( Hook(this,&Mmc5::Hook_Cpu) ); ppu.SetHActiveHook( Hook(this,&Mmc5::Hook_HActive) ); ppu.SetHBlankHook( Hook(this,&Mmc5::Hook_HBlank) ); Map( 0x5000U, &Mmc5::Poke_5000 ); Map( 0x5002U, &Mmc5::Poke_5002 ); Map( 0x5003U, &Mmc5::Poke_5003 ); Map( 0x5004U, &Mmc5::Poke_5004 ); Map( 0x5006U, &Mmc5::Poke_5006 ); Map( 0x5007U, &Mmc5::Poke_5007 ); Map( 0x5010U, &Mmc5::Poke_5010 ); Map( 0x5011U, &Mmc5::Poke_5011 ); Map( 0x5015U, &Mmc5::Peek_5015, &Mmc5::Poke_5015 ); Map( 0x5100U, &Mmc5::Poke_5100 ); Map( 0x5101U, &Mmc5::Poke_5101 ); Map( 0x5102U, &Mmc5::Poke_5102 ); Map( 0x5103U, &Mmc5::Poke_5103 ); Map( 0x5104U, &Mmc5::Poke_5104 ); Map( 0x5105U, &Mmc5::Poke_5105 ); Map( 0x5106U, &Mmc5::Poke_5106 ); Map( 0x5107U, &Mmc5::Poke_5107 ); Map( 0x5113U, &Mmc5::Poke_5113 ); Map( 0x5114U, 0x5117U, &Mmc5::Poke_5114 ); Map( 0x5120U, 0x5127U, &Mmc5::Poke_5120 ); Map( 0x5128U, 0x512BU, &Mmc5::Poke_5128 ); Map( 0x5130U, &Mmc5::Poke_5130 ); Map( 0x5200U, &Mmc5::Poke_5200 ); Map( 0x5201U, &Mmc5::Poke_5201 ); Map( 0x5202U, &Mmc5::Poke_5202 ); Map( 0x5203U, &Mmc5::Poke_5203 ); Map( 0x5204U, &Mmc5::Peek_5204, &Mmc5::Poke_5204 ); Map( 0x5205U, &Mmc5::Peek_5205, &Mmc5::Poke_5205 ); Map( 0x5206U, &Mmc5::Peek_5206, &Mmc5::Poke_5206 ); Map( 0x5C00U, 0x5FFFU, &Mmc5::Peek_5C00, &Mmc5::Poke_5C00 ); Map( 0x6000U, 0x7FFFU, &Mmc5::Peek_6000, &Mmc5::Poke_6000 ); Map( 0x8000U, 0x9FFFU, &Mmc5::Peek_8000, &Mmc5::Poke_8000 ); Map( 0xA000U, 0xBFFFU, &Mmc5::Peek_A000, &Mmc5::Poke_A000 ); Map( 0xC000U, 0xDFFFU, &Mmc5::Peek_C000, &Mmc5::Poke_C000 ); p2001 = cpu.Map( 0x2001 ); for (uint i=0x2001; i < 0x4000; i += 0x8) cpu.Map( i ).Set( this, &Mmc5::Peek_2001, &Mmc5::Poke_2001 ); for (uint i=0; i < 2; ++i) ciRam[i] = nmt.Source().Mem(SIZE_1K * i); exRam.Reset( hard ); flow.Reset(); banks.Reset(); regs.Reset(); irq.Reset(); filler.Reset(); spliter.Reset(); UpdatePrg(); UpdateChrA(); UpdateRenderMethod(); } inline bool Mmc5::Sound::Square::CanOutput() const { return lengthCounter.GetCount() && waveLength >= MIN_FRQ; } void Mmc5::Sound::Square::UpdateSettings(const uint fixed) { active = CanOutput(); frequency = (waveLength + 1UL) * fixed * 2; } bool Mmc5::Sound::UpdateSettings() { uint volume = GetVolume(EXT_MMC5); output = IsMuted() ? 0 : volume; GetOscillatorClock( rate, fixed ); for (uint i=0; i < NUM_SQUARES; ++i) square[i].UpdateSettings( fixed ); quarterClock = GetCpuClockBase() / (240UL * GetCpuClockDivider() * GetCpuClock()) * GetCpuClock(); dcBlocker.Reset(); return volume; } void Mmc5::SubSave(State::Saver& state) const { state.Begin( AsciiId<'M','M','5'>::V ); { const byte data[32] = { regs.prgMode | (regs.chrMode << 2) | (regs.exRamMode << 4), banks.prg[0], banks.prg[1], banks.prg[2], banks.prg[3], banks.security & (Banks::READABLE_6|Banks::WRITABLE_6|Regs::WRK_WRITABLE_A|Regs::WRK_WRITABLE_B), banks.nmt, banks.chrA[0] & 0xFFU, banks.chrA[1] & 0xFFU, banks.chrA[2] & 0xFFU, banks.chrA[3] & 0xFFU, banks.chrA[4] & 0xFFU, banks.chrA[5] & 0xFFU, banks.chrA[6] & 0xFFU, banks.chrA[7] & 0xFFU, banks.chrB[0] & 0xFFU, banks.chrB[1] & 0xFFU, banks.chrB[2] & 0xFFU, banks.chrB[3] & 0xFFU, uint(banks.chrA[0]) >> 8 | uint(banks.chrA[1]) >> 8 << 2 | uint(banks.chrA[2]) >> 8 << 4 | uint(banks.chrA[3]) >> 8 << 6, uint(banks.chrA[4]) >> 8 | uint(banks.chrA[5]) >> 8 << 2 | uint(banks.chrA[6]) >> 8 << 4 | uint(banks.chrA[7]) >> 8 << 6, uint(banks.chrB[0]) >> 8 | uint(banks.chrB[1]) >> 8 << 2 | uint(banks.chrB[2]) >> 8 << 4 | uint(banks.chrB[3]) >> 8 << 6, (banks.chrHigh >> 6) | (banks.lastChr != Banks::LAST_CHR_A ? 0x80 : 0x00), filler.tile, (filler.attribute & 0x3) | (spliter.tile >> 2 & 0xF8), exRam.tile, spliter.ctrl, spliter.yStart, spliter.chrBank >> 12, spliter.tile & 0x1F, spliter.x, spliter.y }; state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End(); } { const byte data[2] = { regs.mul[0], regs.mul[1] }; state.Begin( AsciiId<'M','U','L'>::V ).Write( data ).End(); } { const byte data[2] = { irq.state, irq.target }; state.Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End(); } state.Begin( AsciiId<'R','A','M'>::V ).Compress( exRam.mem ).End(); sound.SaveState( state, AsciiId<'S','N','D'>::V ); state.End(); } void Mmc5::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'M','M','5'>::V) ); if (baseChunk == AsciiId<'M','M','5'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: { State::Loader::Data<32> data( state ); regs.prgMode = data[0] >> 0 & Regs::PRG_MODE; regs.chrMode = data[0] >> 2 & Regs::CHR_MODE; regs.exRamMode = data[0] >> 4 & Regs::EXRAM_MODE; for (uint i=0; i < 4; ++i) banks.prg[i] = data[1+i]; banks.security = data[5] & (Banks::READABLE_6|Banks::WRITABLE_6|Regs::WRK_WRITABLE_A|Regs::WRK_WRITABLE_B); banks.nmt = data[6]; for (uint i=0; i < 8; ++i) banks.chrA[i] = data[7+i] | (data[19+(i/4)] & Regs::CHR_HIGH) << 8; for (uint i=0; i < 4; ++i) banks.chrB[i] = data[15+i] | (data[21+(i/4)] & Regs::CHR_HIGH) << 8; banks.chrHigh = (data[22] & Regs::CHR_HIGH) << 6; banks.lastChr = (data[22] & 0x80) ? Banks::LAST_CHR_B : Banks::LAST_CHR_A; filler.tile = data[23]; filler.attribute = Filler::squared[data[24] & 0x3]; exRam.tile = data[25]; spliter.ctrl = data[26]; spliter.yStart = NST_MIN(data[27],239); spliter.chrBank = data[28] << 12; spliter.tile = (data[29] & 0x1F) | (data[24] << 2 & 0x3E0); spliter.x = data[30] & 0x1F; spliter.y = NST_MIN(data[31],239); UpdatePrg(); if (banks.lastChr == Banks::LAST_CHR_A) UpdateChrA(); else UpdateChrB(); UpdateRenderMethod(); break; } case AsciiId<'M','U','L'>::V: { State::Loader::Data<2> data( state ); regs.mul[0] = data[0]; regs.mul[1] = data[1]; break; } case AsciiId<'I','R','Q'>::V: { State::Loader::Data<2> data( state ); NST_VERIFY( !(data[0] & Irq::FRAME) ); irq.state = data[0] & (Irq::HIT|Irq::ENABLED); irq.target = data[1]; break; } case AsciiId<'R','A','M'>::V: state.Uncompress( exRam.mem ); break; case AsciiId<'S','N','D'>::V: sound.LoadState( state ); break; } state.End(); } } } void Mmc5::Sound::SaveState(State::Saver& state,const dword baseChunk) const { state.Begin( baseChunk ); state.Begin( AsciiId<'C','L','K'>::V ).Write8( atHalfClock ).End(); square[0].SaveState( state, AsciiId<'S','Q','0'>::V ); square[1].SaveState( state, AsciiId<'S','Q','1'>::V ); pcm.SaveState( state, AsciiId<'P','C','M'>::V ); state.End(); } void Mmc5::Sound::LoadState(State::Loader& state) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'C','L','K'>::V: atHalfClock = state.Read8() & 0x1; break; case AsciiId<'S','Q','0'>::V: square[0].LoadState( state, fixed ); break; case AsciiId<'S','Q','1'>::V: square[1].LoadState( state, fixed ); break; case AsciiId<'P','C','M'>::V: pcm.LoadState( state ); break; } state.End(); } } void Mmc5::Sound::Square::SaveState(State::Saver& state,const dword chunk) const { state.Begin( chunk ); { const byte data[3] = { waveLength & 0xFF, waveLength >> 8, duty }; state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End(); } lengthCounter.SaveState( state, AsciiId<'L','E','N'>::V ); envelope.SaveState( state, AsciiId<'E','N','V'>::V ); state.End(); } void Mmc5::Sound::Square::LoadState(State::Loader& state,const dword fixed) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: waveLength = state.Read16() & 0x7FF; duty = state.Read8() & 0x3; break; case AsciiId<'L','E','N'>::V: lengthCounter.LoadState( state ); break; case AsciiId<'E','N','V'>::V: envelope.LoadState( state ); break; } state.End(); } step = 0; timer = 0; frequency = (waveLength + 1UL) * fixed * 2; active = CanOutput(); } void Mmc5::Sound::Pcm::SaveState(State::Saver& state,const dword chunk) const { state.Begin( chunk ).Write16( (enabled != 0) | dword(amp / VOLUME) << 8 ).End(); } void Mmc5::Sound::Pcm::LoadState(State::Loader& state) { const uint data = state.Read16(); enabled = data & 0x1; amp = (data >> 8) * VOLUME; sample = enabled ? amp : 0; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif inline ibool Mmc5::IsPpuSprite8x16() const { return ppu.GetCtrl(0) & Regs::PPU_CTRL0_SP8X16; } void Mmc5::VBlank() { NST_ASSERT( flow.cycles == 0 ); flow.cycles = ppu.GetHVIntClock(); if (flow.cycles <= cpu.GetCycles()) HDummy(); else flow.phase = &Mmc5::HDummy; } void Mmc5::HDummy() { if (ppu.IsEnabled()) irq.count++; flow.cycles += ppu.GetHSyncClock() - (ppu.IsShortFrame() ? ppu.GetClock() : 0); if (flow.cycles <= cpu.GetCycles()) HActive0(); else flow.phase = &Mmc5::HActive0; } void Mmc5::HActive0() { if (ppu.IsEnabled()) { irq.count++; irq.state = (irq.state & Irq::ENABLED) | Irq::FRAME; cpu.ClearIRQ(); } flow.cycles += ppu.GetHSyncClock(); flow.scanline = 0; if (flow.cycles <= cpu.GetCycles()) HActiveX(); else flow.phase = &Mmc5::HActiveX; } void Mmc5::HActiveX() { for (;;) { flow.scanline++; if (ppu.IsEnabled()) { if (++irq.count == irq.target && irq.target) irq.state |= Irq::HIT; if ((irq.state & Irq::SIGNAL_HIT) == Irq::SIGNAL_HIT) cpu.DoIRQ( Cpu::IRQ_EXT, flow.cycles ); } flow.cycles += ppu.GetHSyncClock(); if (flow.scanline < 240) { if (flow.cycles > cpu.GetCycles()) break; } else { irq.count = 0U-2U; flow.cycles = Cpu::CYCLE_MAX; irq.state &= (Irq::ENABLED|Irq::HIT); ppu.Update(); banks.fetchMode = Banks::FETCH_MODE_NONE; spliter.inside = false; if (banks.lastChr == Banks::LAST_CHR_A) UpdateChrA(); else UpdateChrB(); break; } } } inline void Mmc5::Update() { if (flow.cycles <= cpu.GetCycles()) (*this.*flow.phase)(); } void Mmc5::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) { Update(); flow.cycles = 0; flow.phase = &Mmc5::VBlank; } Board::Sync( event, controllers ); } NES_HOOK(Mmc5,Cpu) { Update(); } NES_HOOK(Mmc5,HActive) { if (ppu.IsEnabled()) { banks.fetchMode = Banks::FETCH_MODE_BG; spliter.x = 0x1F; if (ppu.GetPixelCycles() != ~0U) { if (spliter.y < 239) spliter.y++; else spliter.y = 0; } else { spliter.y = spliter.yStart; } if (banks.lastChr != Banks::LAST_CHR_A || IsPpuSprite8x16()) UpdateChrB(); else UpdateChrA(); } } NES_HOOK(Mmc5,HBlank) { banks.fetchMode = Banks::FETCH_MODE_SP; spliter.inside = false; if (ppu.IsEnabled()) { if (banks.lastChr == Banks::LAST_CHR_A || IsPpuSprite8x16()) UpdateChrA(); else UpdateChrB(); } } inline uint Mmc5::Banks::Wrk::operator [] (uint i) const { NST_ASSERT( i < 8 ); return banks[i]; } template void Mmc5::SwapPrg8Ex(uint bank) { enum { ROM = uint(Banks::READABLE_8) << (ADDRESS / SIZE_8K), RAM = uint(Banks::WRITABLE_8) << (ADDRESS / SIZE_8K) | ROM }; // GCC goes banana without the explicit cast if (bank & Regs::PRG_ROM_SELECT) { banks.security = (banks.security & ~uint(RAM)) | ROM; static_cast(prg.Source(0)).SwapBank( bank & Regs::PRG_ROM_BANK ); } else if (Banks::Wrk::INVALID != (bank = banks.wrk[bank & Regs::PRG_RAM_BANK])) { banks.security |= RAM; static_cast(prg.Source(1)).SwapBank( bank ); } else { banks.security &= ~uint(RAM); NST_DEBUG_MSG("MMC5 open bus PRG bankswitch!"); } } void Mmc5::UpdatePrg() { enum { ROM_8_A_C = Banks::READABLE_8|Banks::READABLE_A|Banks::READABLE_C, ROM_C = Banks::READABLE_C, RAM_8_A_C = Banks::WRITABLE_8|Banks::WRITABLE_A|Banks::WRITABLE_C|ROM_8_A_C, RAM_C = Banks::WRITABLE_C|ROM_C }; switch (regs.prgMode & Regs::PRG_MODE) { case Regs::PRG_MODE_32K: banks.security = (banks.security & ~uint(RAM_8_A_C)) | ROM_8_A_C; prg.SwapBank( banks.prg[3] >> 2 ); break; case Regs::PRG_MODE_16K: banks.security = (banks.security & ~uint(RAM_C)) | ROM_C; SwapPrg8Ex<0x0000>( banks.prg[1] & 0xFEU ); SwapPrg8Ex<0x2000>( banks.prg[1] | 0x01U ); prg.SwapBank( banks.prg[3] >> 1 ); break; case Regs::PRG_MODE_16K_8K: SwapPrg8Ex<0x0000>( banks.prg[1] & 0xFEU ); SwapPrg8Ex<0x2000>( banks.prg[1] | 0x01U ); SwapPrg8Ex<0x4000>( banks.prg[2] ); prg.SwapBank( banks.prg[3] ); break; case Regs::PRG_MODE_8K: SwapPrg8Ex<0x0000>( banks.prg[0] ); SwapPrg8Ex<0x2000>( banks.prg[1] ); SwapPrg8Ex<0x4000>( banks.prg[2] ); prg.SwapBank( banks.prg[3] ); break; } } void Mmc5::UpdateChrA() const { switch (regs.chrMode) { case Regs::CHR_MODE_8K: chr.SwapBank( banks.chrA[7] ); break; case Regs::CHR_MODE_4K: chr.SwapBanks( banks.chrA[3], banks.chrA[7] ); break; case Regs::CHR_MODE_2K: chr.SwapBanks( banks.chrA[1], banks.chrA[3], banks.chrA[5], banks.chrA[7] ); break; case Regs::CHR_MODE_1K: chr.SwapBanks( banks.chrA[0], banks.chrA[1], banks.chrA[2], banks.chrA[3], banks.chrA[4], banks.chrA[5], banks.chrA[6], banks.chrA[7] ); break; } } void Mmc5::UpdateChrB() const { switch (regs.chrMode) { case Regs::CHR_MODE_8K: chr.SwapBank( banks.chrB[3] ); break; case Regs::CHR_MODE_4K: chr.SwapBanks( banks.chrB[3], banks.chrB[3] ); break; case Regs::CHR_MODE_2K: chr.SwapBanks( banks.chrB[1], banks.chrB[3], banks.chrB[1], banks.chrB[3] ); break; case Regs::CHR_MODE_1K: chr.SwapBanks( banks.chrB[0], banks.chrB[1], banks.chrB[2], banks.chrB[3], banks.chrB[0], banks.chrB[1], banks.chrB[2], banks.chrB[3] ); break; } } bool Mmc5::ClockSpliter() { NST_ASSERT( spliter.ctrl & Spliter::CTRL_ENABLED ); if (banks.fetchMode == Banks::FETCH_MODE_BG) { spliter.x = (spliter.x + 1) & 0x1F; if ( (spliter.ctrl & Spliter::CTRL_RIGHT_SIDE) ? (spliter.x >= (spliter.ctrl & Spliter::CTRL_START)) : (spliter.x < (spliter.ctrl & Spliter::CTRL_START)) ) { spliter.tile = ((spliter.y & 0xF8) << 2) | spliter.x; spliter.inside = true; return true; } spliter.inside = false; } return false; } template<> NST_FORCE_INLINE uint Mmc5::FetchByte(uint address) const { return ciRam[0][address]; } template<> NST_FORCE_INLINE uint Mmc5::FetchByte(uint address) const { return ciRam[1][address]; } template<> NST_FORCE_INLINE uint Mmc5::FetchByte(uint address) const { return exRam.mem[address]; } template<> NST_FORCE_INLINE uint Mmc5::FetchByte(uint address) const { return (address & 0x3FF) < 0x3C0 ? filler.tile : filler.attribute; } template<> NST_FORCE_INLINE uint Mmc5::FetchByte(uint) const { return 0; } template NST_FORCE_INLINE uint Mmc5::FetchNt(uint address) const { return FetchByte( address ); } template NST_FORCE_INLINE uint Mmc5::FetchNtExt(uint address) { if ((address & 0x3FF) < 0x3C0) { exRam.tile = exRam.mem[address]; return FetchByte( address ); } else { return Filler::squared[exRam.tile >> 6]; } } template NST_FORCE_INLINE uint Mmc5::FetchNtSplit(uint address) { if ((address & 0x3FF) < 0x3C0) { if (ClockSpliter()) return exRam.mem[spliter.tile]; else return FetchByte( address ); } else { if (spliter.inside) return GetSpliterAttribute(); else return FetchByte( address ); } } template NST_FORCE_INLINE uint Mmc5::FetchNtExtSplit(uint address) { if ((address & 0x3FF) < 0x3C0) { if (ClockSpliter()) { return exRam.mem[spliter.tile]; } else { exRam.tile = exRam.mem[address]; return FetchByte( address ); } } else { if (spliter.inside) return GetSpliterAttribute(); else return Filler::squared[exRam.tile >> 6]; } } uint Mmc5::GetSpliterAttribute() const { return Filler::squared[(exRam.mem[0x3C0 | (spliter.tile >> 4 & 0x38) | (spliter.tile >> 2 & 0x7)] >> ((spliter.tile >> 4 & 0x4) | (spliter.tile & 0x2))) & 0x3]; } NES_ACCESSOR( Mmc5, Nt_CiRam_0 ) { return FetchNt < NT_CIRAM_0 >( address ); } NES_ACCESSOR( Mmc5, Nt_CiRam_1 ) { return FetchNt < NT_CIRAM_1 >( address ); } NES_ACCESSOR( Mmc5, Nt_ExRam ) { return FetchNt < NT_EXRAM >( address ); } NES_ACCESSOR( Mmc5, Nt_Fill ) { return FetchNt < NT_FILL >( address ); } NES_ACCESSOR( Mmc5, Nt_Zero ) { return FetchNt < NT_ZERO >( address ); } NES_ACCESSOR( Mmc5, NtExt_CiRam_0 ) { return FetchNtExt < NT_CIRAM_0 >( address ); } NES_ACCESSOR( Mmc5, NtExt_CiRam_1 ) { return FetchNtExt < NT_CIRAM_1 >( address ); } NES_ACCESSOR( Mmc5, NtExt_ExRam ) { return FetchNtExt < NT_EXRAM >( address ); } NES_ACCESSOR( Mmc5, NtExt_Fill ) { return FetchNtExt < NT_FILL >( address ); } NES_ACCESSOR( Mmc5, NtSplit_CiRam_0 ) { return FetchNtSplit < NT_CIRAM_0 >( address ); } NES_ACCESSOR( Mmc5, NtSplit_CiRam_1 ) { return FetchNtSplit < NT_CIRAM_1 >( address ); } NES_ACCESSOR( Mmc5, NtSplit_ExRam ) { return FetchNtSplit < NT_EXRAM >( address ); } NES_ACCESSOR( Mmc5, NtSplit_Fill ) { return FetchNtSplit < NT_FILL >( address ); } NES_ACCESSOR( Mmc5, NtExtSplit_CiRam_0 ) { return FetchNtExtSplit < NT_CIRAM_0 >( address ); } NES_ACCESSOR( Mmc5, NtExtSplit_CiRam_1 ) { return FetchNtExtSplit < NT_CIRAM_1 >( address ); } NES_ACCESSOR( Mmc5, NtExtSplit_ExRam ) { return FetchNtExtSplit < NT_EXRAM >( address ); } NES_ACCESSOR( Mmc5, NtExtSplit_Fill ) { return FetchNtExtSplit < NT_FILL >( address ); } NES_ACCESSOR(Mmc5,CRom) { return chr.Peek( address ); } uint Mmc5::GetSpliterPattern(uint address) const { return *chr.Source().Mem( spliter.chrBank + (address & 0xFFF) ); } uint Mmc5::GetExtPattern(uint address) const { return *chr.Source().Mem( (((exRam.tile & Regs::EXRAM_EXT_CHR_BANK) + banks.chrHigh) << 12) + (address & 0xFFF) ); } NES_ACCESSOR(Mmc5,CRomExt) { if (banks.fetchMode == Banks::FETCH_MODE_BG) return GetExtPattern( address ); else return chr.Peek( address ); } NES_ACCESSOR(Mmc5,CRomSplit) { if (spliter.inside) return GetSpliterPattern( address ); else return chr.Peek( address ); } NES_ACCESSOR(Mmc5,CRomExtSplit) { if (spliter.inside) { return GetSpliterPattern( address ); } else if (banks.fetchMode == Banks::FETCH_MODE_BG) { return GetExtPattern( address ); } else { return chr.Peek( address ); } } void Mmc5::UpdateRenderMethod() { ppu.Update(); const uint method = regs.exRamMode | (spliter.ctrl >> 5 & 0x4); { static const Io::Accessor::Type::Function chrMethods[8] = { &Mmc5::Access_CRom, // PPU NT &Mmc5::Access_CRomExt, // PPU EXT &Mmc5::Access_CRom, // CPU EXRAM &Mmc5::Access_CRom, // CPU EXROM &Mmc5::Access_CRomSplit, // PPU NT + SPLIT &Mmc5::Access_CRomExtSplit, // PPU EXT + SPLIT &Mmc5::Access_CRom, // CPU EXRAM + denied SPLIT &Mmc5::Access_CRom // CPU EXROM + denied SPLIT }; chr.SetAccessor( this, chrMethods[method] ); } uint bank = banks.nmt; { static const Io::Accessor::Type::Function nmtMethods[8][4] = { { // PPU NT &Mmc5::Access_Nt_CiRam_0, &Mmc5::Access_Nt_CiRam_1, &Mmc5::Access_Nt_ExRam, &Mmc5::Access_Nt_Fill }, { // PPU EXT &Mmc5::Access_NtExt_CiRam_0, &Mmc5::Access_NtExt_CiRam_1, &Mmc5::Access_NtExt_ExRam, &Mmc5::Access_NtExt_Fill }, { // CPU EXRAM &Mmc5::Access_Nt_CiRam_0, &Mmc5::Access_Nt_CiRam_1, &Mmc5::Access_Nt_Zero, &Mmc5::Access_Nt_Fill }, { // CPU EXROM &Mmc5::Access_Nt_CiRam_0, &Mmc5::Access_Nt_CiRam_1, &Mmc5::Access_Nt_Zero, &Mmc5::Access_Nt_Fill }, { // PPU NT + SPLIT &Mmc5::Access_NtSplit_CiRam_0, &Mmc5::Access_NtSplit_CiRam_1, &Mmc5::Access_NtSplit_ExRam, &Mmc5::Access_NtSplit_Fill }, { // PPU EXT + SPLIT &Mmc5::Access_NtExtSplit_CiRam_0, &Mmc5::Access_NtExtSplit_CiRam_1, &Mmc5::Access_NtExtSplit_ExRam, &Mmc5::Access_NtExtSplit_Fill }, { // CPU EXRAM + denied SPLIT &Mmc5::Access_Nt_CiRam_0, &Mmc5::Access_Nt_CiRam_1, &Mmc5::Access_Nt_Zero, &Mmc5::Access_Nt_Fill }, { // CPU EXROM + denied SPLIT &Mmc5::Access_Nt_CiRam_0, &Mmc5::Access_Nt_CiRam_1, &Mmc5::Access_Nt_Zero, &Mmc5::Access_Nt_Fill } }; nmt.SetAccessors ( this, nmtMethods[method][bank >> 0 & Regs::NMT_MODE], nmtMethods[method][bank >> 2 & Regs::NMT_MODE], nmtMethods[method][bank >> 4 & Regs::NMT_MODE], nmtMethods[method][bank >> 6 & Regs::NMT_MODE] ); } for (uint address=0; address < SIZE_4K; address += SIZE_1K, bank >>= 2) { static const byte securities[4][4][2] = { { {0,0}, {0,1}, {1,0}, {0,0} }, { {0,0}, {0,1}, {1,0}, {0,0} }, { {0,0}, {0,1}, {0,0}, {0,0} }, { {0,0}, {0,1}, {0,0}, {0,0} } }; nmt.Source( securities[regs.exRamMode][bank & Regs::NMT_MODE][0] ).SwapBank ( address, securities[regs.exRamMode][bank & Regs::NMT_MODE][1] ); } } NES_POKE_AD(Mmc5,2001) { Update(); if (!(data & Regs::PPU_CTRL1_ENABLED)) { irq.count = 0U-2U; irq.state &= (Irq::HIT|Irq::ENABLED); banks.fetchMode = Banks::FETCH_MODE_NONE; spliter.inside = false; } p2001.Poke( address, data ); } NES_PEEK_A(Mmc5,2001) { return p2001.Peek( address ); } NES_POKE_D(Mmc5,5000) { sound.WriteSquareReg0( 0, data ); } NES_POKE_D(Mmc5,5002) { sound.WriteSquareReg1( 0, data ); } NES_POKE_D(Mmc5,5003) { sound.WriteSquareReg2( 0, data ); } NES_POKE_D(Mmc5,5004) { sound.WriteSquareReg0( 1, data ); } NES_POKE_D(Mmc5,5006) { sound.WriteSquareReg1( 1, data ); } NES_POKE_D(Mmc5,5007) { sound.WriteSquareReg2( 1, data ); } NES_POKE_D(Mmc5,5010) { sound.WritePcmReg0( data ); } NES_POKE_D(Mmc5,5011) { sound.WritePcmReg1( data ); } NES_PEEK(Mmc5,5015) { return sound.ReadCtrl(); } NES_POKE_D(Mmc5,5015) { sound.WriteCtrl( data ); } NES_POKE_D(Mmc5,5100) { data &= Regs::PRG_MODE; if (regs.prgMode != data) { regs.prgMode = data; UpdatePrg(); } } NES_POKE_D(Mmc5,5101) { data &= Regs::CHR_MODE; if (regs.chrMode != data) { ppu.Update(); regs.chrMode = data; if (!IsPpuSprite8x16() || !ppu.IsEnabled() || ppu.GetScanline() == Ppu::SCANLINE_VBLANK) { if (banks.lastChr == Banks::LAST_CHR_A) UpdateChrA(); else UpdateChrB(); } } } NES_POKE_D(Mmc5,5102) { if (data == Regs::WRK_WRITABLE_A) banks.security |= Regs::WRK_WRITABLE_A; else banks.security &= ~uint(Regs::WRK_WRITABLE_A); } NES_POKE_D(Mmc5,5103) { if (data == Regs::WRK_WRITABLE_B) banks.security |= Regs::WRK_WRITABLE_B; else banks.security &= ~uint(Regs::WRK_WRITABLE_B); } NES_POKE_D(Mmc5,5104) { data &= Regs::EXRAM_MODE; if (regs.exRamMode != data) { regs.exRamMode = data; UpdateRenderMethod(); } } NES_POKE_D(Mmc5,5105) { if (banks.nmt != data) { banks.nmt = data; UpdateRenderMethod(); } } NES_POKE_D(Mmc5,5106) { if (banks.nmt & (banks.nmt << 1)) ppu.Update(); filler.tile = data; } NES_POKE_D(Mmc5,5107) { if (banks.nmt & (banks.nmt << 1)) ppu.Update(); filler.attribute = Filler::squared[data & 0x3]; } NES_POKE_D(Mmc5,5113) { data = banks.wrk[data & Regs::PRG_RAM_BANK]; if (data != Banks::Wrk::INVALID) { banks.security |= Banks::READABLE_6|Banks::WRITABLE_6; wrk.SwapBank( data ); } else { banks.security &= ~uint(Banks::READABLE_6|Banks::WRITABLE_6); } } NES_POKE_AD(Mmc5,5114) { if (banks.prg[address - 0x5114] != data) { banks.prg[address - 0x5114] = data; UpdatePrg(); } } NES_POKE_AD(Mmc5,5120) { data |= banks.chrHigh << 2; address &= 0x7; if (banks.lastChr != Banks::LAST_CHR_A || banks.chrA[address] != data) { ppu.Update(); banks.chrA[address] = data; banks.lastChr = Banks::LAST_CHR_A; if (!IsPpuSprite8x16() || !ppu.IsEnabled() || ppu.GetScanline() == Ppu::SCANLINE_VBLANK) UpdateChrA(); } } NES_POKE_AD(Mmc5,5128) { data |= banks.chrHigh << 2; address &= 0x3; if (banks.lastChr == Banks::LAST_CHR_A || banks.chrB[address] != data) { ppu.Update(); banks.chrB[address] = data; banks.lastChr = Banks::LAST_CHR_B; if (!IsPpuSprite8x16() || !ppu.IsEnabled() || ppu.GetScanline() == Ppu::SCANLINE_VBLANK) UpdateChrB(); } } NES_POKE_D(Mmc5,5130) { data = (data & Regs::CHR_HIGH) << 6; if (banks.chrHigh != data) { ppu.Update(); banks.chrHigh = data; } } NES_POKE_D(Mmc5,5200) { if (spliter.ctrl != data) { ppu.Update(); spliter.ctrl = data; UpdateRenderMethod(); } } NES_POKE_D(Mmc5,5201) { if (data >= 240) data -= 16; if (spliter.yStart != data) { ppu.Update(); spliter.yStart = data; } } NES_POKE_D(Mmc5,5202) { const dword chrBank = dword(data) << 12; if (spliter.chrBank != chrBank) { ppu.Update(); spliter.chrBank = chrBank; } } NES_POKE_D(Mmc5,5203) { Update(); irq.target = data; } NES_PEEK(Mmc5,5204) { Update(); const uint status = irq.state & (Irq::FRAME|Irq::HIT); irq.state &= (Irq::FRAME|Irq::ENABLED); cpu.ClearIRQ(); return status; } NES_POKE_D(Mmc5,5204) { Update(); if (data & 0x80) { irq.state |= Irq::ENABLED; if (irq.state & Irq::HIT) cpu.DoIRQ(); } else { irq.state &= (Irq::HIT|Irq::FRAME); cpu.ClearIRQ(); } } NES_PEEK(Mmc5,5205) { return (regs.mul[0] * regs.mul[1]) >> 0 & 0xFF; } NES_PEEK(Mmc5,5206) { return (regs.mul[0] * regs.mul[1]) >> 8 & 0xFF; } NES_POKE_D(Mmc5,5205) { regs.mul[0] = data; } NES_POKE_D(Mmc5,5206) { regs.mul[1] = data; } NES_PEEK_A(Mmc5,5C00) { if (regs.exRamMode & Regs::EXRAM_MODE_CPU_RAM) return exRam.mem[address - 0x5C00]; else return address >> 8; } NES_POKE_AD(Mmc5,5C00) { switch (regs.exRamMode) { default: ppu.Update(); Update(); NST_VERIFY( irq.state & Irq::FRAME ); if (!(irq.state & Irq::FRAME)) data = 0; case Regs::EXRAM_MODE_CPU_RAM: exRam.mem[address - 0x5C00] = data; case Regs::EXRAM_MODE_CPU_ROM: break; } } NES_POKE_AD(Mmc5,6000) { NST_VERIFY( (banks.security & Banks::CAN_WRITE_6) == Banks::CAN_WRITE_6 ); if ((banks.security & Banks::CAN_WRITE_6) == Banks::CAN_WRITE_6) wrk[0][address - 0x6000] = data; } NES_POKE_AD(Mmc5,8000) { NST_VERIFY( (banks.security & Banks::CAN_WRITE_8) == Banks::CAN_WRITE_8 ); if ((banks.security & Banks::CAN_WRITE_8) == Banks::CAN_WRITE_8) prg[0][address - 0x8000] = data; } NES_POKE_AD(Mmc5,A000) { NST_VERIFY( (banks.security & Banks::CAN_WRITE_A) == Banks::CAN_WRITE_A ); if ((banks.security & Banks::CAN_WRITE_A) == Banks::CAN_WRITE_A) prg[1][address - 0xA000] = data; } NES_POKE_AD(Mmc5,C000) { NST_VERIFY( (banks.security & Banks::CAN_WRITE_C) == Banks::CAN_WRITE_C ); if ((banks.security & Banks::CAN_WRITE_C) == Banks::CAN_WRITE_C) prg[2][address - 0xC000] = data; } NES_PEEK_A(Mmc5,6000) { NST_VERIFY( banks.security & Banks::READABLE_6 ); return (banks.security & Banks::READABLE_6) ? wrk[0][address - 0x6000] : (address >> 8); } NES_PEEK_A(Mmc5,8000) { NST_VERIFY( banks.security & Banks::READABLE_8 ); return (banks.security & Banks::READABLE_8) ? prg[0][address - 0x8000] : (address >> 8); } NES_PEEK_A(Mmc5,A000) { NST_VERIFY( banks.security & Banks::READABLE_A ); return (banks.security & Banks::READABLE_A) ? prg[1][address - 0xA000] : (address >> 8); } NES_PEEK_A(Mmc5,C000) { NST_VERIFY( banks.security & Banks::READABLE_C ); return (banks.security & Banks::READABLE_C) ? prg[2][address - 0xC000] : (address >> 8); } NST_SINGLE_CALL void Mmc5::Sound::Square::Disable(const bool disable) { if (disable) { timer = 0; active = 0; } lengthCounter.Disable( disable ); } void Mmc5::Sound::WriteCtrl(uint data) { Update(); data = ~data; for (uint i=0; i < NUM_SQUARES; ++i) square[i].Disable( data >> i & 0x1 ); } inline uint Mmc5::Sound::Square::GetLengthCounter() const { return lengthCounter.GetCount(); } uint Mmc5::Sound::ReadCtrl() const { Update(); uint data = 0; for (uint i=0; i < NUM_SQUARES; ++i) { if (square[i].GetLengthCounter()) data |= 0x1U << i; } return data; } NST_SINGLE_CALL void Mmc5::Sound::Square::WriteReg0(const uint data) { envelope.Write( data ); duty = data >> DUTY_SHIFT; } NST_SINGLE_CALL void Mmc5::Sound::Square::WriteReg1(const uint data,const uint fixed) { waveLength &= uint(REG2_WAVELENGTH_HIGH) << 8; waveLength |= data; frequency = (waveLength + 1UL) * fixed * 2; active = CanOutput(); } NST_SINGLE_CALL void Mmc5::Sound::Square::WriteReg2(const uint data,const uint fixed) { step = 0; envelope.ResetClock(); lengthCounter.Write( data ); waveLength &= REG1_WAVELENGTH_LOW; waveLength |= (data & REG2_WAVELENGTH_HIGH) << 8; frequency = (waveLength + 1UL) * fixed * 2; active = CanOutput(); } void Mmc5::Sound::WriteSquareReg0(uint index,uint data) { Update(); NST_ASSERT( index < NUM_SQUARES ); square[index].WriteReg0( data ); } void Mmc5::Sound::WriteSquareReg1(uint index,uint data) { Update(); NST_ASSERT( index < NUM_SQUARES ); square[index].WriteReg1( data, fixed ); } void Mmc5::Sound::WriteSquareReg2(uint index,uint data) { Update(); NST_ASSERT( index < NUM_SQUARES ); square[index].WriteReg2( data, fixed ); } NST_SINGLE_CALL void Mmc5::Sound::Pcm::WriteReg0(const uint data) { enabled = ~data & PCM_DISABLE; sample = enabled ? amp : 0; } NST_SINGLE_CALL void Mmc5::Sound::Pcm::WriteReg1(const uint data) { amp = data * VOLUME; sample = enabled ? amp : 0; } void Mmc5::Sound::WritePcmReg0(uint data) { Update(); pcm.WriteReg0( data ); } void Mmc5::Sound::WritePcmReg1(uint data) { Update(); pcm.WriteReg1( data ); } NST_SINGLE_CALL dword Mmc5::Sound::Square::GetSample(const Cycle rate) { NST_VERIFY( bool(active) == CanOutput() && timer >= 0 ); if (active) { dword sum = timer; timer -= idword(rate); static const byte duties[4][8] = { {0x1F,0x00,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F}, {0x1F,0x00,0x00,0x1F,0x1F,0x1F,0x1F,0x1F}, {0x1F,0x00,0x00,0x00,0x00,0x1F,0x1F,0x1F}, {0x00,0x1F,0x1F,0x00,0x00,0x00,0x00,0x00} }; if (timer >= 0) { return dword(envelope.Volume()) >> duties[duty][step]; } else { sum >>= duties[duty][step]; do { sum += NST_MIN(dword(-timer),frequency) >> duties[duty][step = (step + 1) & 0x7]; timer += idword(frequency); } while (timer < 0); return (sum * envelope.Volume() + rate/2) / rate; } } else { return 0; } } inline Mmc5::Sound::Sample Mmc5::Sound::Pcm::GetSample() const { return sample; } Mmc5::Sound::Sample Mmc5::Sound::GetSample() { if (output) { dword sample = 0; for (uint i=0; i < NUM_SQUARES; ++i) sample += square[i].GetSample( rate ); sample += pcm.GetSample(); return dcBlocker.Apply( sample * 2 * output / DEFAULT_VOLUME ); } else { return 0; } } NST_SINGLE_CALL void Mmc5::Sound::Square::ClockQuarter() { envelope.Clock(); } NST_SINGLE_CALL void Mmc5::Sound::Square::ClockHalf() { if (!envelope.Looping() && lengthCounter.Clock()) active = false; } Cycle Mmc5::Sound::Clock(Cycle rateCycles,Cycle rateClock,const Cycle targetCycles) { rateClock *= quarterClock; do { for (uint i=0; i < NUM_SQUARES; ++i) square[i].ClockQuarter(); if (atHalfClock) { for (uint i=0; i < NUM_SQUARES; ++i) square[i].ClockHalf(); } atHalfClock ^= 1; rateCycles += rateClock; } while (rateCycles <= targetCycles); return rateCycles; } } } } nestopia-1.51.1/source/core/board/NstBoardMmc5.hpp000066400000000000000000000250101411157722000217050ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_MMC5_H #define NST_BOARD_MMC5_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { class NST_NO_VTABLE Mmc5 : public Board { protected: explicit Mmc5(const Context&); public: class Sound : public Apu::Channel { public: explicit Sound(Apu&,bool=true); void WriteCtrl(uint); uint ReadCtrl() const; void WriteSquareReg0(uint,uint); void WriteSquareReg1(uint,uint); void WriteSquareReg2(uint,uint); void WritePcmReg0(uint); void WritePcmReg1(uint); void SaveState(State::Saver&,dword) const; void LoadState(State::Loader&); protected: void Reset(); bool UpdateSettings(); Cycle Clock(Cycle,Cycle,Cycle); Sample GetSample(); private: enum { NUM_SQUARES = 2 }; class Square { public: void Reset(); NST_SINGLE_CALL dword GetSample(Cycle); NST_SINGLE_CALL void WriteReg0(uint); NST_SINGLE_CALL void WriteReg1(uint,uint); NST_SINGLE_CALL void WriteReg2(uint,uint); NST_SINGLE_CALL void Disable(bool); NST_SINGLE_CALL void ClockQuarter(); NST_SINGLE_CALL void ClockHalf(); inline uint GetLengthCounter() const; void UpdateSettings(uint); void SaveState(State::Saver&,dword) const; void LoadState(State::Loader&,dword); private: inline bool CanOutput() const; enum { MIN_FRQ = 0x4, REG1_WAVELENGTH_LOW = 0xFF, REG2_WAVELENGTH_HIGH = 0x07, DUTY_SHIFT = 6 }; uint waveLength; ibool active; Cycle frequency; idword timer; uint step; uint duty; LengthCounter lengthCounter; Envelope envelope; }; class Pcm { public: void Reset(); inline Sample GetSample() const; NST_SINGLE_CALL void WriteReg0(uint); NST_SINGLE_CALL void WriteReg1(uint); void SaveState(State::Saver&,dword) const; void LoadState(State::Loader&); private: enum { VOLUME = OUTPUT_MUL / 4, PCM_DISABLE = 0x1 }; ibool enabled; Sample sample; Sample amp; }; uint output; Cycle rate; uint fixed; uint atHalfClock; dword quarterClock; Square square[NUM_SQUARES]; Pcm pcm; DcBlocker dcBlocker; }; // Needs to be public because of bug in GCC 3.x.x enum FetchType { NT_CIRAM_0, NT_CIRAM_1, NT_EXRAM, NT_FILL, NT_ZERO }; private: void SubReset(bool); void VBlank(); void HDummy(); void HActive0(); void HActiveX(); void Sync(Event,Input::Controllers*); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); template void SwapPrg8Ex(uint); void UpdatePrg(); void UpdateChrA() const; void UpdateChrB() const; void UpdateRenderMethod(); bool ClockSpliter(); inline void Update(); inline ibool IsPpuSprite8x16() const; uint GetExtPattern(uint) const; uint GetSpliterAttribute() const; uint GetSpliterPattern(uint) const; template NST_FORCE_INLINE uint FetchByte(uint) const; template NST_FORCE_INLINE uint FetchNt(uint) const; template NST_FORCE_INLINE uint FetchNtExt(uint); template NST_FORCE_INLINE uint FetchNtSplit(uint); template NST_FORCE_INLINE uint FetchNtExtSplit(uint); NES_DECL_HOOK( Cpu ); NES_DECL_HOOK( HActive ); NES_DECL_HOOK( HBlank ); NES_DECL_ACCESSOR( Nt_CiRam_0 ); NES_DECL_ACCESSOR( Nt_CiRam_1 ); NES_DECL_ACCESSOR( Nt_ExRam ); NES_DECL_ACCESSOR( Nt_Fill ); NES_DECL_ACCESSOR( Nt_Zero ); NES_DECL_ACCESSOR( NtExt_CiRam_0 ); NES_DECL_ACCESSOR( NtExt_CiRam_1 ); NES_DECL_ACCESSOR( NtExt_ExRam ); NES_DECL_ACCESSOR( NtExt_Fill ); NES_DECL_ACCESSOR( NtSplit_CiRam_0 ); NES_DECL_ACCESSOR( NtSplit_CiRam_1 ); NES_DECL_ACCESSOR( NtSplit_ExRam ); NES_DECL_ACCESSOR( NtSplit_Fill ); NES_DECL_ACCESSOR( NtExtSplit_CiRam_0 ); NES_DECL_ACCESSOR( NtExtSplit_CiRam_1 ); NES_DECL_ACCESSOR( NtExtSplit_ExRam ); NES_DECL_ACCESSOR( NtExtSplit_Fill ); NES_DECL_ACCESSOR( CRom ); NES_DECL_ACCESSOR( CRomExt ); NES_DECL_ACCESSOR( CRomSplit ); NES_DECL_ACCESSOR( CRomExtSplit ); NES_DECL_POKE( 2001 ); NES_DECL_PEEK( 2001 ); NES_DECL_POKE( 5000 ); NES_DECL_POKE( 5002 ); NES_DECL_POKE( 5003 ); NES_DECL_POKE( 5004 ); NES_DECL_POKE( 5006 ); NES_DECL_POKE( 5007 ); NES_DECL_POKE( 5010 ); NES_DECL_POKE( 5011 ); NES_DECL_PEEK( 5015 ); NES_DECL_POKE( 5015 ); NES_DECL_POKE( 5100 ); NES_DECL_POKE( 5101 ); NES_DECL_POKE( 5102 ); NES_DECL_POKE( 5103 ); NES_DECL_POKE( 5104 ); NES_DECL_POKE( 5105 ); NES_DECL_POKE( 5106 ); NES_DECL_POKE( 5107 ); NES_DECL_POKE( 5113 ); NES_DECL_POKE( 5114 ); NES_DECL_POKE( 5120 ); NES_DECL_POKE( 5128 ); NES_DECL_POKE( 5130 ); NES_DECL_POKE( 5200 ); NES_DECL_POKE( 5201 ); NES_DECL_POKE( 5202 ); NES_DECL_POKE( 5203 ); NES_DECL_PEEK( 5204 ); NES_DECL_POKE( 5204 ); NES_DECL_PEEK( 5205 ); NES_DECL_POKE( 5205 ); NES_DECL_PEEK( 5206 ); NES_DECL_POKE( 5206 ); NES_DECL_PEEK( 5C00 ); NES_DECL_POKE( 5C00 ); NES_DECL_PEEK( 6000 ); NES_DECL_POKE( 6000 ); NES_DECL_PEEK( 8000 ); NES_DECL_POKE( 8000 ); NES_DECL_PEEK( A000 ); NES_DECL_POKE( A000 ); NES_DECL_PEEK( C000 ); NES_DECL_POKE( C000 ); struct Flow { void Reset(); typedef void (Mmc5::*Phase)(); Cycle cycles; Phase phase; uint scanline; }; struct Irq { void Reset(); enum { ENABLED = 0x01, FRAME = 0x40, HIT = 0x80, SIGNAL_HIT = ENABLED|HIT }; uint state; uint count; uint target; }; struct Regs { void Reset(); enum { PRG_MODE = 0x03, PRG_MODE_32K = 0x00, PRG_MODE_16K = 0x01, PRG_MODE_16K_8K = 0x02, PRG_MODE_8K = 0x03, PRG_ROM_SELECT = 0x80, PRG_ROM_BANK = 0x7F, PRG_RAM_BANK = 0x07, CHR_MODE = 0x03, CHR_MODE_8K = 0x00, CHR_MODE_4K = 0x01, CHR_MODE_2K = 0x02, CHR_MODE_1K = 0x03, CHR_HIGH = 0x03, WRK_WRITABLE_A = 0x02, WRK_WRITABLE_B = 0x01, NMT_MODE = 0x03, NMT_CIRAM_0 = 0x00, NMT_CIRAM_1 = 0x01, NMT_EXRAM = 0x02, NMT_FILL = 0x03, EXRAM_MODE = 0x03, EXRAM_MODE_PPU_NT = 0x00, EXRAM_MODE_PPU_EXT = 0x01, EXRAM_MODE_CPU_RAM = 0x02, EXRAM_MODE_CPU_ROM = 0x03, EXRAM_EXT_CHR_BANK = 0x3F, PPU_CTRL0_SP8X16 = 0x20, PPU_CTRL1_ENABLED = 0x18 }; uint prgMode; uint chrMode; uint exRamMode; uint mul[2]; }; struct Banks { explicit Banks(uint); void Reset(); enum { READABLE_6 = 0x004, READABLE_8 = 0x008, READABLE_A = 0x010, READABLE_C = 0x020, WRITABLE_6 = 0x040, WRITABLE_8 = 0x080, WRITABLE_A = 0x100, WRITABLE_C = 0x200, CAN_WRITE_6 = READABLE_6|WRITABLE_6|Regs::WRK_WRITABLE_A|Regs::WRK_WRITABLE_B, CAN_WRITE_8 = READABLE_8|WRITABLE_8|Regs::WRK_WRITABLE_A|Regs::WRK_WRITABLE_B, CAN_WRITE_A = READABLE_A|WRITABLE_A|Regs::WRK_WRITABLE_A|Regs::WRK_WRITABLE_B, CAN_WRITE_C = READABLE_C|WRITABLE_C|Regs::WRK_WRITABLE_A|Regs::WRK_WRITABLE_B }; enum FetchMode { FETCH_MODE_NONE, FETCH_MODE_BG, FETCH_MODE_SP }; enum LastChr { LAST_CHR_A = 0, LAST_CHR_B = 1 }; class Wrk { byte banks[8]; public: enum { INVALID = 8 }; explicit Wrk(dword); inline uint operator [] (uint) const; }; uint nmt; word chrA[8]; word chrB[4]; dword chrHigh; LastChr lastChr; FetchMode fetchMode; uint security; byte prg[4]; const Wrk wrk; }; struct Filler { void Reset(); uint tile; uint attribute; static const byte squared[4]; }; struct Spliter { void Reset(); enum { CTRL_START = 0x1F, CTRL_RIGHT_SIDE = 0x40, CTRL_ENABLED = 0x80 }; uint ctrl; uint tile; ibool inside; uint yStart; uint chrBank; uint x; uint y; }; struct ExRam { void Reset(bool); uint tile; byte mem[SIZE_1K]; }; Flow flow; Irq irq; Regs regs; Banks banks; const byte* ciRam[2]; Filler filler; Spliter spliter; Io::Port p2001; ExRam exRam; Sound sound; }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardMmc6.cpp000066400000000000000000000070471411157722000217130ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc6.hpp" #include "../NstFile.hpp" namespace Nes { namespace Core { namespace Boards { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Mmc6::Mmc6(const Context& c) : Mmc3(c,REV_A) {} void Mmc6::SubReset(const bool hard) { Mmc3::SubReset( hard ); reg = 0; Map( 0x6000U, 0x6FFFU, NOP_POKE ); Map( 0x7000U, 0x7FFFU, &Mmc6::Peek_7000, &Mmc6::Poke_7000 ); for (uint i=0xA001; i < 0xC000; i += 0x2) Map( i, &Mmc6::Poke_A001 ); } void Mmc6::Load(File& file) { if (board.HasBattery()) file.Load( File::BATTERY, ram, sizeof(ram) ); } void Mmc6::Save(File& file) const { if (board.HasBattery()) file.Save( File::BATTERY, ram, sizeof(ram) ); } void Mmc6::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'M','M','6'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: reg = state.Read8(); break; case AsciiId<'R','A','M'>::V: state.Uncompress( ram ); break; } state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void Mmc6::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); state.Begin( AsciiId<'M','M','6'>::V ); state.Begin( AsciiId<'R','E','G'>::V ).Write8( reg ).End(); state.Begin( AsciiId<'R','A','M'>::V ).Compress( ram ).End(); state.End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif inline bool Mmc6::IsRamEnabled() const { return reg & (RAM_LO_BANK_ENABLED|RAM_HI_BANK_ENABLED); } inline bool Mmc6::IsRamReadable(uint address) const { return (reg >> (address >> 8 & 0x2)) & 0x20; } inline bool Mmc6::IsRamWritable(uint address) const { return ((reg >> (address >> 8 & 0x2)) & 0x30) == 0x30; } NES_POKE_AD(Mmc6,7000) { NST_VERIFY( IsRamWritable(address) ); if (IsRamWritable( address )) ram[address & 0x3FF] = data; } NES_PEEK_A(Mmc6,7000) { NST_VERIFY( IsRamEnabled() && IsRamReadable(address) ); if (IsRamEnabled()) return IsRamReadable(address) ? ram[address & 0x3FF] : 0x00; else return address >> 8; } NES_POKE_D(Mmc6,A001) { if ((reg & 0x1) | (regs.ctrl0 & RAM_ENABLE)) reg = data | 0x1; } } } } nestopia-1.51.1/source/core/board/NstBoardMmc6.hpp000066400000000000000000000037601411157722000217160ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_MMC6_H #define NST_BOARD_MMC6_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardMmc3.hpp" namespace Nes { namespace Core { namespace Boards { class NST_NO_VTABLE Mmc6 : public Mmc3 { protected: explicit Mmc6(const Context&); private: void SubReset(bool); void Save(File&) const; void Load(File&); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); enum { RAM_ENABLE = 0x20, RAM_LO_BANK_WRITABLE = 0x10, RAM_LO_BANK_ENABLED = 0x20, RAM_HI_BANK_WRITABLE = 0x40, RAM_HI_BANK_ENABLED = 0x80 }; inline bool IsRamEnabled() const; inline bool IsRamReadable(uint) const; inline bool IsRamWritable(uint) const; NES_DECL_POKE( 7000 ); NES_DECL_PEEK( 7000 ); NES_DECL_POKE( 8000 ); NES_DECL_POKE( A001 ); uint reg; byte ram[SIZE_1K]; }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardMxRom.hpp000066400000000000000000000024121411157722000221470ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_MXROM_H #define NST_BOARD_MXROM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardGxRom.hpp" namespace Nes { namespace Core { namespace Boards { typedef GxRom MxRom; } } } #endif nestopia-1.51.1/source/core/board/NstBoardNRom.hpp000066400000000000000000000025551411157722000217700ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_NROM_H #define NST_BOARD_NROM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { class NRom : public Board { public: explicit NRom(const Context& c) : Board(c) {} private: void SubReset(bool) {} }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardNamcot.hpp000066400000000000000000000026631411157722000223360ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_NAMCOT_H #define NST_BOARD_NAMCOT_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardNamcot163.hpp" #include "NstBoardNamcot175.hpp" #include "NstBoardNamcot340.hpp" #include "NstBoardNamcot34xx.hpp" namespace Nes { namespace Core { namespace Boards { namespace Namcot { typedef N34x3 N3433; typedef N34x3 N3443; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardNamcot163.cpp000066400000000000000000000300411411157722000225520ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstBoard.hpp" #include "../NstTimer.hpp" #include "../NstFile.hpp" #include "NstBoardNamcot163.hpp" namespace Nes { namespace Core { namespace Boards { namespace Namcot { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif N163::N163(const Context& c) : Board (c), irq (*c.cpu), sound (*c.apu) { } N163::Sound::Sound(Apu& a,bool connect) : Channel(a) { Reset(); bool audible = UpdateSettings(); if (connect) Connect( audible ); } void N163::SubReset(const bool hard) { irq.Reset( hard, hard || irq.Connected() ); Map( 0x4800U, 0x4FFFU, &N163::Peek_4800, &N163::Poke_4800 ); Map( 0x5000U, 0x57FFU, &N163::Peek_5000, &N163::Poke_5000 ); Map( 0x5800U, 0x5FFFU, &N163::Peek_5800, &N163::Poke_5800 ); Map( 0x8000U, 0x87FFU, CHR_SWAP_1K_0 ); Map( 0x8800U, 0x8FFFU, CHR_SWAP_1K_1 ); Map( 0x9000U, 0x97FFU, CHR_SWAP_1K_2 ); Map( 0x9800U, 0x9FFFU, CHR_SWAP_1K_3 ); Map( 0xA000U, 0xA7FFU, CHR_SWAP_1K_4 ); Map( 0xA800U, 0xAFFFU, CHR_SWAP_1K_5 ); Map( 0xB000U, 0xB7FFU, CHR_SWAP_1K_6 ); Map( 0xB800U, 0xBFFFU, CHR_SWAP_1K_7 ); Map( 0xC000U, 0xC7FFU, &N163::Poke_C000 ); Map( 0xC800U, 0xCFFFU, &N163::Poke_C800 ); Map( 0xD000U, 0xD7FFU, &N163::Poke_D000 ); Map( 0xD800U, 0xDFFFU, &N163::Poke_D800 ); Map( 0xE000U, 0xE7FFU, PRG_SWAP_8K_0 ); Map( 0xE800U, 0xEFFFU, PRG_SWAP_8K_1 ); Map( 0xF000U, 0xF7FFU, PRG_SWAP_8K_2 ); Map( 0xF800U, 0xFFFFU, &N163::Poke_F800 ); } void N163::Irq::Reset(const bool hard) { if (hard) count = 0; } void N163::Sound::Reset() { exAddress = 0x00; exIncrease = 0x01; startChannel = NUM_CHANNELS; frequency = 0; std::memset( wave, 0, sizeof(wave) ); std::memset( exRam, 0, sizeof(exRam) ); for (uint i=0; i < NUM_CHANNELS; ++i) channels[i].Reset(); dcBlocker.Reset(); } void N163::Sound::BaseChannel::Reset() { enabled = false; active = false; timer = 0; frequency = 0; phase = 0; waveLength = 0; waveOffset = 0; volume = 0; } void N163::Load(File& file) { if (board.HasBattery() && (board == Type::NAMCOT_163_S_0 || board == Type::NAMCOT_163_S_1)) { const File::LoadBlock block[] = { { wrk.Source().Mem(), board.GetWram() }, { sound.GetExRam(), Sound::EXRAM_SIZE } }; file.Load( File::BATTERY, block ); } else { Board::Load( file ); } } void N163::Save(File& file) const { if (board.HasBattery() && (board == Type::NAMCOT_163_S_0 || board == Type::NAMCOT_163_S_1)) { const File::SaveBlock block[] = { { wrk.Source().Mem(), board.GetWram() }, { sound.GetExRam(), Sound::EXRAM_SIZE } }; file.Save( File::BATTERY, block ); } else { Board::Save( file ); } } byte* N163::Sound::GetExRam() { return exRam; } const byte* N163::Sound::GetExRam() const { return exRam; } void N163::Sound::SaveState(State::Saver& state,const dword baseChunk) const { state.Begin( baseChunk ); state.Begin( AsciiId<'R','E','G'>::V ).Write8( exAddress | (exIncrease << 7) ).End(); state.Begin( AsciiId<'R','A','M'>::V ).Compress( exRam ).End(); state.End(); } void N163::Sound::LoadState(State::Loader& state) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: { const uint data = state.Read8(); exAddress = data & 0x7F; exIncrease = data >> 7; break; } case AsciiId<'R','A','M'>::V: state.Uncompress( exRam ); for (uint i=0; i < sizeof(exRam); ++i) { wave[i*2+0] = (exRam[i] & 0xFU) << 2; wave[i*2+1] = (exRam[i] >> 4) << 2; } for (uint i=64; i < sizeof(exRam); i += 8) { BaseChannel& channel = channels[(i - 64) >> 3]; channel.Reset(); channel.SetFrequency ( FetchFrequency(i) ); channel.SetWaveLength ( exRam[i+4] ); channel.SetWaveOffset ( exRam[i+6] ); channel.SetVolume ( exRam[i+7] ); channel.Validate(); } SetChannelState( exRam[0x7F] ); break; } state.End(); } } void N163::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'N','6','3'>::V) ); if (baseChunk == AsciiId<'N','6','3'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'I','R','Q'>::V: { State::Loader::Data<3> data( state ); irq.unit.count = data[1] | (data[2] << 8 & 0x7F00) | (data[0] << 15 & 0x8000); break; } case AsciiId<'S','N','D'>::V: sound.LoadState( state ); break; } state.End(); } } } void N163::SubSave(State::Saver& state) const { state.Begin( AsciiId<'N','6','3'>::V ); const byte data[3] = { irq.unit.count >> 15, irq.unit.count >> 0 & 0xFF, irq.unit.count >> 8 & 0x7F }; state.Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End(); sound.SaveState( state, AsciiId<'S','N','D'>::V ); state.End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif bool N163::Irq::Clock() { return (count - 0x8000 < 0x7FFF) && (++count == 0xFFFF); } inline bool N163::Sound::BaseChannel::CanOutput() const { return volume && frequency && enabled; } inline void N163::Sound::BaseChannel::Validate() { active = CanOutput(); } inline void N163::Sound::BaseChannel::SetFrequency(const uint f) { frequency = f; } inline void N163::Sound::BaseChannel::SetWaveLength(const uint data) { //const dword length = (0x20UL - (data & REG_WAVELENGTH)) << PHASE_SHIFT; const dword length = (0x100UL - (data & REG_WAVELENGTH)) << PHASE_SHIFT; if (waveLength != length) { waveLength = length; phase = 0; } enabled = data >> REG_ENABLE_SHIFT; } inline void N163::Sound::BaseChannel::SetWaveOffset(const uint data) { waveOffset = data; } inline void N163::Sound::BaseChannel::SetVolume(const uint data) { volume = (data & REG_VOLUME) * VOLUME; } inline dword N163::Sound::BaseChannel::GetSample ( const Cycle rate, const Cycle factor, const byte (&wave)[0x100] ) { NST_VERIFY( bool(active) == CanOutput() ); if (active) { phase = (phase + (timer + rate) / factor * frequency) % waveLength; timer = (timer + rate) % factor; return wave[(waveOffset + (phase >> PHASE_SHIFT)) & 0xFF] * dword(volume); } return 0; } N163::Sound::Sample N163::Sound::GetSample() { if (output) { dword sample = 0; for (BaseChannel* channel = channels+startChannel; channel != channels+NUM_CHANNELS; ++channel) sample += channel->GetSample( rate, frequency, wave ); return dcBlocker.Apply( sample * output / DEFAULT_VOLUME ); } else { return 0; } } bool N163::Sound::UpdateSettings() { uint volume = GetVolume(EXT_N163) * 68U / DEFAULT_VOLUME; output = IsMuted() ? 0 : volume; rate = GetCpuClockBase() * qaword(1UL << SPEED_SHIFT) / (GetSampleRate() * 45UL * GetCpuClockDivider()); dcBlocker.Reset(); return volume; } inline void N163::Sound::SetChannelState(uint data) { data = (data >> 4 & 0x7) + 1; frequency = dword(data) << SPEED_SHIFT; startChannel = NUM_CHANNELS - data; } inline dword N163::Sound::FetchFrequency(uint address) const { address &= 0x78; return ( (dword(exRam[address+0x0] ) << 0) | (dword(exRam[address+0x2] ) << 8) | (dword(exRam[address+0x4] & 0x3U) << 16) ); } inline void N163::Sound::WriteWave(const uint data) { const uint index = exAddress << 1; wave[index+0] = (data & 0xF) << 2; wave[index+1] = (data >> 4) << 2; } uint N163::Sound::ReadData() { const uint data = exRam[exAddress]; exAddress = (exAddress + exIncrease) & 0x7F; return data; } NES_PEEK(N163,4800) { return sound.ReadData(); } void N163::Sound::WriteData(const uint data) { Update(); WriteWave( data ); exRam[exAddress] = data; if (exAddress >= 0x40) { BaseChannel& channel = channels[(exAddress - 0x40) >> 3]; switch (exAddress & 0x7) { case 0x4: channel.SetWaveLength( data ); case 0x0: case 0x2: channel.SetFrequency( FetchFrequency(exAddress) ); break; case 0x6: channel.SetWaveOffset( data ); break; case 0x7: channel.SetVolume( data ); if (exAddress == 0x7F) SetChannelState( data ); break; } channel.Validate(); } exAddress = (exAddress + exIncrease) & 0x7F; } NES_POKE_D(N163,4800) { sound.WriteData( data ); } NES_PEEK(N163,5000) { irq.Update(); return irq.unit.count & 0xFF; } NES_POKE_D(N163,5000) { irq.Update(); irq.unit.count = (irq.unit.count & 0xFF00) | data; irq.ClearIRQ(); } NES_PEEK(N163,5800) { irq.Update(); return irq.unit.count >> 8; } NES_POKE_D(N163,5800) { irq.Update(); irq.unit.count = (irq.unit.count & 0x00FF) | (data << 8); irq.ClearIRQ(); } void N163::Sound::WriteAddress(const uint data) { NST_COMPILE_ASSERT( EXRAM_INC == 0x80 ); exAddress = data & 0x7F; exIncrease = data >> 7; } void N163::SwapNmt(const uint address,const uint data) const { ppu.Update(); nmt.Source( data < 0xE0 ).SwapBank( address, data ); } NES_POKE_D(N163,C000) { SwapNmt( 0x0000, data ); } NES_POKE_D(N163,C800) { SwapNmt( 0x0400, data ); } NES_POKE_D(N163,D000) { SwapNmt( 0x0800, data ); } NES_POKE_D(N163,D800) { SwapNmt( 0x0C00, data ); } NES_POKE_D(N163,F800) { sound.WriteAddress( data ); } void N163::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardNamcot163.hpp000066400000000000000000000077131411157722000225710ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_NAMCOT_163_H #define NST_BOARD_NAMCOT_163_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Namcot { class N163 : public Board { public: explicit N163(const Context&); class Sound : public Apu::Channel { public: explicit Sound(Apu&,bool=true); enum { EXRAM_SIZE = 0x80 }; void WriteData(uint); uint ReadData(); void WriteAddress(uint); byte* GetExRam(); const byte* GetExRam() const; void SaveState(State::Saver&,dword) const; void LoadState(State::Loader&); protected: void Reset(); bool UpdateSettings(); Sample GetSample(); private: inline void SetChannelState(uint); inline void WriteWave(uint); inline dword FetchFrequency(uint) const; enum { NUM_CHANNELS = 8, EXRAM_INC = 0x80, //REG_WAVELENGTH = 0x1C, REG_WAVELENGTH = 0xFC, REG_ENABLE_SHIFT = 5, REG_VOLUME = 0x0F, PHASE_SHIFT = 18, SPEED_SHIFT = 20 }; class BaseChannel { public: void Reset(); inline dword GetSample(Cycle,Cycle,const byte (&)[0x100]); inline void SetFrequency (uint); inline void SetWaveLength (uint); inline void SetWaveOffset (uint); inline void SetVolume (uint); inline void Validate(); private: enum { VOLUME = OUTPUT_MUL / 16 }; inline bool CanOutput() const; ibool enabled; ibool active; Cycle timer; Cycle frequency; Cycle phase; dword waveLength; uint waveOffset; uint volume; }; uint output; Cycle rate; Cycle frequency; uint exAddress; uint exIncrease; uint startChannel; byte wave[0x100]; byte exRam[0x80]; BaseChannel channels[NUM_CHANNELS]; DcBlocker dcBlocker; }; private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Load(File&); void Save(File&) const; void Sync(Event,Input::Controllers*); void SwapChr(uint,uint,uint) const; void SwapNmt(uint,uint) const; struct Irq { void Reset(bool); bool Clock(); uint count; }; NES_DECL_PEEK( 4800 ); NES_DECL_POKE( 4800 ); NES_DECL_PEEK( 5000 ); NES_DECL_POKE( 5000 ); NES_DECL_PEEK( 5800 ); NES_DECL_POKE( 5800 ); NES_DECL_POKE( C000 ); NES_DECL_POKE( C800 ); NES_DECL_POKE( D000 ); NES_DECL_POKE( D800 ); NES_DECL_POKE( F800 ); Timer::M2 irq; Sound sound; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardNamcot175.cpp000066400000000000000000000050651411157722000225650ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // Copyright (C) 2021 Rupert Carmichael // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardNamcot175.hpp" namespace Nes { namespace Core { namespace Boards { namespace Namcot { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif N175::N175(const Context& c) : Board (c) { } void N175::SubReset(const bool hard) { Map( 0x6000U, 0x7FFFU, &N175::Peek_6000 ); Map( 0x6000U, 0x7FFFU, &N175::Poke_6000 ); Map( 0x8000U, 0x87FFU, CHR_SWAP_1K_0 ); Map( 0x8800U, 0x8FFFU, CHR_SWAP_1K_1 ); Map( 0x9000U, 0x97FFU, CHR_SWAP_1K_2 ); Map( 0x9800U, 0x9FFFU, CHR_SWAP_1K_3 ); Map( 0xA000U, 0xA7FFU, CHR_SWAP_1K_4 ); Map( 0xA800U, 0xAFFFU, CHR_SWAP_1K_5 ); Map( 0xB000U, 0xB7FFU, CHR_SWAP_1K_6 ); Map( 0xB800U, 0xBFFFU, CHR_SWAP_1K_7 ); Map( 0xC000U, 0xC7FFU, &N175::Poke_C000 ); Map( 0xE000U, 0xE7FFU, PRG_SWAP_8K_0 ); Map( 0xE800U, 0xEFFFU, PRG_SWAP_8K_1 ); Map( 0xF000U, 0xF7FFU, PRG_SWAP_8K_2 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(N175,6000) { NST_VERIFY( wrk.Readable(0) ); return wrk.Readable(0) ? wrk[0][address & 0x7FFU] : (address >> 8); } NES_POKE_AD(N175,6000) { NST_VERIFY( wrk.Writable(0) ); if (wrk.Writable(0)) wrk[0][address & 0x7FFU] = data; } NES_POKE_D(N175,C000) { bool enable = data & 0x1; wrk.Source().SetSecurity(enable, enable); } } } } } nestopia-1.51.1/source/core/board/NstBoardNamcot175.hpp000066400000000000000000000030151411157722000225630ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // Copyright (C) 2021 Rupert Carmichael // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_NAMCOT_175_H #define NST_BOARD_NAMCOT_175_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Namcot { class N175 : public Board { public: explicit N175(const Context&); private: void SubReset(bool); NES_DECL_PEEK( 6000 ); NES_DECL_POKE( 6000 ); NES_DECL_POKE( C000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardNamcot340.cpp000066400000000000000000000047451411157722000225630ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // Copyright (C) 2021 Rupert Carmichael // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardNamcot340.hpp" namespace Nes { namespace Core { namespace Boards { namespace Namcot { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif N340::N340(const Context& c) : Board (c) { } void N340::SubReset(const bool hard) { Map( 0x8000U, 0x87FFU, CHR_SWAP_1K_0 ); Map( 0x8800U, 0x8FFFU, CHR_SWAP_1K_1 ); Map( 0x9000U, 0x97FFU, CHR_SWAP_1K_2 ); Map( 0x9800U, 0x9FFFU, CHR_SWAP_1K_3 ); Map( 0xA000U, 0xA7FFU, CHR_SWAP_1K_4 ); Map( 0xA800U, 0xAFFFU, CHR_SWAP_1K_5 ); Map( 0xB000U, 0xB7FFU, CHR_SWAP_1K_6 ); Map( 0xB800U, 0xBFFFU, CHR_SWAP_1K_7 ); Map( 0xE000U, 0xE7FFU, &N340::Poke_E000 ); Map( 0xE800U, 0xEFFFU, PRG_SWAP_8K_1 ); Map( 0xF000U, 0xF7FFU, PRG_SWAP_8K_2 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(N340,E000) { prg.SwapBank( 0, data & 0x3FU ); switch ((data >> 6) & 0x3U) { case 0x0U: // One-screen A ppu.SetMirroring( Ppu::NMT_0 ); break; case 0x1U: // Vertical ppu.SetMirroring( Ppu::NMT_V ); break; case 0x2U: // One-screen B ppu.SetMirroring( Ppu::NMT_1 ); break; case 0x3U: // Horizontal ppu.SetMirroring( Ppu::NMT_H ); break; } } } } } } nestopia-1.51.1/source/core/board/NstBoardNamcot340.hpp000066400000000000000000000027231411157722000225620ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // Copyright (C) 2021 Rupert Carmichael // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_NAMCOT_340_H #define NST_BOARD_NAMCOT_340_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Namcot { class N340 : public Board { public: explicit N340(const Context&); private: void SubReset(bool); NES_DECL_POKE( E000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardNamcot34xx.cpp000066400000000000000000000065401411157722000230560ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardNamcot34xx.hpp" namespace Nes { namespace Core { namespace Boards { namespace Namcot { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void N34x3::SubReset(const bool hard) { if (hard) ctrl = 0; for (uint i=0x8000; i < 0xA000; i += 0x2) { Map( i + 0x0, &N34x3::Poke_8000 ); Map( i + 0x1, &N34x3::Poke_8001 ); } } void N34xx::SubReset(const bool hard) { N34x3::SubReset( hard ); for (uint i=0x0000; i < 0x8000; i += 0x2) Map( 0x8000 + i, &N34xx::Poke_8000 ); } void N34x3::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'N','3','4'>::V) ); if (baseChunk == AsciiId<'N','3','4'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) ctrl = state.Read8(); state.End(); } } } void N34x3::SubSave(State::Saver& state) const { state.Begin( AsciiId<'N','3','4'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( ctrl ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(N34x3,8000) { ctrl = data; } NES_POKE_D(N34x3,8001) { const uint mode = ctrl & 0x7; if (mode >= 6) { prg.SwapBank( (mode-6) << 13, data ); } else { ppu.Update(); UpdateChr( mode, data & 0x3F ); } } void NST_FASTCALL N34x3::UpdateChr(uint mode,uint data) const { if (mode >= 2) chr.SwapBank( (mode+2) << 10, data | 0x40 ); else chr.SwapBank( mode << 11, data >> 1 ); } void NST_FASTCALL N3446::UpdateChr(uint mode,uint data) const { NST_VERIFY( mode >= 2 ); if (mode >= 2) chr.SwapBank( (mode-2) << 11, data ); } void NST_FASTCALL N3425::UpdateChr(uint mode,uint data) const { nmt.SwapBank( mode << 9 & 0xC00, data >> 5 ); N34x3::UpdateChr( mode, data ); } NES_POKE_AD(N34xx,8000) { ppu.SetMirroring( (data & 0x40) ? Ppu::NMT_1 : Ppu::NMT_0 ); N34x3::NES_DO_POKE(8000,address,data); } } } } } nestopia-1.51.1/source/core/board/NstBoardNamcot34xx.hpp000066400000000000000000000043451411157722000230640ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_NAMCOT_N34XX_H #define NST_BOARD_NAMCOT_N34XX_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Namcot { class N34x3 : public Board { public: explicit N34x3(const Context& c) : Board(c) {} protected: void SubReset(bool); virtual void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_POKE( 8000 ); private: void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); NES_DECL_POKE( 8001 ); uint ctrl; }; class N3446 : public N34x3 { public: explicit N3446(const Context& c) : N34x3(c) {} private: void NST_FASTCALL UpdateChr(uint,uint) const; }; class N3425 : public N34x3 { public: explicit N3425(const Context& c) : N34x3(c) {} private: void NST_FASTCALL UpdateChr(uint,uint) const; }; class N34xx : public N34x3 { public: explicit N34xx(const Context& c) : N34x3(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardNanjing.cpp000066400000000000000000000111001411157722000224560ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardNanjing.hpp" namespace Nes { namespace Core { namespace Boards { namespace Nanjing { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Standard::SubReset(bool) { strobe = 0xFF; regs[0] = 0xFF; regs[1] = 0x00; trigger = 0x00; security = 0x00; ppu.SetHBlankHook( Hook(this,&Standard::Hook_HBlank) ); for (uint i=0x5000; i < 0x6000; i += 0x800) { Map( i + 0x000, i + 0x0FF, &Standard::Peek_5000 ); Map( i + 0x100, i + 0x1FF, &Standard::Peek_5100 ); Map( i + 0x200, i + 0x4FF, &Standard::Peek_5000 ); Map( i + 0x500, i + 0x5FF, &Standard::Peek_5500 ); Map( i + 0x600, i + 0x7FF, &Standard::Peek_5000 ); } Map( 0x5100U, &Standard::Poke_5100 ); Map( 0x5101U, &Standard::Poke_5101 ); for (uint i=0x5000; i < 0x6000; i += 0x400) { Map( i + 0x000, i + 0x0FF, &Standard::Poke_5000 ); Map( i + 0x200, i + 0x2FF, &Standard::Poke_5000 ); Map( i + 0x300, i + 0x3FF, &Standard::Poke_5300 ); } } void Standard::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'N','J','N'>::V) ); if (baseChunk == AsciiId<'N','J','N'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: { State::Loader::Data<2> data( state ); regs[0] = data[0]; regs[1] = data[1]; break; } case AsciiId<'S','E','C'>::V: { State::Loader::Data<3> data( state ); strobe = data[0]; trigger = (data[1] & 0x1) ? 0xFF : 0x00; security = data[2]; break; } } state.End(); } } } void Standard::SubSave(State::Saver& state) const { state.Begin( AsciiId<'N','J','N'>::V ); { const byte data[2] = { regs[0], regs[1] }; state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End(); } { const byte data[3] = { strobe, trigger ? 0x1 : 0x0, security }; state.Begin( AsciiId<'S','E','C'>::V ).Write( data ).End(); } state.End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK(Standard,5000) { return 0x4; } NES_POKE_AD(Standard,5000) { regs[address >> 9 & 0x1] = data; prg.SwapBank( (regs[0] & 0xFU) | (regs[1] << 4) ); if (!((address & 0x0300) | (regs[0] & 0x80U))) { ppu.Update(); if (ppu.GetScanline() <= 127) chr.SwapBank(0); } } NES_PEEK(Standard,5100) { return security; } NES_POKE_D(Standard,5100) { if (data == 0x6) prg.SwapBank( 0x3 ); } NES_POKE_D(Standard,5101) { const uint address = strobe; strobe = data; if (address && !data) trigger ^= 0xFFU; } NES_POKE_D(Standard,5300) { security = data; } NES_PEEK(Standard,5500) { return security & trigger; } NES_HOOK(Standard,HBlank) { if ((regs[0] & 0x80U) && ppu.IsEnabled()) { switch (const int scanline=ppu.GetScanline()) { case 127: case 239: chr.SwapBanks( scanline == 127, scanline == 127 ); break; } } } } } } } nestopia-1.51.1/source/core/board/NstBoardNanjing.hpp000066400000000000000000000035161411157722000224770ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_NANJING_H #define NST_BOARD_NANJING_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Nanjing { class Standard : public Board { public: explicit Standard(const Context& c) : Board(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void UpdatePrg(); NES_DECL_PEEK( 5000 ); NES_DECL_POKE( 5000 ); NES_DECL_PEEK( 5100 ); NES_DECL_POKE( 5100 ); NES_DECL_POKE( 5101 ); NES_DECL_POKE( 5300 ); NES_DECL_PEEK( 5500 ); NES_DECL_HOOK( HBlank ); byte regs[2]; byte strobe; byte trigger; uint security; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardNihon.cpp000066400000000000000000000026541411157722000221630ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardNihon.hpp" namespace Nes { namespace Core { namespace Boards { namespace Nihon { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void UnRomM5::SubReset(bool) { Map( 0x8000U, 0xFFFFU, PRG_SWAP_16K_1 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } } } nestopia-1.51.1/source/core/board/NstBoardNihon.hpp000066400000000000000000000026331411157722000221650ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_NIHON_H #define NST_BOARD_NIHON_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Nihon { class UnRomM5 : public Board { public: explicit UnRomM5(const Context& c) : Board(c) {} private: void SubReset(bool); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardNitra.cpp000066400000000000000000000043061411157722000221610ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardNitra.hpp" namespace Nes { namespace Core { namespace Boards { namespace Nitra { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Tda::SubReset(const bool hard) { Mmc3::SubReset( hard ); Map( 0x8000U, 0xFFFFU, &Tda::Poke_8000 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(Tda,8000) { data = address & 0xFF; address = (address & 0xE000) | (address >> 10 & 0x1); switch (address) { case 0x8000: Mmc3::NES_DO_POKE( 8000, address, data ); break; case 0x8001: Mmc3::NES_DO_POKE( 8001, address, data ); break; case 0xA000: SetMirroringHV( data ); break; case 0xA001: Mmc3::NES_DO_POKE( A001, address, data ); break; case 0xC000: Mmc3::NES_DO_POKE( C000, address, data ); break; case 0xC001: Mmc3::NES_DO_POKE( C001, address, data ); break; case 0xE000: Mmc3::NES_DO_POKE( E000, address, data ); break; case 0xE001: Mmc3::NES_DO_POKE( E001, address, data ); break; } } } } } } nestopia-1.51.1/source/core/board/NstBoardNitra.hpp000066400000000000000000000026601411157722000221670ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_NITRA_H #define NST_BOARD_NITRA_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Nitra { class Tda : public Mmc3 { public: explicit Tda(const Context& c) : Mmc3(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardNtdec.cpp000066400000000000000000000104251411157722000221400ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardNtdec.hpp" namespace Nes { namespace Core { namespace Boards { namespace Ntdec { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Asder::SubReset(const bool hard) { if (hard) { command = 0; for (uint i=0; i < 8; ++i) banks.chr[i] = 0; } for (uint i=0x0000; i < 0x2000; i += 0x2) { Map( 0x8000U + i, &Asder::Poke_8000 ); Map( 0xA000U + i, &Asder::Poke_A000 ); Map( 0xC000U + i, &Asder::Poke_C000 ); Map( 0xE000U + i, &Asder::Poke_E000 ); } } void Asder::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'N','A','S'>::V) ); if (baseChunk == AsciiId<'N','A','S'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: command = state.Read8(); break; case AsciiId<'B','N','K'>::V: state.Read( banks.chr ); break; } state.End(); } } } void Asder::SubSave(State::Saver& state) const { state.Begin( AsciiId<'N','A','S'>::V ); state.Begin( AsciiId<'R','E','G'>::V ).Write8( command ).End(); state.Begin( AsciiId<'B','N','K'>::V ).Write( banks.chr ).End(); state.End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Asder::UpdateChr() const { ppu.Update(); const uint extChr = (banks.chr[1] & 0x2U) ? banks.chr[0] : 0; chr.SwapBanks ( banks.chr[2] | (extChr << 5 & 0x80), banks.chr[3] | (extChr << 4 & 0x80) ); chr.SwapBanks ( banks.chr[4] | (extChr << 4 & 0x100), banks.chr[5] | (extChr << 3 & 0x100), banks.chr[6] | (extChr << 2 & 0x100), banks.chr[7] | (extChr << 1 & 0x100) ); } NES_POKE_D(Asder,8000) { command = data; } NES_POKE_D(Asder,A000) { const uint address = command & 0x7; if (address < 2) { prg.SwapBank( address << 13, data ); } else { banks.chr[address] = data >> uint(address < 4); UpdateChr(); } } NES_POKE_D(Asder,C000) { banks.chr[0] = data; UpdateChr(); } NES_POKE_D(Asder,E000) { banks.chr[1] = data; UpdateChr(); SetMirroringHV( data ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void FightingHero::SubReset(const bool hard) { Map( 0x6000U, 0x7FFFU, &FightingHero::Poke_6000 ); if (hard) prg.SwapBank(~0U); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(FightingHero,6000) { ppu.Update(); switch (address & 0x3) { case 0x0: chr.SwapBank( data >> 2 ); break; case 0x1: chr.SwapBank( data >> 1 ); break; case 0x2: chr.SwapBank( data >> 1 ); break; case 0x3: prg.SwapBank( data ); break; } } } } } } nestopia-1.51.1/source/core/board/NstBoardNtdec.hpp000066400000000000000000000037141411157722000221500ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_NTDEC_H #define NST_BOARD_NTDEC_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardCxRom.hpp" namespace Nes { namespace Core { namespace Boards { namespace Ntdec { typedef CnRom N715062; class Asder : public Board { public: explicit Asder(const Context& c) : Board(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void UpdateChr() const; NES_DECL_POKE( 8000 ); NES_DECL_POKE( A000 ); NES_DECL_POKE( C000 ); NES_DECL_POKE( E000 ); uint command; struct { byte chr[8]; } banks; }; class FightingHero : public Board { public: explicit FightingHero(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 6000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardNxRom.hpp000066400000000000000000000024221411157722000221510ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_NXROM_H #define NST_BOARD_NXROM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardSunsoft.hpp" namespace Nes { namespace Core { namespace Boards { typedef Sunsoft::S4 NxRom; } } } #endif nestopia-1.51.1/source/core/board/NstBoardOpenCorp.cpp000066400000000000000000000111051411157722000226240ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// // Reference: https://github.com/TASVideos/fceux/blob/master/src/boards/156.cpp #include "NstBoard.hpp" #include "NstBoardOpenCorp.hpp" namespace Nes { namespace Core { namespace Boards { namespace OpenCorp { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Daou306::RemapChr() { chr.SwapBank( 0x0000, (chrHigh[0] << 8) | chrLow[0] ); chr.SwapBank( 0x0400, (chrHigh[1] << 8) | chrLow[1] ); chr.SwapBank( 0x0800, (chrHigh[2] << 8) | chrLow[2] ); chr.SwapBank( 0x0C00, (chrHigh[3] << 8) | chrLow[3] ); chr.SwapBank( 0x1000, (chrHigh[4] << 8) | chrLow[4] ); chr.SwapBank( 0x1400, (chrHigh[5] << 8) | chrLow[5] ); chr.SwapBank( 0x1800, (chrHigh[6] << 8) | chrLow[6] ); chr.SwapBank( 0x1C00, (chrHigh[7] << 8) | chrLow[7] ); if (mirrorUsed) { ppu.SetMirroring( mirror ^ 0x1 ? Ppu::NMT_V : Ppu::NMT_H ); } else { ppu.SetMirroring( Ppu::NMT_0 ); } } void Daou306::SubReset(bool) { for (uint i = 0; i < 8; i++) { chrLow[i] = chrHigh[i] = 0; } Map( 0xC000U, 0xC00FU, &Daou306::Poke_C000 ); Map( 0xC010U, PRG_SWAP_16K_0 ); Map( 0xC014U, &Daou306::Poke_C014 ); } NES_POKE_AD(Daou306,C000) { switch (address) { case 0xC000: case 0xC001: case 0xC002: case 0xC003: chrLow[address & 0x03] = data; break; case 0xC004: case 0xC005: case 0xC006: case 0xC007: chrHigh[address & 0x03] = data; break; case 0xC008: case 0xC009: case 0xC00A: case 0xC00B: chrLow[4 + (address & 0x03)] = data; break; case 0xC00C: case 0xC00D: case 0xC00E: case 0xC00F: chrHigh[4 + (address & 0x03)] = data; break; } RemapChr(); } NES_POKE_D(Daou306,C014) { mirror = data; mirrorUsed = 1; } void Daou306::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'O','P','C'>::V) ); if (baseChunk == AsciiId<'O','P','C'>::V) { state.Begin(); State::Loader::Data<18> data( state ); chrLow[0] = data[0]; chrLow[1] = data[1]; chrLow[2] = data[2]; chrLow[3] = data[3]; chrLow[4] = data[4]; chrLow[5] = data[5]; chrLow[6] = data[6]; chrLow[7] = data[7]; chrHigh[0] = data[8]; chrHigh[1] = data[9]; chrHigh[2] = data[10]; chrHigh[3] = data[11]; chrHigh[4] = data[12]; chrHigh[5] = data[13]; chrHigh[6] = data[14]; chrHigh[7] = data[15]; mirror = data[16]; mirrorUsed = data[17]; state.End(); RemapChr(); } } void Daou306::SubSave(State::Saver& state) const { state.Begin( AsciiId<'O','P','C'>::V ); const byte data[18] = { chrLow[0], chrLow[1], chrLow[2], chrLow[3], chrLow[4], chrLow[5], chrLow[6], chrLow[7], chrHigh[0], chrHigh[1], chrHigh[2], chrHigh[3], chrHigh[4], chrHigh[5], chrHigh[6], chrHigh[7], mirror, mirrorUsed, }; state.Begin( AsciiId<'C','H','R'>::V ).Write( data ).End(); state.End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } } } nestopia-1.51.1/source/core/board/NstBoardOpenCorp.hpp000066400000000000000000000032431411157722000226350ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_OPENCORP_H #define NST_BOARD_OPENCORP_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace OpenCorp { class Daou306 : public Board { public: explicit Daou306(const Context& c) : Board(c) {} private: byte chrLow[8]; byte chrHigh[8]; byte mirror; byte mirrorUsed; void RemapChr(); void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); NES_DECL_POKE( C000 ); NES_DECL_POKE( C014 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardPxRom.hpp000066400000000000000000000025411411157722000221550ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_PXROM_H #define NST_BOARD_PXROM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardMmc2.hpp" namespace Nes { namespace Core { namespace Boards { class PxRom : public Mmc2 { public: explicit PxRom(const Context& c) : Mmc2(c) {} }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardQj.cpp000066400000000000000000000047411411157722000214610ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardQj.hpp" namespace Nes { namespace Core { namespace Boards { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Qj::SubReset(const bool hard) { if (hard) exReg = 0x0; Mmc3::SubReset( hard ); Map( 0x6000U, 0x7FFFU, &Qj::Poke_6000 ); } void Qj::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'Q','J'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) exReg = state.Read8() & 0x1; state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void Qj::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); state.Begin( AsciiId<'Q','J'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( exReg ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void NST_FASTCALL Qj::UpdatePrg(uint address,uint bank) { prg.SwapBank( address, (exReg << 4) | (bank & 0x0F) ); } void NST_FASTCALL Qj::UpdateChr(uint address,uint bank) const { chr.SwapBank( address, (exReg << 7) | (bank & 0x7F) ); } NES_POKE_D(Qj,6000) { data &= 0x1; if (exReg != data) { exReg = data; Mmc3::UpdatePrg(); Mmc3::UpdateChr(); } } } } } nestopia-1.51.1/source/core/board/NstBoardQj.hpp000066400000000000000000000031051411157722000214570ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_QJ_H #define NST_BOARD_QJ_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { class Qj : public Mmc3 { public: explicit Qj(const Context& c) : Mmc3(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void NST_FASTCALL UpdatePrg(uint,uint); void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_POKE( 6000 ); uint exReg; }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardRcm.cpp000066400000000000000000000062301411157722000216230ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardRcm.hpp" namespace Nes { namespace Core { namespace Boards { namespace Rcm { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Gs2015::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &Gs2015::Poke_8000 ); if (hard) prg.SwapBank(0); } void Gs2013::SubReset(const bool hard) { Map( 0x6000U, 0x7FFFU, &Gs2013::Peek_6000 ); Map( 0x8000U, 0xFFFFU, &Gs2013::Poke_8000 ); if (hard) { wrk.SwapBank( 0x1F ); prg.SwapBank( ~0U ); } } void Gs2004::SubReset(const bool hard) { Map( 0x6000U, 0x7FFFU, &Gs2004::Peek_6000 ); Map( 0x8000U, 0xFFFFU, PRG_SWAP_32K ); if (hard) { wrk.SwapBank( ~0U ); prg.SwapBank( prg.Source().Size() / SIZE_32K - 1 ); } } void TetrisFamily::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &TetrisFamily::Poke_8000 ); if (hard) prg.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(Gs2013,6000) { return wrk[0][address - 0x6000]; } NES_PEEK_A(Gs2004,6000) { return wrk[0][address - 0x6000]; } NES_POKE_D(Gs2013,8000) { prg.SwapBank( (data & 0x8) ? (data & 0x9) : (data & 0x7) ); } NES_POKE_A(Gs2015,8000) { ppu.Update(); prg.SwapBank( address ); chr.SwapBank( address >> 1 ); } NES_POKE_A(TetrisFamily,8000) { ppu.SetMirroring( (address & 0x80) ? Ppu::NMT_H : Ppu::NMT_V ); switch (address & 0x30) { case 0x00: case 0x30: prg.SwapBank( address & 0xF ); break; case 0x20: case 0x10: address = (address << 1 & 0x1E) | (address >> 4 & 0x02); prg.SwapBanks( address, address ); break; } } } } } } nestopia-1.51.1/source/core/board/NstBoardRcm.hpp000066400000000000000000000040661411157722000216350ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_RCM_H #define NST_BOARD_RCM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Rcm { class Gs2015 : public Board { public: explicit Gs2015(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; class Gs2013 : public Board { public: explicit Gs2013(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_PEEK( 6000 ); NES_DECL_POKE( 8000 ); }; class Gs2004 : public Board { public: explicit Gs2004(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_PEEK( 6000 ); }; class TetrisFamily : public Board { public: explicit TetrisFamily(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardRexSoft.hpp000066400000000000000000000023231411157722000225000ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_REXSOFT_H #define NST_BOARD_REXSOFT_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardRexSoftSl1632.hpp" #include "NstBoardRexSoftDb5z.hpp" #endif nestopia-1.51.1/source/core/board/NstBoardRexSoftDb5z.cpp000066400000000000000000000050431411157722000232220ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardRexSoftDb5z.hpp" namespace Nes { namespace Core { namespace Boards { namespace RexSoft { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Dbz5::SubReset(const bool hard) { if (hard) exReg = 0; Mmc3::SubReset( hard ); Map( 0x4100U, 0x5FFFU, &Dbz5::Peek_4100, &Dbz5::Poke_4100 ); Map( 0x6000U, 0x7FFFU, &Dbz5::Peek_4100 ); } void Dbz5::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'R','Z','5'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) exReg = state.Read8(); state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void Dbz5::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); state.Begin( AsciiId<'R','Z','5'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( exReg ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Dbz5,4100) { if (exReg != data) { exReg = data; Mmc3::UpdateChr(); } } NES_PEEK(Dbz5,4100) { return 0x01; } void NST_FASTCALL Dbz5::UpdateChr(uint address,uint bank) const { chr.SwapBank( address, (exReg << ((address & 0x1000) ? 4 : 8) & 0x100) | bank ); } } } } } nestopia-1.51.1/source/core/board/NstBoardRexSoftDb5z.hpp000066400000000000000000000032021411157722000232220ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_REXSOFT_DB5Z_H #define NST_BOARD_REXSOFT_DB5Z_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace RexSoft { class Dbz5 : public Mmc3 { public: explicit Dbz5(const Context& c) : Mmc3(c,REV_A) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_PEEK( 4100 ); NES_DECL_POKE( 4100 ); uint exReg; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardRexSoftSl1632.cpp000066400000000000000000000117531411157722000233150ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardRexSoftSl1632.hpp" namespace Nes { namespace Core { namespace Boards { namespace RexSoft { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Sl1632::SubReset(const bool hard) { exMode = 0; if (hard) { for (uint i=0; i < 2; ++i) exPrg[i] = 0; for (uint i=0; i < 8; ++i) exChr[i] = 0; exNmt = 0; } Mmc3::SubReset( hard ); Map( 0x8000U, 0xFFFFU, &Sl1632::Poke_8000 ); } void Sl1632::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'R','1','2'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<12> data( state ); exMode = data[0]; for (uint i=0; i < 2; ++i) exPrg[i] = data[1+i]; for (uint i=0; i < 8; ++i) exChr[i] = data[1+2+i]; exNmt = data[11]; } state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void Sl1632::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); const byte data[12] = { exMode, exPrg[0], exPrg[1], exChr[0], exChr[1], exChr[2], exChr[3], exChr[4], exChr[5], exChr[6], exChr[7], exNmt }; state.Begin( AsciiId<'R','1','2'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void NST_FASTCALL Sl1632::UpdatePrg(uint address,uint bank) { if (exMode & 0x2U) Mmc3::UpdatePrg( address, bank ); else prg.SwapBanks( exPrg[0], exPrg[1], ~1U, ~0U ); } void NST_FASTCALL Sl1632::UpdateChr(uint address,uint bank) const { if (exMode & 0x2U) { static const byte modes[4] = {5,5,3,1}; bank |= uint(exMode) << modes[address >> 11 ^ (regs.ctrl0 >> 6 & 0x2)] & 0x100; } else { bank = exChr[address >> 10]; } chr.SwapBank( address, bank ); } NES_POKE_AD(Sl1632,8000) { if ((address & 0xA131) == 0xA131 && exMode != data) { exMode = data; Mmc3::UpdatePrg(); Mmc3::UpdateChr(); if (!(exMode & 0x2U)) SetMirroringHV( exNmt ); } if (exMode & 0x2U) { switch (address & 0xE001) { case 0x8000: Mmc3::NES_DO_POKE( 8000, address, data ); break; case 0x8001: Mmc3::NES_DO_POKE( 8001, address, data ); break; case 0xA000: SetMirroringVH( exNmt ); break; case 0xA001: Mmc3::NES_DO_POKE( A001, address, data ); break; case 0xC000: Mmc3::NES_DO_POKE( C000, address, data ); break; case 0xC001: Mmc3::NES_DO_POKE( C001, address, data ); break; case 0xE000: Mmc3::NES_DO_POKE( E000, address, data ); break; case 0xE001: Mmc3::NES_DO_POKE( E001, address, data ); break; } } else if (address >= 0xB000 && address <= 0xE003) { const uint offset = address << 2 & 0x4; address = ((((address & 0x2) | address >> 10) >> 1) + 2) & 0x7; exChr[address] = (exChr[address] & 0xF0U >> offset) | ((data & 0x0F) << offset); Mmc3::UpdateChr(); } else switch (address & 0xF003) { case 0x8000: if (exPrg[0] != data) { exPrg[0] = data; Mmc3::UpdatePrg(); } break; case 0x9000: if (exNmt != data) { exNmt = data; SetMirroringHV( exNmt ); } break; case 0xA000: if (exPrg[1] != data) { exPrg[1] = data; Mmc3::UpdatePrg(); } break; } } } } } } nestopia-1.51.1/source/core/board/NstBoardRexSoftSl1632.hpp000066400000000000000000000033221411157722000233130ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_REXSOFT_SL1632_H #define NST_BOARD_REXSOFT_SL1632_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace RexSoft { class Sl1632 : public Mmc3 { public: explicit Sl1632(const Context& c) : Mmc3(c) {} private: void SubReset(bool); void SubLoad(State::Loader&,dword); void SubSave(State::Saver&) const; void NST_FASTCALL UpdatePrg(uint,uint); void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_POKE( 8000 ); byte exMode; byte exPrg[2]; byte exChr[8]; byte exNmt; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardRumbleStation.cpp000066400000000000000000000040701411157722000236720ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardRumbleStation.hpp" namespace Nes { namespace Core { namespace Boards { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void RumbleStation::SubReset(bool) { Map( 0x6000U, 0x7FFFU, &RumbleStation::Poke_6000 ); Map( 0x8000U, 0xFFFFU, &RumbleStation::Poke_8000 ); prg.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(RumbleStation,6000) { ppu.Update(); prg.SwapBank( (prg.GetBank() & 0x1) | (data << 1 & 0x1E) ); chr.SwapBank( (chr.GetBank() & 0x7) | (data >> 1 & 0x78) ); } NES_POKE_AD(RumbleStation,8000) { ppu.Update(); data = GetBusData(address,data); prg.SwapBank( (data >> 0 & 0x1) | (prg.GetBank() & 0x1E) ); chr.SwapBank( (data >> 4 & 0x7) | (chr.GetBank() & 0x78) ); } } } } nestopia-1.51.1/source/core/board/NstBoardRumbleStation.hpp000066400000000000000000000027111411157722000236770ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_RUMBLESTATION_H #define NST_BOARD_RUMBLESTATION_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { class RumbleStation : public Board { public: explicit RumbleStation(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 6000 ); NES_DECL_POKE( 8000 ); }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardSachen.hpp000066400000000000000000000031501411157722000223060ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SACHEN_H #define NST_BOARD_SACHEN_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardSachenS8259.hpp" #include "NstBoardSachenTca01.hpp" #include "NstBoardSachenTcu.hpp" #include "NstBoardSachenSa0036.hpp" #include "NstBoardSachenSa0037.hpp" #include "NstBoardSachenSa72007.hpp" #include "NstBoardSachenSa72008.hpp" #include "NstBoardSachen74x374.hpp" #include "NstBoardSachenStreetHeroes.hpp" namespace Nes { namespace Core { namespace Boards { namespace Sachen { typedef Ave::Nina06 Sa0161m; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardSachen74x374.cpp000066400000000000000000000153311411157722000231060ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardSachen74x374.hpp" #include "../NstDipSwitches.hpp" #include "../NstCrc32.hpp" namespace Nes { namespace Core { namespace Boards { namespace Sachen { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif class S74x374b::CartSwitches : public DipSwitches { enum { CA = 0x858130BF }; uint copyright; CartSwitches() : copyright(1) {} public: static CartSwitches* Create(const Context& c) { return Crc32::Compute(c.prg.Mem(),c.prg.Size()) == CA ? new CartSwitches : NULL; } void SetCopyright(uint value) { copyright = value; } uint GetCopyright() const { return copyright; } private: uint GetValue(uint) const { return copyright ^ 1; } void SetValue(uint,uint value) { copyright = value ^ 1; } uint NumDips() const { return 1; } uint NumValues(uint) const { return 2; } cstring GetDipName(uint) const { return "Copyright"; } cstring GetValueName(uint,uint i) const { return i ? "Sachen & Hacker" : "Sachen"; } }; S74x374b::S74x374b(const Context& c) : S74x374a(c), cartSwitches(CartSwitches::Create(c)) {} S74x374b::~S74x374b() { delete cartSwitches; } S74x374b::Device S74x374b::QueryDevice(DeviceType type) { if (type == DEVICE_DIP_SWITCHES) return cartSwitches; else return Board::QueryDevice( type ); } void S74x374a::SubReset(const bool hard) { for (uint i=0x4100; i < 0x6000; i += 0x200) { for (uint j=0x00; j < 0x100; j += 0x2) { Map( i + j + 0x0, &S74x374a::Poke_4100 ); Map( i + j + 0x1, &S74x374a::Poke_4101 ); } } if (hard) { ctrl = 0; prg.SwapBank(0); } } void S74x374b::SubReset(const bool hard) { S74x374a::SubReset( hard ); for (uint i=0x4100; i < 0x6000; i += 0x200) { for (uint j=0x00; j < 0x100; j += 0x2) { Map( i + j + 0x0, &S74x374b::Peek_4100 ); Map( i + j + 0x1, &S74x374b::Peek_4100, &S74x374b::Poke_4101 ); } } } void S74x374a::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'S','7','A'>::V) ); if (baseChunk == AsciiId<'S','7','A'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) ctrl = state.Read8(); state.End(); } } } void S74x374b::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'S','7','B'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'D','I','P'>::V) { NST_VERIFY( cartSwitches ); if (cartSwitches) cartSwitches->SetCopyright( state.Read8() & 0x1 ); } state.End(); } } else { S74x374a::SubLoad( state, baseChunk ); } } void S74x374a::SubSave(State::Saver& state) const { state.Begin( AsciiId<'S','7','A'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( ctrl ).End().End(); } void S74x374b::SubSave(State::Saver& state) const { S74x374a::SubSave( state ); if (cartSwitches) state.Begin( AsciiId<'S','7','B'>::V ).Begin( AsciiId<'D','I','P'>::V ).Write8( cartSwitches->GetCopyright() ? 0x1 : 0x0 ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void S74x374a::UpdatePrg(uint bank) { prg.SwapBank( bank ); } void S74x374a::UpdateChr(uint bank) const { ppu.Update(); chr.SwapBank( bank ); } void S74x374a::UpdateNmt(uint mode) const { NST_ASSERT( mode <= 0x3 ); static const byte lut[4][4] = { {0,1,0,1}, {0,0,1,1}, {0,1,1,1}, {0,0,0,0} }; ppu.SetMirroring( lut[mode] ); } NES_PEEK(S74x374b,4100) { return (~(ctrl & 0x7) & 0x3F) ^ (cartSwitches ? cartSwitches->GetCopyright() : 0x1); } NES_POKE_D(S74x374a,4100) { ctrl = data; } NES_POKE_D(S74x374a,4101) { switch (ctrl & 0x7) { case 0x0: UpdatePrg( 0x0 ); UpdateChr( 0x3 ); break; case 0x2: UpdateChr( (chr.GetBank() & ~0x8U) | (data << 3 & 0x8) ); break; case 0x4: UpdateChr( (chr.GetBank() & ~0x1U) | (data << 0 & 0x1) ); break; case 0x5: UpdatePrg( data & 0x1 ); break; case 0x6: UpdateChr( (chr.GetBank() & ~0x6U) | (data << 1 & 0x6) ); break; case 0x7: UpdateNmt( data & 0x1 ); break; } } NES_POKE_D(S74x374b,4101) { switch (ctrl & 0x7) { case 0x2: UpdatePrg( data & 0x1 ); UpdateChr( (chr.GetBank() & ~0x8U) | (data << 3 & 0x8) ); break; case 0x4: UpdateChr( (chr.GetBank() & ~0x4U) | (data << 2 & 0x4) ); break; case 0x5: UpdatePrg( data & 0x7 ); break; case 0x6: UpdateChr( (chr.GetBank() & ~0x3U) | (data << 0 & 0x3) ); break; case 0x7: UpdateNmt( data >> 1 & 0x3 ); break; } } } } } } nestopia-1.51.1/source/core/board/NstBoardSachen74x374.hpp000066400000000000000000000041471411157722000231160ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SACHEN_74X374_H #define NST_BOARD_SACHEN_74X374_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Sachen { class S74x374a : public Board { public: explicit S74x374a(const Context& c) : Board(c) {} protected: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void UpdatePrg(uint); void UpdateChr(uint) const; void UpdateNmt(uint) const; uint ctrl; private: NES_DECL_POKE( 4100 ); NES_DECL_POKE( 4101 ); }; class S74x374b : public S74x374a { public: S74x374b(const Context&); private: ~S74x374b(); class CartSwitches; void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); Device QueryDevice(DeviceType); NES_DECL_PEEK( 4100 ); NES_DECL_POKE( 4101 ); CartSwitches* const cartSwitches; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardSachenS8259.cpp000066400000000000000000000100731411157722000227560ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardSachenS8259.hpp" namespace Nes { namespace Core { namespace Boards { namespace Sachen { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void S8259::SubReset(const bool hard) { for (uint i=0x4100; i < 0x8000; i += 0x200) { for (uint j=0; j < 0x100; j += 0x2) { Map( i + j + 0x0, &S8259::Poke_4100 ); Map( i + j + 0x1, &S8259::Poke_4101 ); } } if (hard) { ctrl = 0; for (uint i=0; i < 8; ++i) regs[i] = 0; prg.SwapBank(0); } if (board == Type::SACHEN_8259D && !chr.Source().Writable()) chr.SwapBank( ~0U ); } void S8259::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'S','8','2'>::V) ); if (baseChunk == AsciiId<'S','8','2'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { ctrl = state.Read8(); state.Read( regs ); } state.End(); } } } void S8259::SubSave(State::Saver& state) const { state.Begin( AsciiId<'S','8','2'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( ctrl ).Write( regs ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(S8259,4100) { ctrl = data; } NES_POKE_D(S8259,4101) { regs[ctrl & 0x7] = data; switch (ctrl & 0x7) { case 0x5: prg.SwapBank( data ); break; case 0x7: { static const byte lut[4][4] = { {0,1,0,1}, {0,0,1,1}, {0,1,1,1}, {0,0,0,0} }; ppu.SetMirroring( lut[(data & 0x1) ? 0 : (data >> 1 & 0x3)] ); } default: if (!chr.Source().Writable()) { ppu.Update(); if (board == Type::SACHEN_8259D) { chr.SwapBanks ( (regs[0] & 0x07U), (regs[1] & 0x07U) | (regs[4] << 4 & 0x10U), (regs[2] & 0x07U) | (regs[4] << 3 & 0x10U), (regs[3] & 0x07U) | (regs[4] << 2 & 0x10U) | (regs[6] << 3 & 0x08U) ); } else { const uint h = regs[4] << 3 & 0x38U; const uint s = (board == Type::SACHEN_8259A ? 1 : board == Type::SACHEN_8259C ? 2 : 0); chr.SwapBanks ( ((regs[(regs[7] & 0x1U) ? 0 : 0] & 0x07U) | h) << s, ((regs[(regs[7] & 0x1U) ? 0 : 1] & 0x07U) | h) << s | (board != Type::SACHEN_8259B ? 1 : 0), ((regs[(regs[7] & 0x1U) ? 0 : 2] & 0x07U) | h) << s | (board == Type::SACHEN_8259C ? 2 : 0), ((regs[(regs[7] & 0x1U) ? 0 : 3] & 0x07U) | h) << s | (board == Type::SACHEN_8259A ? 1 : board == Type::SACHEN_8259C ? 3 : 0) ); } } break; } } } } } } nestopia-1.51.1/source/core/board/NstBoardSachenS8259.hpp000066400000000000000000000031341411157722000227630ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SACHEN_S8259_H #define NST_BOARD_SACHEN_S8259_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Sachen { class S8259 : public Board { public: explicit S8259(const Context& c) : Board(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); NES_DECL_POKE( 4100 ); NES_DECL_POKE( 4101 ); uint ctrl; byte regs[8]; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardSachenSa0036.cpp000066400000000000000000000030511411157722000230760ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardSachenSa0036.hpp" namespace Nes { namespace Core { namespace Boards { namespace Sachen { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Sa0036::SubReset(bool) { Map( 0x8000U, 0xFFFFU, &Sa0036::Poke_8000 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Sa0036,8000) { ppu.Update(); chr.SwapBank( data >> 7 ); } } } } } nestopia-1.51.1/source/core/board/NstBoardSachenSa0036.hpp000066400000000000000000000027111411157722000231050ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SACHEN_SA0036_H #define NST_BOARD_SACHEN_SA0036_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Sachen { class Sa0036 : public Board { public: explicit Sa0036(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardSachenSa0037.cpp000066400000000000000000000033041411157722000231000ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardSachenSa0037.hpp" namespace Nes { namespace Core { namespace Boards { namespace Sachen { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Sa0037::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &Sa0037::Poke_8000 ); if (hard) prg.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(Sa0037,8000) { ppu.Update(); data = GetBusData(address,data); prg.SwapBank( data >> 3 ); chr.SwapBank( data ); } } } } } nestopia-1.51.1/source/core/board/NstBoardSachenSa0037.hpp000066400000000000000000000027111411157722000231060ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SACHEN_SA0037_H #define NST_BOARD_SACHEN_SA0037_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Sachen { class Sa0037 : public Board { public: explicit Sa0037(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardSachenSa72007.cpp000066400000000000000000000031341411157722000231670ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardSachenSa72007.hpp" namespace Nes { namespace Core { namespace Boards { namespace Sachen { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Sa72007::SubReset(bool) { for (uint i=0x4100; i < 0x6000; i += 0x200) Map( i, i + 0x100, &Sa72007::Poke_4100 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Sa72007,4100) { ppu.Update(); chr.SwapBank( data >> 7 ); } } } } } nestopia-1.51.1/source/core/board/NstBoardSachenSa72007.hpp000066400000000000000000000027151411157722000232000ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SACHEN_SA72007_H #define NST_BOARD_SACHEN_SA72007_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Sachen { class Sa72007 : public Board { public: explicit Sa72007(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 4100 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardSachenSa72008.cpp000066400000000000000000000031321411157722000231660ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardSachenSa72008.hpp" namespace Nes { namespace Core { namespace Boards { namespace Sachen { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Sa72008::SubReset(bool) { Map( 0x4100U, 0x6000U, &Sa72008::Poke_4100 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Sa72008,4100) { ppu.Update(); prg.SwapBank( data >> 2 ); chr.SwapBank( data ); } } } } } nestopia-1.51.1/source/core/board/NstBoardSachenSa72008.hpp000066400000000000000000000027151411157722000232010ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SACHEN_SA72008_H #define NST_BOARD_SACHEN_SA72008_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Sachen { class Sa72008 : public Board { public: explicit Sa72008(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 4100 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardSachenStreetHeroes.cpp000066400000000000000000000102271411157722000246410ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "../NstDipSwitches.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardSachenStreetHeroes.hpp" namespace Nes { namespace Core { namespace Boards { namespace Sachen { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif StreetHeroes::CartSwitches::CartSwitches() : region(0x00) {} inline void StreetHeroes::CartSwitches::SetRegion(uint value) { region = value ? 0xFF : 0x00; } inline uint StreetHeroes::CartSwitches::GetRegion() const { return region; } uint StreetHeroes::CartSwitches::GetValue(uint) const { return region ? 1 : 0; } void StreetHeroes::CartSwitches::SetValue(uint,uint value) { region = value ? 0xFF : 0x00; } uint StreetHeroes::CartSwitches::NumDips() const { return 1; } uint StreetHeroes::CartSwitches::NumValues(uint) const { return 2; } cstring StreetHeroes::CartSwitches::GetDipName(uint) const { return "Region"; } cstring StreetHeroes::CartSwitches::GetValueName(uint,uint i) const { return i ? "Asia" : "US"; } StreetHeroes::Device StreetHeroes::QueryDevice(DeviceType type) { if (type == DEVICE_DIP_SWITCHES) return &cartSwitches; else return Board::QueryDevice( type ); } void StreetHeroes::SubReset(const bool hard) { if (hard) exReg = 0; Mmc3::SubReset( hard ); Map( 0x4100U, &StreetHeroes::Peek_4100, &StreetHeroes::Poke_4100 ); } void StreetHeroes::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'S','S','H'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<2> data( state ); exReg = data[1]; cartSwitches.SetRegion( data[0] & 0x1 ); } state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void StreetHeroes::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); const byte data[2] = { cartSwitches.GetRegion() ? 0x1 : 0x0, exReg }; state.Begin( AsciiId<'S','S','H'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void NST_FASTCALL StreetHeroes::UpdateChr(uint address,uint bank) const { if (!(exReg & 0x40)) { chr.SwapBank ( address, (exReg << ( address < 0x0800 ? 5 : address < 0x1000 ? 6 : address < 0x1800 ? 8 : 7 ) & 0x100) | bank ); } } NES_POKE_D(StreetHeroes,4100) { if (exReg != data) { exReg = data; if (exReg & 0x40) chr.Source(1).SwapBank(0); else Mmc3::UpdateChr(); } } NES_PEEK(StreetHeroes,4100) { return cartSwitches.GetRegion(); } } } } } nestopia-1.51.1/source/core/board/NstBoardSachenStreetHeroes.hpp000066400000000000000000000042251411157722000246470ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SACHEN_STREETHEROES_H #define NST_BOARD_SACHEN_STREETHEROES_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Sachen { class StreetHeroes : public Mmc3 { public: explicit StreetHeroes(const Context& c) : Mmc3(c) {} private: class CartSwitches : public DipSwitches { uint region; public: CartSwitches(); inline void SetRegion(uint); inline uint GetRegion() const; private: uint GetValue(uint) const; void SetValue(uint,uint); uint NumDips() const; uint NumValues(uint) const; cstring GetDipName(uint) const; cstring GetValueName(uint,uint) const; }; void SubReset(bool); void SubLoad(State::Loader&,dword); void SubSave(State::Saver&) const; Device QueryDevice(DeviceType); void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_POKE( 4100 ); NES_DECL_PEEK( 4100 ); uint exReg; CartSwitches cartSwitches; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardSachenTca01.cpp000066400000000000000000000041301411157722000230710ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardSachenTca01.hpp" namespace Nes { namespace Core { namespace Boards { namespace Sachen { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif /*void Tca01::SubReset(bool) { for (uint i=0x4100; i < 0x6000; i += 0x200) Map( i + 0x00, i + 0xFF, &Tca01::Peek_4100 ); }*/ // shalma's fix for Dancing Blocks (Sachen) void Tca01::SubReset(bool hard) { for (uint i=0x4100; i < 0x6000; i += 0x200) Map( i + 0x00, i + 0xFF, &Tca01::Peek_4100 ); if (hard) { //FCEUmm (cah4e3) - random boot fix for (int lcv = 0; lcv < 0x800; lcv++) { cpu.Poke(lcv, (lcv & 4) ? 0x7f : 0x00); } // Nestopia default cpu.Poke(0x08, 0xF7); cpu.Poke(0x09, 0xEF); cpu.Poke(0x0a, 0xDF); cpu.Poke(0x0b, 0xBF); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(Tca01,4100) { return (~address & 0x3F) | 0x40; } } } } } nestopia-1.51.1/source/core/board/NstBoardSachenTca01.hpp000066400000000000000000000027051411157722000231040ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SACHEN_TCA01_H #define NST_BOARD_SACHEN_TCA01_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Sachen { class Tca01 : public Board { public: explicit Tca01(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_PEEK( 4100 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardSachenTcu.cpp000066400000000000000000000055361411157722000227670ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardSachenTcu.hpp" namespace Nes { namespace Core { namespace Boards { namespace Sachen { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Tcu01::SubReset(const bool hard) { for (dword i=0x4100; i < 0x10000; i += 0x200) { for (uint j=0x2; j < 0x100; j += 0x4) Map( i + j, &Tcu01::Poke_4102 ); } if (hard) prg.SwapBank(0); } void Tcu02::SubReset(const bool hard) { for (uint i=0x4100; i < 0x6000; i += 0x200) { for (uint j=0x0; j < 0x100; j += 0x4) { Map( i + j + 0x0, &Tcu02::Peek_4100 ); Map( i + j + 0x2, &Tcu02::Poke_4102 ); } } if (hard) reg = 0; } void Tcu02::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'S','0','2'>::V) ); if (baseChunk == AsciiId<'S','0','2'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) reg = state.Read8(); state.End(); } } } void Tcu02::SubSave(State::Saver& state) const { state.Begin( AsciiId<'S','0','2'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( reg ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK(Tcu02,4100) { return reg | 0x40; } NES_POKE_D(Tcu01,4102) { ppu.Update(); prg.SwapBank( (data >> 6 & 0x2) | (data >> 2 & 0x1) ); chr.SwapBank( data >> 3 ); } NES_POKE_D(Tcu02,4102) { ppu.Update(); reg = (data & 0x30) | ((data+3) & 0x0F); chr.SwapBank( reg ); } } } } } nestopia-1.51.1/source/core/board/NstBoardSachenTcu.hpp000066400000000000000000000034121411157722000227630ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SACHEN_TCU_H #define NST_BOARD_SACHEN_TCU_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Sachen { class Tcu01 : public Board { public: explicit Tcu01(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 4102 ); }; class Tcu02 : public Board { public: explicit Tcu02(const Context& c) : Board(c) {} private: void SubReset(bool); void SubLoad(State::Loader&,dword); void SubSave(State::Saver&) const; NES_DECL_PEEK( 4100 ); NES_DECL_POKE( 4102 ); uint reg; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardSomeriTeam.hpp000066400000000000000000000022661411157722000231610ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SOMERITEAM_H #define NST_BOARD_SOMERITEAM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardSomeriTeamSl12.hpp" #endif nestopia-1.51.1/source/core/board/NstBoardSomeriTeamSl12.cpp000066400000000000000000000277731411157722000236300ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardSomeriTeam.hpp" namespace Nes { namespace Core { namespace Boards { namespace SomeriTeam { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Sl12::Sl12(const Context& c) : Board (c), irq (*c.cpu,*c.ppu,false) {} void Sl12::SubReset(const bool hard) { irq.Reset( hard ); if (hard) { mode = 0; vrc2.prg[0] = 0x0; vrc2.prg[1] = 0x1; vrc2.nmt = 0; for (uint i=0; i < 8; ++i) vrc2.chr[i] = i; mmc3.ctrl = 0; mmc3.nmt = 0; mmc3.banks[0] = 0x0; mmc3.banks[1] = 0x1; mmc3.banks[2] = 0x4; mmc3.banks[3] = 0x5; mmc3.banks[4] = 0x6; mmc3.banks[5] = 0x7; mmc3.banks[6] = 0x3C; mmc3.banks[7] = 0x3D; mmc3.banks[8] = 0xFE; mmc3.banks[9] = 0xFF; mmc1.buffer = 0; mmc1.shifter = 0; mmc1.regs[0] = 0x4U|0x8U; mmc1.regs[1] = 0; mmc1.regs[2] = 0; mmc1.regs[3] = 0; } for (uint i=0x4100; i < 0x6000; i += 0x200) Map( i + 0x00, i + 0xFF, &Sl12::Poke_4100 ); Map( 0x8000U, 0x8FFFU, &Sl12::Poke_8000 ); Map( 0x9000U, 0x9FFFU, &Sl12::Poke_9000 ); Map( 0xA000U, 0xAFFFU, &Sl12::Poke_A000 ); Map( 0xB000U, 0xBFFFU, &Sl12::Poke_B000 ); Map( 0xC000U, 0xCFFFU, &Sl12::Poke_C000 ); Map( 0xD000U, 0xDFFFU, &Sl12::Poke_D000 ); Map( 0xE000U, 0xEFFFU, &Sl12::Poke_E000 ); Map( 0xF000U, 0xFFFFU, &Sl12::Poke_F000 ); UpdatePrg(); UpdateNmt(); UpdateChr(); } void Sl12::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'S','1','2'>::V) ); if (baseChunk == AsciiId<'S','1','2'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: mode = state.Read8(); break; case AsciiId<'V','R','2'>::V: state.Read( vrc2.chr ); state.Read( vrc2.prg ); vrc2.nmt = state.Read8(); break; case AsciiId<'M','M','3'>::V: state.Read( mmc3.banks ); mmc3.ctrl = state.Read8(); mmc3.nmt = state.Read8(); break; case AsciiId<'M','M','1'>::V: state.Read( mmc1.regs ); mmc1.buffer = state.Read8(); mmc1.shifter = state.Read8(); break; case AsciiId<'I','R','Q'>::V: irq.unit.LoadState( state ); break; } state.End(); } } UpdatePrg(); UpdateNmt(); UpdateChr(); } void Sl12::SubSave(State::Saver& state) const { state.Begin( AsciiId<'S','1','2'>::V ); state.Begin( AsciiId<'R','E','G'>::V ).Write8( mode ).End(); state.Begin( AsciiId<'V','R','2'>::V ).Write( vrc2.chr ).Write( vrc2.prg ).Write8( vrc2.nmt ).End(); state.Begin( AsciiId<'M','M','3'>::V ).Write( mmc3.banks ).Write8( mmc3.ctrl ).Write8( mmc3.nmt ).End(); state.Begin( AsciiId<'M','M','1'>::V ).Write( mmc1.regs ).Write8( mmc1.buffer ).Write8( mmc1.shifter ).End(); irq.unit.SaveState( state, AsciiId<'I','R','Q'>::V ); state.End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Sl12::UpdatePrg() { switch (mode & 0x3) { case 0x0: prg.SwapBanks( vrc2.prg[0], vrc2.prg[1], 0x1E, 0x1F ); break; case 0x1: { const uint i = mmc3.ctrl >> 5 & 0x2U; prg.SwapBanks( mmc3.banks[6+i], mmc3.banks[6+1], mmc3.banks[6+(i^2)], mmc3.banks[6+3] ); break; } case 0x2: { const uint bank = mmc1.regs[3] & 0xFU; if (mmc1.regs[0] & 0x8U) prg.SwapBanks( (mmc1.regs[0] & 0x4U) ? bank : 0x0, (mmc1.regs[0] & 0x4U) ? 0xF : bank ); else prg.SwapBank( bank >> 1 ); break; } } } void Sl12::UpdateChr() const { const uint base = (mode & 0x4) << 6; switch (mode & 0x3) { case 0x0: chr.SwapBanks( base|vrc2.chr[0], base|vrc2.chr[1], base|vrc2.chr[2], base|vrc2.chr[3], base|vrc2.chr[4], base|vrc2.chr[5], base|vrc2.chr[6], base|vrc2.chr[7] ); break; case 0x1: { const uint swap = (mmc3.ctrl & 0x80U) << 5; chr.SwapBanks( 0x0000 ^ swap, base >> 1 | mmc3.banks[0], base >> 1 | mmc3.banks[1] ); chr.SwapBanks( 0x1000 ^ swap, base|mmc3.banks[2], base|mmc3.banks[3], base|mmc3.banks[4], base|mmc3.banks[5] ); break; } case 0x2: chr.SwapBanks( (mmc1.regs[0] & 0x10U) ? mmc1.regs[1] : mmc1.regs[1] & 0x1EU, (mmc1.regs[0] & 0x10U) ? mmc1.regs[2] : mmc1.regs[1] | 0x01U ); break; } } void Sl12::UpdateNmt() const { Ppu::NmtMirroring nmtCtrl; switch (mode & 0x3) { case 0x0: nmtCtrl = (vrc2.nmt & 0x1U) ? Ppu::NMT_H : Ppu::NMT_V; break; case 0x1: nmtCtrl = (mmc3.nmt & 0x1U) ? Ppu::NMT_H : Ppu::NMT_V; break; case 0x2: switch (mmc1.regs[0] & 0x3U) { case 0x0: nmtCtrl = Ppu::NMT_0; break; case 0x1: nmtCtrl = Ppu::NMT_1; break; case 0x2: nmtCtrl = Ppu::NMT_V; break; default: nmtCtrl = Ppu::NMT_H; break; } break; default: return; } ppu.SetMirroring( nmtCtrl ); } void Sl12::Poke_Vrc2_8000(uint address,uint data) { NST_ASSERT( (mode & 0x3) == 0 ); data &= 0x1F; address = address >> 13 & 0x1; if (vrc2.prg[address] != data) { vrc2.prg[address] = data; UpdatePrg(); } } void Sl12::Poke_Vrc2_9000(uint,uint data) { NST_ASSERT( (mode & 0x3) == 0 ); data &= 0x1; if (vrc2.nmt != data) { vrc2.nmt = data; UpdateNmt(); } } void Sl12::Poke_Vrc2_B000(uint address,uint data) { NST_ASSERT( (mode & 0x3) == 0 ); data = (data & 0xF) << (address << 1 & 0x4); address = ((address - 0xB000) >> 11 & 0x6) | (address & 0x1); if (vrc2.chr[address] != data) { vrc2.chr[address] = data; ppu.Update(); UpdateChr(); } } void Sl12::Poke_Mmc3_8000(uint address,uint data) { NST_ASSERT( (mode & 0x3) == 1 ); if (address & 0x1) { address = mmc3.ctrl & 0x7U; if (address < 2) data >>= 1; if (mmc3.banks[address] != data) { mmc3.banks[address] = data; if (address < 6) { ppu.Update(); UpdateChr(); } else { UpdatePrg(); } } } else { address = mmc3.ctrl ^ data; mmc3.ctrl = data; if (address & 0x40) UpdatePrg(); if (address & (0x80U|0x07U)) { ppu.Update(); UpdateChr(); } } } void Sl12::Poke_Mmc3_A000(uint address,uint data) { NST_ASSERT( (mode & 0x3) == 1 ); if (!(address & 0x1)) { if (mmc3.nmt != data) { mmc3.nmt = data; UpdateNmt(); } } } void Sl12::Poke_Mmc3_C000(uint address,uint data) { NST_ASSERT( (mode & 0x3) == 1 ); irq.Update(); if (address & 0x1) irq.unit.Reload(); else irq.unit.SetLatch( data ); } void Sl12::Poke_Mmc3_E000(uint address,uint) { NST_ASSERT( (mode & 0x3) == 1 ); irq.Update(); if (address & 0x1) irq.unit.Enable(); else irq.unit.Disable( cpu ); } void Sl12::Poke_Mmc1_8000(uint address,uint data) { NST_ASSERT( (mode & 0x3) == 2 ); if (!(data & 0x80)) { mmc1.buffer |= (data & 0x1) << mmc1.shifter++; if (mmc1.shifter != 5) return; mmc1.shifter = 0; data = mmc1.buffer; mmc1.buffer = 0; address = address >> 13 & 0x3; if (mmc1.regs[address] != data) { mmc1.regs[address] = data; UpdatePrg(); UpdateNmt(); UpdateChr(); } } else { mmc1.buffer = 0; mmc1.shifter = 0; if ((mmc1.regs[0] & (0x4U|0x8U)) != (0x4U|0x8U)) { mmc1.regs[0] |= (0x4U|0x8U); UpdatePrg(); UpdateNmt(); UpdateChr(); } } } NES_POKE_D(Sl12,4100) { if (mode != data) { mode = data; if ((data & 0x3) != 1) irq.unit.Disable( cpu ); UpdatePrg(); UpdateNmt(); UpdateChr(); } } NES_POKE_AD(Sl12,8000) { switch (mode & 0x3) { case 0x0: Poke_Vrc2_8000( address, data ); break; case 0x1: Poke_Mmc3_8000( address, data ); break; case 0x2: Poke_Mmc1_8000( address, data ); break; } } NES_POKE_AD(Sl12,9000) { switch (mode & 0x3) { case 0x0: Poke_Vrc2_9000( address, data ); break; case 0x1: Poke_Mmc3_8000( address, data ); break; case 0x2: Poke_Mmc1_8000( address, data ); break; } } NES_POKE_AD(Sl12,A000) { switch (mode & 0x3) { case 0x0: Poke_Vrc2_8000( address, data ); break; case 0x1: Poke_Mmc3_A000( address, data ); break; case 0x2: Poke_Mmc1_8000( address, data ); break; } } NES_POKE_AD(Sl12,B000) { switch (mode & 0x3) { case 0x0: Poke_Vrc2_B000( address, data ); break; case 0x1: Poke_Mmc3_A000( address, data ); break; case 0x2: Poke_Mmc1_8000( address, data ); break; } } NES_POKE_AD(Sl12,C000) { switch (mode & 0x3) { case 0x0: Poke_Vrc2_B000( address, data ); break; case 0x1: Poke_Mmc3_C000( address, data ); break; case 0x2: Poke_Mmc1_8000( address, data ); break; } } NES_POKE_AD(Sl12,D000) { switch (mode & 0x3) { case 0x0: Poke_Vrc2_B000( address, data ); break; case 0x1: Poke_Mmc3_C000( address, data ); break; case 0x2: Poke_Mmc1_8000( address, data ); break; } } NES_POKE_AD(Sl12,E000) { switch (mode & 0x3) { case 0x0: Poke_Vrc2_B000( address, data ); break; case 0x1: Poke_Mmc3_E000( address, data ); break; case 0x2: Poke_Mmc1_8000( address, data ); break; } } NES_POKE_AD(Sl12,F000) { switch (mode & 0x3) { case 0x0: break; case 0x1: Poke_Mmc3_E000( address, data ); break; case 0x2: Poke_Mmc1_8000( address, data ); break; } } void Sl12::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardSomeriTeamSl12.hpp000066400000000000000000000050521411157722000236170ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SOMERITEAM_SL12_H #define NST_BOARD_SOMERITEAM_SL12_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace SomeriTeam { class Sl12 : public Board { public: explicit Sl12(const Context&); private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Sync(Event,Input::Controllers*); void UpdatePrg(); void UpdateChr() const; void UpdateNmt() const; void Poke_Mmc1_8000(uint,uint); void Poke_Vrc2_8000(uint,uint); void Poke_Vrc2_9000(uint,uint); void Poke_Vrc2_B000(uint,uint); void Poke_Mmc3_8000(uint,uint); void Poke_Mmc3_A000(uint,uint); void Poke_Mmc3_C000(uint,uint); void Poke_Mmc3_E000(uint,uint); NES_DECL_POKE( 4100 ); NES_DECL_POKE( 8000 ); NES_DECL_POKE( 9000 ); NES_DECL_POKE( A000 ); NES_DECL_POKE( B000 ); NES_DECL_POKE( C000 ); NES_DECL_POKE( D000 ); NES_DECL_POKE( E000 ); NES_DECL_POKE( F000 ); uint mode; struct { byte chr[8]; byte prg[2]; byte nmt; byte padding; } vrc2; struct { byte banks[10]; byte ctrl; byte nmt; } mmc3; struct { byte regs[4]; byte buffer; byte shifter; byte padding[2]; } mmc1; Mmc3::Irq<> irq; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardSubor.cpp000066400000000000000000000060221411157722000221730ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardSubor.hpp" namespace Nes { namespace Core { namespace Boards { namespace Subor { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Type0::SubReset(bool) { Map( 0x8000U, 0xFFFFU, &Type0::Poke_8000 ); for (uint i=0; i < 4; ++i) regs[i] = 0; NES_DO_POKE(8000,0x8000,0x00); } void StudyNGame::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, PRG_SWAP_32K ); if (hard) prg.SwapBank(0); } void Type0::SubSave(State::Saver& state) const { state.Begin( AsciiId<'S','B','R'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( regs ).End().End(); } void Type0::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'S','B','R'>::V) ); if (baseChunk == AsciiId<'S','B','R'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) state.Read( regs ); state.End(); } } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif uint Type0::GetMode() const { return 0; } uint Type1::GetMode() const { return 1; } NES_POKE_AD(Type0,8000) { regs[address >> 13 & 0x3] = data; uint banks[2] = { (uint(regs[0]) ^ regs[1]) << 1 & 0x20, (uint(regs[2]) ^ regs[3]) << 0 & 0x1F }; const uint mode = GetMode(); if (regs[1] & 0x8U) { banks[0] += banks[1] & 0xFE; banks[1] = banks[0]; banks[0] += mode ^ 1; banks[1] += mode ^ 0; } else if (regs[1] & 0x4U) { banks[1] = banks[0] + banks[1]; banks[0] = 0x1F; } else { banks[0] = banks[0] + banks[1]; banks[1] = mode ? 0x07 : 0x20; } prg.SwapBanks( banks[0], banks[1] ); } } } } } nestopia-1.51.1/source/core/board/NstBoardSubor.hpp000066400000000000000000000036401411157722000222030ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SUBOR_H #define NST_BOARD_SUBOR_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Subor { class Type0 : public Board { public: explicit Type0(const Context& c) : Board(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); virtual uint GetMode() const; NES_DECL_POKE( 8000 ); byte regs[4]; }; class Type1 : public Type0 { public: explicit Type1(const Context& c) : Type0(c) {} private: uint GetMode() const; }; class StudyNGame : public Board { public: explicit StudyNGame(const Context& c) : Board(c) {} private: void SubReset(bool); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardSunsoft.hpp000066400000000000000000000025251411157722000225530ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SUNSOFT_H #define NST_BOARD_SUNSOFT_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardSunsoft1.hpp" #include "NstBoardSunsoft2.hpp" #include "NstBoardSunsoft3.hpp" #include "NstBoardSunsoftDcs.hpp" #include "NstBoardSunsoftFme7.hpp" #include "NstBoardSunsoft5b.hpp" #endif nestopia-1.51.1/source/core/board/NstBoardSunsoft1.cpp000066400000000000000000000030461411157722000226260ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardSunsoft1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Sunsoft { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void S1::SubReset(bool) { Map( 0x6000U, 0x7FFFU, &S1::Poke_6000 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(S1,6000) { ppu.Update(); chr.SwapBanks( data >> 0, data >> 4 ); } } } } } nestopia-1.51.1/source/core/board/NstBoardSunsoft1.hpp000066400000000000000000000027101411157722000226300ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SUNSOFT_SUNSOFT1_H #define NST_BOARD_SUNSOFT_SUNSOFT1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Sunsoft { class S1 : public Board { public: explicit S1(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 6000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardSunsoft2.cpp000066400000000000000000000037721411157722000226350ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardSunsoft2.hpp" namespace Nes { namespace Core { namespace Boards { namespace Sunsoft { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void S2a::SubReset(bool) { Map( 0x8000U, 0xFFFFU, &S2a::Poke_8000 ); } void S2b::SubReset(bool) { Map( 0x8000U, 0xFFFFU, &S2b::Poke_8000 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(S2a,8000) { ppu.Update(); data = GetBusData(address,data); prg.SwapBank( data >> 4 ); chr.SwapBank( (data >> 4 & 0x8) | (data & 0x7) ); } NES_POKE_AD(S2b,8000) { data = GetBusData(address,data); ppu.SetMirroring( (data & 0x8) ? Ppu::NMT_1 : Ppu::NMT_0 ); prg.SwapBank( data >> 4 ); chr.SwapBank( (data >> 4 & 0x8) | (data & 0x7) ); } } } } } nestopia-1.51.1/source/core/board/NstBoardSunsoft2.hpp000066400000000000000000000032131411157722000226300ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SUNSOFT_SUNSOFT2_H #define NST_BOARD_SUNSOFT_SUNSOFT2_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Sunsoft { class S2a : public Board { public: explicit S2a(const Context& c) : Board(c) {} protected: void SubReset(bool); NES_DECL_POKE( 8000 ); }; class S2b : public S2a { public: explicit S2b(const Context& c) : S2a(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardSunsoft3.cpp000066400000000000000000000071611411157722000226320ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardSunsoft3.hpp" namespace Nes { namespace Core { namespace Boards { namespace Sunsoft { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif S3::S3(const Context& c) : Board (c), irq (*c.cpu) {} void S3::Irq::Reset(const bool hard) { if (hard) { enabled = false; count = 0; toggle = 0; } } void S3::SubReset(const bool hard) { irq.Reset( hard, true ); Map( 0x8800U, 0x8FFFU, CHR_SWAP_2K_0 ); Map( 0x9800U, 0x9FFFU, CHR_SWAP_2K_1 ); Map( 0xA800U, 0xAFFFU, CHR_SWAP_2K_2 ); Map( 0xB800U, 0xBFFFU, CHR_SWAP_2K_3 ); Map( 0xC000U, 0xCFFFU, &S3::Poke_C000 ); Map( 0xD800U, 0xDFFFU, &S3::Poke_D800 ); Map( 0xE800U, 0xEFFFU, NMT_SWAP_VH01 ); Map( 0xF800U, 0xFFFFU, PRG_SWAP_16K_0 ); } void S3::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'S','3'>::V) ); if (baseChunk == AsciiId<'S','3'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'I','R','Q'>::V) { State::Loader::Data<3> data( state ); irq.unit.enabled = data[0] & 0x1; irq.unit.toggle = data[0] >> 1 & 0x1; irq.unit.count = data[1] | data[2] << 8; } state.End(); } } } void S3::SubSave(State::Saver& state) const { const byte data[3] = { (irq.unit.enabled ? 0x1U : 0x0U) | (irq.unit.toggle ? 0x2U : 0x0U), irq.unit.count & 0xFF, irq.unit.count >> 8 }; state.Begin( AsciiId<'S','3'>::V ).Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(S3,C000) { irq.Update(); if (irq.unit.toggle ^= 1) irq.unit.count = (irq.unit.count & 0x00FF) | data << 8; else irq.unit.count = (irq.unit.count & 0xFF00) | data << 0; } NES_POKE_D(S3,D800) { irq.Update(); irq.unit.toggle = 0; irq.unit.enabled = data & 0x10; irq.ClearIRQ(); } bool S3::Irq::Clock() { if (enabled && count && !--count) { enabled = false; count = 0xFFFF; return true; } return false; } void S3::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardSunsoft3.hpp000066400000000000000000000034321411157722000226340ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SUNSOFT_SUNSOFT3_H #define NST_BOARD_SUNSOFT_SUNSOFT3_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "../NstTimer.hpp" namespace Nes { namespace Core { namespace Boards { namespace Sunsoft { class S3 : public Board { public: explicit S3(const Context&); private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Sync(Event,Input::Controllers*); NES_DECL_POKE( C000 ); NES_DECL_POKE( D800 ); struct Irq { void Reset(bool); bool Clock(); ibool enabled; uint count; uint toggle; }; Timer::M2 irq; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardSunsoft4.cpp000066400000000000000000000070721411157722000226340ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardSunsoft4.hpp" namespace Nes { namespace Core { namespace Boards { namespace Sunsoft { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void S4::SubReset(const bool hard) { if (hard) { regs.ctrl = 0; regs.nmt[0] = Regs::BANK_OFFSET; regs.nmt[1] = Regs::BANK_OFFSET; } Map( 0x8000U, 0x8FFFU, CHR_SWAP_2K_0 ); Map( 0x9000U, 0x9FFFU, CHR_SWAP_2K_1 ); Map( 0xA000U, 0xAFFFU, CHR_SWAP_2K_2 ); Map( 0xB000U, 0xBFFFU, CHR_SWAP_2K_3 ); Map( 0xC000U, 0xCFFFU, &S4::Poke_C000 ); Map( 0xD000U, 0xDFFFU, &S4::Poke_D000 ); Map( 0xE000U, 0xEFFFU, &S4::Poke_E000 ); Map( 0xF000U, 0xFFFFU, PRG_SWAP_16K_0 ); } void S4::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'S','4'>::V) ); if (baseChunk == AsciiId<'S','4'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: { State::Loader::Data<3> data( state ); regs.ctrl = data[0]; regs.nmt[0] = data[1] | Regs::BANK_OFFSET; regs.nmt[1] = data[2] | Regs::BANK_OFFSET; break; } } state.End(); } } } void S4::SubSave(State::Saver& state) const { const byte data[3] = { regs.ctrl, regs.nmt[0] & ~uint(Regs::BANK_OFFSET), regs.nmt[1] & ~uint(Regs::BANK_OFFSET) }; state.Begin( AsciiId<'S','4'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void S4::UpdateMirroring() const { ppu.Update(); static const byte select[4][4] = { {0,1,0,1}, {0,0,1,1}, {0,0,0,0}, {1,1,1,1} }; const uint isCrom = (regs.ctrl & Regs::CTRL_CROM) >> 4; const byte (&index)[4] = select[regs.ctrl & Regs::CTRL_MIRRORING]; for (uint i=0; i < 4; ++i) nmt.Source( isCrom ).SwapBank( i * SIZE_1K, isCrom ? regs.nmt[index[i]] : index[i] ); } NES_POKE_D(S4,C000) { regs.nmt[0] = Regs::BANK_OFFSET | data; UpdateMirroring(); } NES_POKE_D(S4,D000) { regs.nmt[1] = Regs::BANK_OFFSET | data; UpdateMirroring(); } NES_POKE_D(S4,E000) { regs.ctrl = data; UpdateMirroring(); } } } } } nestopia-1.51.1/source/core/board/NstBoardSunsoft4.hpp000066400000000000000000000035711411157722000226410ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SUNSOFT_SUNSOFT4_H #define NST_BOARD_SUNSOFT_SUNSOFT4_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Sunsoft { class S4 : public Board { public: explicit S4(const Context& c) : Board(c) {} protected: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); private: void UpdateMirroring() const; NES_DECL_POKE( C000 ); NES_DECL_POKE( D000 ); NES_DECL_POKE( E000 ); struct Regs { enum { CTRL_MIRRORING = 0x03, CTRL_CROM = 0x10, BANK_OFFSET = 0x80 }; uint ctrl; uint prg; uint nmt[2]; }; Regs regs; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardSunsoft5b.cpp000066400000000000000000000330541411157722000227760ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "../NstTimer.hpp" #include "NstBoardSunsoftFme7.hpp" #include "NstBoardSunsoft5b.hpp" namespace Nes { namespace Core { namespace Boards { namespace Sunsoft { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif const word S5b::Sound::levels[32] = { // 32 levels, 1.5dB per step 0,89,106,127,152,181,216,257,306,364,433,515,613,729,867,1031,1226,1458, 1733,2060,2449,2911,3460,4113,4889,5811,6907,8209,9757,11597,13784,16383 }; S5b::Sound::Sound(Apu& a,bool connect) : Channel(a), fixed(1) { Reset(); bool audible = UpdateSettings(); if (connect) Connect( audible ); } S5b::S5b(const Context& c) : Fme7 (c), sound (*c.apu) {} void S5b::Sound::Envelope::Reset(const uint fixed) { holding = false; hold = 0; alternate = 0; attack = 0; timer = 0; frequency = 1 * 8 * fixed; length = 0; count = 0; volume = 0; } void S5b::Sound::Noise::Reset(const uint fixed) { timer = 0; frequency = 1 * 16 * fixed; length = 0; rng = 1; dc = 0; } void S5b::Sound::Square::Reset(const uint fixed) { timer = 0; frequency = 1 * 16 * fixed; status = 0; ctrl = 0; volume = 0; dc = 0; length = 0; } void S5b::Sound::Reset() { active = false; regSelect = 0x0; envelope.Reset( fixed ); for (uint i=0; i < NUM_SQUARES; ++i) squares[i].Reset( fixed ); noise.Reset( fixed ); dcBlocker.Reset(); } void S5b::SubReset(const bool hard) { Fme7::SubReset( hard ); Map( 0xC000U, 0xDFFFU, &S5b::Poke_C000 ); Map( 0xE000U, 0xFFFFU, &S5b::Poke_E000 ); } void S5b::Sound::Envelope::UpdateSettings(const uint fixed) { timer = 0; UpdateFrequency( fixed ); } void S5b::Sound::Noise::UpdateSettings(const uint fixed) { timer = 0; UpdateFrequency( fixed ); } void S5b::Sound::Square::UpdateSettings(const uint fixed) { timer = 0; UpdateFrequency( fixed ); } bool S5b::Sound::UpdateSettings() { uint volume = GetVolume(EXT_S5B) * 94U / DEFAULT_VOLUME; output = IsMuted() ? 0 : volume; GetOscillatorClock( rate, fixed ); envelope.UpdateSettings( fixed ); for (uint i=0; i < NUM_SQUARES; ++i) squares[i].UpdateSettings( fixed ); noise.UpdateSettings( fixed ); dcBlocker.Reset(); return volume; } void S5b::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'S','5','B'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'S','N','D'>::V) sound.LoadState( state ); state.End(); } } else { Fme7::SubLoad( state, baseChunk ); } } void S5b::SubSave(State::Saver& state) const { Fme7::SubSave( state ); state.Begin( AsciiId<'S','5','B'>::V ); sound.SaveState( state, AsciiId<'S','N','D'>::V ); state.End(); } void S5b::Sound::SaveState(State::Saver& state,const dword baseChunk) const { state.Begin( baseChunk ); state.Begin( AsciiId<'R','E','G'>::V ).Write8( regSelect ).End(); envelope.SaveState ( state, AsciiId<'E','N','V'>::V ); noise.SaveState ( state, AsciiId<'N','O','I'>::V ); squares[0].SaveState ( state, AsciiId<'S','Q','0'>::V ); squares[1].SaveState ( state, AsciiId<'S','Q','1'>::V ); squares[2].SaveState ( state, AsciiId<'S','Q','2'>::V ); state.End(); } void S5b::Sound::LoadState(State::Loader& state) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: regSelect = state.Read8(); break; case AsciiId<'E','N','V'>::V: envelope.LoadState( state, fixed ); break; case AsciiId<'N','O','I'>::V: noise.LoadState( state, fixed ); break; case AsciiId<'S','Q','0'>::V: squares[0].LoadState( state, fixed ); break; case AsciiId<'S','Q','1'>::V: squares[1].LoadState( state, fixed ); break; case AsciiId<'S','Q','2'>::V: squares[2].LoadState( state, fixed ); break; } state.End(); } } void S5b::Sound::Envelope::SaveState(State::Saver& state,const dword chunk) const { const byte data[4] = { (holding ? 0x1U : 0x0U) | (hold ? 0x2U : 0x1U) | (alternate ? 0x4U : 0x0U) | (attack ? 0x8U : 0x0U), count, length & 0xFF, length >> 8 }; state.Begin( chunk ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } void S5b::Sound::Noise::SaveState(State::Saver& state,const dword chunk) const { state.Begin( chunk ).Begin( AsciiId<'R','E','G'>::V ).Write8( length ).End().End(); } void S5b::Sound::Square::SaveState(State::Saver& state,const dword chunk) const { const byte data[3] = { (~status & 0x1) | (ctrl << 1), length & 0xFF, (length >> 8) | ((status & 0x8) << 1), }; state.Begin( chunk ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } void S5b::Sound::Envelope::LoadState(State::Loader& state,const uint fixed) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<4> data( state ); holding = data[0] & 0x1; hold = data[0] & 0x2; alternate = data[0] & 0x4; attack = (data[0] & 0x8) ? 0x1F : 0x00; count = data[1] & 0x1F; length = data[2] | (data[3] << 8 & 0xF00); volume = levels[count ^ attack]; UpdateSettings( fixed ); } state.End(); } } void S5b::Sound::Noise::LoadState(State::Loader& state,const uint fixed) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { length = state.Read8() & 0x1F; dc = 0; rng = 1; UpdateSettings( fixed ); } state.End(); } } void S5b::Sound::Square::LoadState(State::Loader& state,const uint fixed) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<3> data( state ); status = (~data[0] & 0x1) | (data[2] >> 1 & 0x8); ctrl = data[0] >> 1 & 0x1F; length = data[1] | (data[2] << 8 & 0xF00); volume = levels[(ctrl & 0xF) ? (ctrl & 0xF) * 2 + 1 : 0]; dc = (status & 0x1) ? ~dword(0) : dword(0); UpdateSettings( fixed ); } state.End(); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(S5b,C000) { sound.SelectReg( data ); } void S5b::Sound::Square::UpdateFrequency(const uint fixed) { const idword prev = frequency; frequency = NST_MAX(length,1) * 16 * fixed; timer = NST_MAX(timer + idword(frequency) - prev,0); } void S5b::Sound::Square::WriteReg0(const uint data,const uint fixed) { length = (length & 0x0F00) | data; UpdateFrequency( fixed ); } void S5b::Sound::Square::WriteReg1(const uint data,const uint fixed) { length = (length & 0x00FF) | (data & 0xF) << 8; UpdateFrequency( fixed ); } void S5b::Sound::Square::WriteReg2(const uint data) { status = data & (0x1|0x8); if (status & 0x1) dc = (unsigned int) ~0UL; } void S5b::Sound::Square::WriteReg3(const uint data) { ctrl = data & 0x1F; volume = levels[(ctrl & 0xF) ? (ctrl & 0xF) * 2 + 1 : 0]; } void S5b::Sound::Envelope::UpdateFrequency(const uint fixed) { const idword prev = frequency; frequency = NST_MAX(length*16,1*8) * fixed; timer = NST_MAX(timer + idword(frequency) - prev,0); } void S5b::Sound::Envelope::WriteReg0(const uint data,const uint fixed) { length = (length & 0xFF00) | data << 0; UpdateFrequency( fixed ); } void S5b::Sound::Envelope::WriteReg1(const uint data,const uint fixed) { length = (length & 0x00FF) | data << 8; UpdateFrequency( fixed ); } void S5b::Sound::Envelope::WriteReg2(const uint data) { holding = false; attack = (data & 0x04) ? 0x1F : 0x00; if (data & 0x8) { hold = data & 0x1; alternate = data & 0x2; } else { hold = 1; alternate = attack; } timer = frequency; count = 0x1F; volume = levels[count ^ attack]; } void S5b::Sound::Noise::UpdateFrequency(const uint fixed) { const idword prev = frequency; frequency = NST_MAX(length,1) * 16 * fixed; timer = NST_MAX(timer + idword(frequency) - prev,0); } void S5b::Sound::Noise::WriteReg(const uint data,const uint fixed) { length = data & 0x1F; UpdateFrequency( fixed ); } void S5b::Sound::WriteReg(const uint data) { Update(); active = true; switch (regSelect & 0xF) { case 0x0: case 0x2: case 0x4: squares[regSelect >> 1].WriteReg0( data, fixed ); break; case 0x1: case 0x3: case 0x5: squares[regSelect >> 1].WriteReg1( data, fixed ); break; case 0x6: noise.WriteReg( data, fixed ); break; case 0x7: for (uint i=0; i < NUM_SQUARES; ++i) squares[i].WriteReg2( data >> i ); break; case 0x8: case 0x9: case 0xA: squares[regSelect - 0x8].WriteReg3( data ); break; case 0xB: envelope.WriteReg0( data, fixed ); break; case 0xC: envelope.WriteReg1( data, fixed ); break; case 0xD: envelope.WriteReg2( data ); break; } } NES_POKE_D(S5b,E000) { sound.WriteReg( data ); } NST_SINGLE_CALL dword S5b::Sound::Envelope::Clock(const Cycle rate) { if (!holding) { timer -= idword(rate); if (timer < 0) { do { --count; timer += idword(frequency); } while (timer < 0); if (count > 0x1F) { if (hold) { if (alternate) attack ^= 0x1FU; holding = true; count = 0x00; } else { if (alternate && count & 0x20) attack ^= 0x1FU; count = 0x1F; } } volume = levels[count ^ attack]; } } return volume; } NST_SINGLE_CALL dword S5b::Sound::Noise::Clock(const Cycle rate) { for (timer -= idword(rate); timer < 0; timer += idword(frequency)) { if ((rng + 1) & 0x2) dc = ~dc; if ((rng + 0) & 0x1) rng ^= 0x24000; rng >>= 1; } return dc; } NST_SINGLE_CALL dword S5b::Sound::Square::GetSample(const Cycle rate,const uint envelope,const uint noise) { dword sum = timer; timer -= idword(rate); const uint out = (ctrl & 0x10) ? envelope : volume; if ((noise|status) & 0x8 && out) { if (timer >= 0) { return out & dc; } else { sum &= dc; do { dc ^= (status & 0x1) - 1UL; sum += NST_MIN(dword(-timer),frequency) & dc; timer += idword(frequency); } while (timer < 0); NST_VERIFY( sum <= 0xFFFFFFFF / out + rate/2 ); return (sum * out + rate/2) / rate; } } else { while (timer < 0) { dc ^= (status & 0x1) - 1UL; timer += idword(frequency); } return 0; } } S5b::Sound::Sample S5b::Sound::GetSample() { if (active && output) { dword sample = 0; for (dword i=0, e=envelope.Clock( rate ), n=noise.Clock( rate ); i < NUM_SQUARES; ++i) sample += squares[i].GetSample( rate, e, n ); return dcBlocker.Apply( sample * output / DEFAULT_VOLUME ); } else { return 0; } } } } } } nestopia-1.51.1/source/core/board/NstBoardSunsoft5b.hpp000066400000000000000000000077131411157722000230060ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SUNSOFT_5B_H #define NST_BOARD_SUNSOFT_5B_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Sunsoft { class S5b : public Fme7 { public: explicit S5b(const Context&); class Sound : public Apu::Channel { public: explicit Sound(Apu&,bool=true); void WriteReg(uint); void LoadState(State::Loader&); void SaveState(State::Saver&,dword) const; protected: void Reset(); bool UpdateSettings(); Sample GetSample(); private: enum { NUM_SQUARES = 3 }; class Envelope { public: void Reset(uint); void UpdateSettings(uint); void SaveState(State::Saver&,dword) const; void LoadState(State::Loader&,uint); void WriteReg0(uint,uint); void WriteReg1(uint,uint); void WriteReg2(uint); NST_SINGLE_CALL dword Clock(Cycle); private: void UpdateFrequency(uint); byte holding; byte hold; byte alternate; byte attack; idword timer; dword frequency; uint count; uint volume; uint length; }; class Noise { public: void Reset(uint); void UpdateSettings(uint); void SaveState(State::Saver&,dword) const; void LoadState(State::Loader&,uint); void WriteReg(uint,uint); NST_SINGLE_CALL dword Clock(Cycle); private: void UpdateFrequency(uint); idword timer; dword frequency; dword rng; dword dc; uint length; }; class Square { public: void Reset(uint); void UpdateSettings(uint); void SaveState(State::Saver&,dword) const; void LoadState(State::Loader&,uint); void WriteReg0(uint,uint); void WriteReg1(uint,uint); void WriteReg2(uint); void WriteReg3(uint); NST_SINGLE_CALL dword GetSample(Cycle,uint,uint); private: void UpdateFrequency(uint); idword timer; dword frequency; uint status; uint ctrl; uint volume; dword dc; uint length; }; ibool active; uint output; Cycle rate; uint fixed; uint regSelect; Envelope envelope; Noise noise; Square squares[NUM_SQUARES]; DcBlocker dcBlocker; static const word levels[32]; public: void SelectReg(uint data) { regSelect = data; } }; private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); NES_DECL_POKE( C000 ); NES_DECL_POKE( E000 ); Sound sound; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardSunsoftDcs.cpp000066400000000000000000000056251411157722000232040ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardSunsoftDcs.hpp" namespace Nes { namespace Core { namespace Boards { namespace Sunsoft { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Dcs::SubReset(const bool hard) { counter = SIGNAL; prgBank = 0; S4::SubReset( hard ); prg.SwapBanks( 0x0, 0x7 ); Map( 0x6000U, &Dcs::Poke_6000 ); Map( 0x8000U, 0xBFFFU, &Dcs::Peek_8000 ); Map( 0xF000U, 0xFFFFU, &Dcs::Poke_F000 ); } void Dcs::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'S','D','C'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'D','B','C'>::V) { prgBank = state.Read8() & 0xF; counter = state.Read16(); if (counter > SIGNAL) counter = SIGNAL; } state.End(); } } else { S4::SubLoad( state, baseChunk ); } } void Dcs::SubSave(State::Saver& state) const { S4::SubSave( state ); state.Begin( AsciiId<'S','D','C'>::V ).Begin( AsciiId<'D','B','C'>::V ).Write8( prgBank ).Write16( counter ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Dcs,6000) { if (data == 0x00) { counter = 0; prg.SwapBank( prgBank ); } } NES_PEEK_A(Dcs,8000) { if (const uint bank = ((prgBank & 0x8 && counter < SIGNAL && ++counter == SIGNAL) ? ((prgBank & 0x7) | 0x10) : 0)) prg.SwapBank( bank & 0xF ); return prg.Peek( address - 0x8000 ); } NES_POKE_D(Dcs,F000) { prgBank = (data & 0x7) | (~data & 0x8); prg.SwapBank( prgBank ); } } } } } nestopia-1.51.1/source/core/board/NstBoardSunsoftDcs.hpp000066400000000000000000000033071411157722000232040ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SUNSOFT_DCS_H #define NST_BOARD_SUNSOFT_DCS_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardSunsoft4.hpp" namespace Nes { namespace Core { namespace Boards { namespace Sunsoft { class Dcs : public S4 { public: explicit Dcs(const Context& c) : S4(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); NES_DECL_POKE( 6000 ); NES_DECL_PEEK( 8000 ); NES_DECL_POKE( F000 ); enum { SIGNAL = 1784 }; uint prgBank; uint counter; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardSunsoftFme7.cpp000066400000000000000000000110331411157722000232570ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "../NstTimer.hpp" #include "NstBoardSunsoftFme7.hpp" namespace Nes { namespace Core { namespace Boards { namespace Sunsoft { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Fme7::Fme7(const Context& c) : Board (c), irq (*c.cpu) {} void Fme7::Irq::Reset(const bool hard) { if (hard) { enabled = false; count = 0; } } void Fme7::SubReset(const bool hard) { if (hard) command = 0x0; irq.Reset( hard, hard ? false : irq.Connected() ); Map( 0x6000U, 0x7FFFU, &Fme7::Peek_6000 ); Map( 0x8000U, 0x9FFFU, &Fme7::Poke_8000 ); Map( 0xA000U, 0xBFFFU, &Fme7::Poke_A000 ); } void Fme7::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'S','F','7'>::V) ); if (baseChunk == AsciiId<'S','F','7'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: command = state.Read8(); break; case AsciiId<'I','R','Q'>::V: { State::Loader::Data<3> data( state ); irq.Connect( data[0] & 0x80 ); irq.unit.enabled = data[0] & 0x01; irq.unit.count = data[1] | data[2] << 8; break; } } state.End(); } } } void Fme7::SubSave(State::Saver& state) const { state.Begin( AsciiId<'S','F','7'>::V ); state.Begin( AsciiId<'R','E','G'>::V ).Write8( command ).End(); { const byte data[3] = { (irq.Connected() ? 0x80U : 0x00U) | (irq.unit.enabled ? 0x1U : 0x0U), irq.unit.count & 0xFF, irq.unit.count >> 8 }; state.Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End(); } state.End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(Fme7,6000) { return wrk[0][address - 0x6000]; } NES_POKE_D(Fme7,8000) { command = data; } NES_POKE_D(Fme7,A000) { switch (const uint bank = (command & 0xF)) { case 0x0: case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7: ppu.Update(); chr.SwapBank( bank << 10, data ); break; case 0x8: if (!(data & 0x40) || (data & 0x80)) wrk.Source( !(data & 0x40) ).SwapBank( data ); break; case 0x9: case 0xA: case 0xB: prg.SwapBank( (command - 0x9) << 13, data ); break; case 0xC: SetMirroringVH01( data ); break; case 0xD: irq.Update(); irq.unit.enabled = data & 0x01; irq.Connect( data & 0x80 ); irq.ClearIRQ(); break; case 0xE: irq.Update(); irq.unit.count = (irq.unit.count & 0xFF00) | data << 0; break; case 0xF: irq.Update(); irq.unit.count = (irq.unit.count & 0x00FF) | data << 8; break; } } bool Fme7::Irq::Clock() { count = (count - 1U) & 0xFFFF; return count < enabled; } void Fme7::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardSunsoftFme7.hpp000066400000000000000000000034471411157722000232760ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SUNSOFT_FME7_H #define NST_BOARD_SUNSOFT_FME7_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Sunsoft { class Fme7 : public Board { public: explicit Fme7(const Context&); protected: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Sync(Event,Input::Controllers*); private: NES_DECL_PEEK( 6000 ); NES_DECL_POKE( 8000 ); NES_DECL_POKE( A000 ); struct Irq { void Reset(bool); bool Clock(); uint count; ibool enabled; }; uint command; Timer::M2 irq; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardSuperGame.hpp000066400000000000000000000026361411157722000230050ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SUPERGAME_H #define NST_BOARD_SUPERGAME_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardSuperGameBoogerman.hpp" #include "NstBoardSuperGameLionKing.hpp" #include "NstBoardSuperGamePocahontas2.hpp" namespace Nes { namespace Core { namespace Boards { namespace SuperGame { typedef Boogerman Mk3e; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardSuperGameBoogerman.cpp000066400000000000000000000127251411157722000246320ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardSuperGameBoogerman.hpp" namespace Nes { namespace Core { namespace Boards { namespace SuperGame { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Boogerman::SubReset(const bool hard) { exRegs[0] = 0x00; exRegs[1] = 0xFF; exRegs[2] = 0x04; exRegs[3] = false; Mmc3::SubReset( hard ); Map( 0x5000U, &Boogerman::Poke_5000 ); Map( 0x5001U, &Boogerman::Poke_5001 ); Map( 0x5007U, &Boogerman::Poke_5007 ); if (board != Type::SUPERGAME_MK3E) { Map( 0x6000U, &Boogerman::Poke_5000 ); Map( 0x6001U, &Boogerman::Poke_5001 ); Map( 0x6007U, &Boogerman::Poke_5007 ); } for (uint i=0x0000; i < 0x2000; i += 0x2) { Map( 0x8000U + i, &Boogerman::Poke_8000 ); Map( 0x8001U + i, &Boogerman::Poke_8001 ); Map( 0xA000U + i, &Boogerman::Poke_A000 ); Map( 0xC000U + i, &Boogerman::Poke_C000 ); Map( 0xC001U + i, &Boogerman::Poke_C001 ); Map( 0xE001U + i, &Boogerman::Poke_E001 ); } } void Boogerman::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'S','B','G'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { state.Read( exRegs ); exRegs[3] &= 0x1U; } state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void Boogerman::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); state.Begin( AsciiId<'S','B','G'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( exRegs ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void NST_FASTCALL Boogerman::UpdatePrg(uint address,uint bank) { if (!(exRegs[0] & 0x80U)) { if (exRegs[1] & 0x8U) bank = (bank & 0x1F) | 0x20; else bank = (bank & 0x0F) | (exRegs[1] & 0x10U); prg.SwapBank( address, bank ); } } void NST_FASTCALL Boogerman::UpdateChr(uint address,uint bank) const { if (exRegs[1] & 0x4U) bank = (bank | 0x100); else bank = (bank & 0x7F) | (exRegs[1] << 3 & 0x80U); chr.SwapBank( address, bank ); } void Boogerman::UpdatePrg() { if (exRegs[0] & 0x80U) { uint bank = (exRegs[0] & 0x0FU) | (exRegs[1] & 0x10U); prg.SwapBanks( bank, bank ); } else { Mmc3::UpdatePrg(); } } NES_POKE_D(Boogerman,5000) { if (exRegs[0] != data) { exRegs[0] = data; UpdatePrg(); } } NES_POKE_D(Boogerman,5001) { if (exRegs[1] != data) { exRegs[1] = data; Mmc3::UpdateChr(); } } NES_POKE_D(Boogerman,5007) { regs.ctrl0 = 0; if (exRegs[2] != data) { exRegs[2] = data; UpdatePrg(); Mmc3::UpdateChr(); } } NES_POKE_D(Boogerman,8000) { if (!exRegs[2]) Mmc3::NES_DO_POKE(8000,0x8000,data); } NES_POKE_D(Boogerman,8001) { if (exRegs[2]) { if (exRegs[3] && ((exRegs[0] & 0x80U) == 0 || (regs.ctrl0 & 0x7) < 6)) { exRegs[3] = false; Mmc3::NES_DO_POKE(8001,0x8001,data); } } else { Mmc3::NES_DO_POKE(8001,0x8001,data); } } NES_POKE_D(Boogerman,A000) { if (exRegs[2]) { static const byte security[8] = {0,2,5,3,6,1,7,4}; data = (data & 0xC0) | security[data & 0x07]; exRegs[3] = true; Mmc3::NES_DO_POKE(8000,0x8000,data); } else { SetMirroringHV( data ); } } NES_POKE_D(Boogerman,C000) { if (exRegs[2]) SetMirroringHV( data >> 7 | data ); else Mmc3::NES_DO_POKE(C000,0xC000,data); } NES_POKE_D(Boogerman,C001) { if (exRegs[2]) Mmc3::NES_DO_POKE(E001,0xE001,data); else Mmc3::NES_DO_POKE(C001,0xC001,data); } NES_POKE_D(Boogerman,E001) { if (exRegs[2]) { Mmc3::NES_DO_POKE(C000,0xC000,data); Mmc3::NES_DO_POKE(C001,0xC001,data); } else { Mmc3::NES_DO_POKE(E001,0xE001,data); } } } } } } nestopia-1.51.1/source/core/board/NstBoardSuperGameBoogerman.hpp000066400000000000000000000036531411157722000246370ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SUPERGAME_BOOGERMAN_H #define NST_BOARD_SUPERGAME_BOOGERMAN_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace SuperGame { class Boogerman : public Mmc3 { public: explicit Boogerman(const Context& c) : Mmc3(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void UpdatePrg(); void NST_FASTCALL UpdatePrg(uint,uint); void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_POKE( 5000 ); NES_DECL_POKE( 5001 ); NES_DECL_POKE( 5007 ); NES_DECL_POKE( 8000 ); NES_DECL_POKE( 8001 ); NES_DECL_POKE( A000 ); NES_DECL_POKE( C000 ); NES_DECL_POKE( C001 ); NES_DECL_POKE( E001 ); byte exRegs[4]; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardSuperGameLionKing.cpp000066400000000000000000000067341411157722000244360ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardSuperGameLionKing.hpp" namespace Nes { namespace Core { namespace Boards { namespace SuperGame { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void LionKing::SubReset(const bool hard) { exRegs[0] = 0x00; exRegs[1] = false; Mmc3::SubReset( hard ); Map( 0x5000U, 0x7FFFU, &LionKing::Poke_5000 ); Map( 0x8000U, 0x9FFFU, NMT_SWAP_HV ); Map( 0xA000U, 0xBFFFU, &LionKing::Poke_A000 ); Map( 0xC000U, 0xDFFFU, &LionKing::Poke_C000 ); Map( 0xE000U, 0xFFFFU, NOP_POKE ); Map( 0xE002U, &LionKing::Poke_E000 ); Map( 0xE003U, &LionKing::Poke_E003 ); } void LionKing::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'S','L','K'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<2> data( state ); exRegs[0] = data[0]; exRegs[1] = data[1] & 0x1; } state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void LionKing::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); const byte data[2] = { exRegs[0], exRegs[1] }; state.Begin( AsciiId<'S','L','K'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(LionKing,5000) { exRegs[0] = data; if (data & 0x80) { data &= 0x1F; prg.SwapBanks( data, data ); } else { Mmc3::UpdatePrg(); } } NES_POKE_D(LionKing,A000) { static const byte security[8] = {0,3,1,5,6,7,2,4}; data = (data & 0xC0) | security[data & 0x07]; exRegs[1] = true; Mmc3::NES_DO_POKE(8000,0x8000,data); } NES_POKE_D(LionKing,C000) { if (exRegs[1] && ((exRegs[0] & 0x80) == 0 || (regs.ctrl0 & 0x7) < 6)) { exRegs[1] = false; Mmc3::NES_DO_POKE(8001,0x8001,data); } } NES_POKE_D(LionKing,E003) { Mmc3::NES_DO_POKE(E001,0xE001,data); Mmc3::NES_DO_POKE(C000,0xC000,data); Mmc3::NES_DO_POKE(C001,0xC001,data); } } } } } nestopia-1.51.1/source/core/board/NstBoardSuperGameLionKing.hpp000066400000000000000000000032671411157722000244410ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SUPERGAME_LIONKING_H #define NST_BOARD_SUPERGAME_LIONKING_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace SuperGame { class LionKing : public Mmc3 { public: explicit LionKing(const Context& c) : Mmc3(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); NES_DECL_POKE( 5000 ); NES_DECL_POKE( 8000 ); NES_DECL_POKE( A000 ); NES_DECL_POKE( C000 ); NES_DECL_POKE( E003 ); uint exRegs[2]; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardSuperGamePocahontas2.cpp000066400000000000000000000104371411157722000251000ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardSuperGamePocahontas2.hpp" namespace Nes { namespace Core { namespace Boards { namespace SuperGame { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Pocahontas2::SubReset(const bool hard) { if (hard) { exRegs[0] = 0x00; exRegs[1] = 0x00; } exRegs[2] = false; Mmc3::SubReset( hard ); Map( 0x5000U, &Pocahontas2::Poke_5000 ); Map( 0x5001U, &Pocahontas2::Poke_5001 ); Map( 0x8000U, 0x9FFFU, &Pocahontas2::Poke_8000 ); Map( 0xA000U, 0xBFFFU, &Pocahontas2::Poke_A000 ); Map( 0xC000U, 0xDFFFU, &Pocahontas2::Poke_C000 ); Map( 0xE000U, 0xEFFFU, &Pocahontas2::Poke_E000 ); Map( 0xF000U, 0xFFFFU, &Pocahontas2::Poke_F000 ); } void Pocahontas2::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'S','P','2'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<3> data( state ); exRegs[0] = data[0]; exRegs[1] = data[1]; exRegs[2] = data[2] & 0x1; } state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void Pocahontas2::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); const byte data[3] = { exRegs[0], exRegs[1], exRegs[2] }; state.Begin( AsciiId<'S','P','2'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void NST_FASTCALL Pocahontas2::UpdatePrg(uint address,uint bank) { if (!(exRegs[0] & 0x80)) prg.SwapBank( address, bank ); } void NST_FASTCALL Pocahontas2::UpdateChr(uint address,uint bank) const { chr.SwapBank( address, (exRegs[1] << 6 & 0x100) | bank ); } NES_POKE_D(Pocahontas2,5000) { if (exRegs[0] != data) { exRegs[0] = data; if (exRegs[0] & 0x80) { const uint bank = exRegs[0] & 0xF; if (exRegs[0] & 0x20) prg.SwapBank( bank >> 1 ); else prg.SwapBanks( bank, bank ); } else { Mmc3::UpdatePrg(); } } } NES_POKE_D(Pocahontas2,5001) { if (exRegs[1] != data) { exRegs[1] = data; Mmc3::UpdateChr(); } } NES_POKE_D(Pocahontas2,8000) { SetMirroringHV( data >> 7 | data ); } NES_POKE_D(Pocahontas2,A000) { static const byte lut[8] = {0,2,6,1,7,3,4,5}; data = (data & 0xC0) | lut[data & 0x07]; exRegs[2] = true; Mmc3::NES_DO_POKE(8000,0x8000,data); } NES_POKE_D(Pocahontas2,C000) { if (exRegs[2]) { exRegs[2] = false; Mmc3::NES_DO_POKE(8001,0x8001,data); } } NES_POKE_D(Pocahontas2,F000) { Mmc3::NES_DO_POKE(E001,0xE001,data); Mmc3::NES_DO_POKE(C000,0xC000,data); Mmc3::NES_DO_POKE(C001,0xC001,data); } } } } } nestopia-1.51.1/source/core/board/NstBoardSuperGamePocahontas2.hpp000066400000000000000000000035041411157722000251020ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SUPERGAME_POCAHONTAS2_H #define NST_BOARD_SUPERGAME_POCAHONTAS2_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace SuperGame { class Pocahontas2 : public Mmc3 { public: explicit Pocahontas2(const Context& c) : Mmc3(c) {} private: void SubReset(bool); void SubLoad(State::Loader&,dword); void SubSave(State::Saver&) const; void NST_FASTCALL UpdatePrg(uint,uint); void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_POKE( 5000 ); NES_DECL_POKE( 5001 ); NES_DECL_POKE( 8000 ); NES_DECL_POKE( A000 ); NES_DECL_POKE( C000 ); NES_DECL_POKE( F000 ); uint exRegs[3]; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardSxRom.hpp000066400000000000000000000027021411157722000221570ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_SXROM_H #define NST_BOARD_SXROM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardMmc1.hpp" namespace Nes { namespace Core { namespace Boards { class SxRom : public Mmc1 { public: explicit SxRom(const Context& c) : Mmc1(c,c.chips.Has(L"MMC1") || c.chips.Has(L"MMC1A") ? REV_A : c.chips.Has(L"MMC1B3") ? REV_B3 : REV_B2) {} }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardTaito.hpp000066400000000000000000000023711411157722000221710ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_TAITO_H #define NST_BOARD_TAITO_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardTaitoTc0190fmcPal16r4.hpp" #include "NstBoardTaitoX1005.hpp" #include "NstBoardTaitoX1017.hpp" #endif nestopia-1.51.1/source/core/board/NstBoardTaitoTc0190fmc.cpp000066400000000000000000000036671411157722000234640ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardTaitoTc0190fmc.hpp" namespace Nes { namespace Core { namespace Boards { namespace Taito { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Tc0190fmc::SubReset(bool) { for (uint i=0x0000; i < 0x1000; i += 0x4) { Map( 0x8000 + i, &Tc0190fmc::Poke_8000 ); Map( 0x8001 + i, PRG_SWAP_8K_1 ); Map( 0x8002 + i, CHR_SWAP_2K_0 ); Map( 0x8003 + i, CHR_SWAP_2K_1 ); Map( 0xA000 + i, CHR_SWAP_1K_4 ); Map( 0xA001 + i, CHR_SWAP_1K_5 ); Map( 0xA002 + i, CHR_SWAP_1K_6 ); Map( 0xA003 + i, CHR_SWAP_1K_7 ); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Tc0190fmc,8000) { prg.SwapBank( data ); ppu.SetMirroring( (data & 0x40) ? Ppu::NMT_H : Ppu::NMT_V ); } } } } } nestopia-1.51.1/source/core/board/NstBoardTaitoTc0190fmc.hpp000066400000000000000000000031651411157722000234620ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_TAITO_TC0190FMC_H #define NST_BOARD_TAITO_TC0190FMC_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Taito { class Tc0190fmc : public Board { public: explicit Tc0190fmc(const Context& c) : Board(c) {} protected: void SubReset(bool); private: NES_DECL_POKE( 8000 ); NES_DECL_POKE( C000 ); NES_DECL_POKE( C001 ); NES_DECL_POKE( C002 ); NES_DECL_POKE( C003 ); NES_DECL_POKE( E000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardTaitoTc0190fmcPal16r4.cpp000066400000000000000000000064171411157722000245320ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardTaitoTc0190fmcPal16r4.hpp" namespace Nes { namespace Core { namespace Boards { namespace Taito { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Tc0190fmcPal16r4::Tc0190fmcPal16r4(const Context& c) : Tc0190fmc(c), irq(*c.cpu,*c.ppu,false) {} void Tc0190fmcPal16r4::SubReset(const bool hard) { Tc0190fmc::SubReset( hard ); irq.Reset( hard ); for (uint i=0x0000; i < 0x1000; i += 0x4) { Map( 0x8000 + i, PRG_SWAP_8K_0 ); Map( 0xC000 + i, &Tc0190fmcPal16r4::Poke_C000 ); Map( 0xC001 + i, &Tc0190fmcPal16r4::Poke_C001 ); Map( 0xC002 + i, &Tc0190fmcPal16r4::Poke_C002 ); Map( 0xC003 + i, &Tc0190fmcPal16r4::Poke_C003 ); Map( 0xE000 + i, &Tc0190fmcPal16r4::Poke_E000 ); } } void Tc0190fmcPal16r4::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'T','T','C'>::V) ); if (baseChunk == AsciiId<'T','T','C'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'I','R','Q'>::V) irq.unit.LoadState( state ); state.End(); } } } void Tc0190fmcPal16r4::SubSave(State::Saver& state) const { state.Begin( AsciiId<'T','T','C'>::V ); irq.unit.SaveState( state, AsciiId<'I','R','Q'>::V ); state.End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Tc0190fmcPal16r4,C000) { irq.Update(); irq.unit.SetLatch( (0x100 - data) & 0xFF ); } NES_POKE(Tc0190fmcPal16r4,C001) { irq.Update(); irq.unit.Reload(); } NES_POKE(Tc0190fmcPal16r4,C002) { irq.Update(); irq.unit.Enable(); } NES_POKE(Tc0190fmcPal16r4,C003) { irq.Update(); irq.unit.Disable( cpu ); } NES_POKE_D(Tc0190fmcPal16r4,E000) { ppu.SetMirroring( (data & 0x40) ? Ppu::NMT_H : Ppu::NMT_V ); } void Tc0190fmcPal16r4::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Tc0190fmc::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardTaitoTc0190fmcPal16r4.hpp000066400000000000000000000035531411157722000245350ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_TAITO_TC0190FMCPAL16R4_H #define NST_BOARD_TAITO_TC0190FMCPAL16R4_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardMmc3.hpp" #include "NstBoardTaitoTc0190fmc.hpp" namespace Nes { namespace Core { namespace Boards { namespace Taito { class Tc0190fmcPal16r4 : public Tc0190fmc { public: explicit Tc0190fmcPal16r4(const Context&); private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Sync(Event,Input::Controllers*); enum { IRQ_DELAY = 2 }; NES_DECL_POKE( C000 ); NES_DECL_POKE( C001 ); NES_DECL_POKE( C002 ); NES_DECL_POKE( C003 ); NES_DECL_POKE( E000 ); Mmc3::Irq irq; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardTaitoX1005.cpp000066400000000000000000000112411411157722000226160ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstBoard.hpp" #include "NstBoardTaitoX1005.hpp" #include "../NstFile.hpp" namespace Nes { namespace Core { namespace Boards { namespace Taito { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif X1005::X1005(const Context& c) : Board(c), version(DetectVersion(c)) { std::memset( ram, 0, sizeof(ram) ); } X1005::Version X1005::DetectVersion(const Context& c) { if (const Chips::Type* const type = c.chips.Find(L"X1-005")) { if (type->Pin(17).C(L"CIRAM").A() == 10 && type->Pin(31) == L"NC") return VERSION_B; } return VERSION_A; } void X1005::SubReset(const bool hard) { if (hard) security = 0; if (version == VERSION_A) { Map( 0x7EF0U, 0x7EF1U, &X1005::Poke_7EF0_0 ); Map( 0x7EF2U, CHR_SWAP_1K_4 ); Map( 0x7EF3U, CHR_SWAP_1K_5 ); Map( 0x7EF4U, CHR_SWAP_1K_6 ); Map( 0x7EF5U, CHR_SWAP_1K_7 ); Map( 0x7EF6U, 0x7EF7U, NMT_SWAP_VH ); ppu.SetMirroring( Ppu::NMT_H ); } else { Map( 0x7EF0U, 0x7EF1U, &X1005::Poke_7EF0_1 ); Map( 0x7EF2U, 0x7EF5U, &X1005::Poke_7EF2 ); ppu.SetMirroring( Ppu::NMT_0 ); } Map( 0x7EF8U, 0x7EF9U, &X1005::Peek_7EF8, &X1005::Poke_7EF8 ); Map( 0x7EFAU, 0x7EFBU, PRG_SWAP_8K_0 ); Map( 0x7EFCU, 0x7EFDU, PRG_SWAP_8K_1 ); Map( 0x7EFEU, 0x7EFFU, PRG_SWAP_8K_2 ); Map( 0x7F00U, 0x7FFFU, &X1005::Peek_7F00, &X1005::Poke_7F00 ); } void X1005::Load(File& file) { if (board.HasBattery()) file.Load( File::BATTERY, ram, sizeof(ram) ); } void X1005::Save(File& file) const { if (board.HasBattery()) file.Save( File::BATTERY, ram, sizeof(ram) ); } void X1005::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'T','X','1'>::V) ); if (baseChunk == AsciiId<'T','X','1'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: security = state.Read8(); break; case AsciiId<'R','A','M'>::V: state.Uncompress( ram ); break; } state.End(); } } } void X1005::SubSave(State::Saver& state) const { state.Begin( AsciiId<'T','X','1'>::V ); state.Begin( AsciiId<'R','E','G'>::V ).Write8( security ).End(); state.Begin( AsciiId<'R','A','M'>::V ).Compress( ram ).End(); state.End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(X1005,7EF0_0) { ppu.Update(); chr.SwapBank( address << 11 & 0x800, data >> 1 ); } NES_POKE_AD(X1005,7EF0_1) { ppu.SetMirroring( (data & 0x80) ? Ppu::NMT_1 : Ppu::NMT_0 ); chr.SwapBank( address << 11 & 0x800, data >> 1 ); } NES_POKE_AD(X1005,7EF2) { ppu.SetMirroring( (data & 0x80) ? Ppu::NMT_1 : Ppu::NMT_0 ); chr.SwapBank( 0x1000 | (address - 0x7EF2) << 10, data ); } NES_PEEK(X1005,7EF8) { return security; } NES_POKE_D(X1005,7EF8) { security = data; } NES_PEEK_A(X1005,7F00) { NST_VERIFY( security == SECURITY_DATA ); return (security == SECURITY_DATA) ? ram[address & 0x7F] : (address >> 8); } NES_POKE_AD(X1005,7F00) { NST_VERIFY( security == SECURITY_DATA ); if (security == SECURITY_DATA) ram[address & 0x7F] = data; } } } } } nestopia-1.51.1/source/core/board/NstBoardTaitoX1005.hpp000066400000000000000000000037651411157722000226370ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_TAITO_X1005_H #define NST_BOARD_TAITO_X1005_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Taito { class X1005 : public Board { public: explicit X1005(const Context&); private: enum Version { VERSION_A, VERSION_B }; enum { SECURITY_DATA = 0xA3 }; void SubReset(bool); void Load(File&); void Save(File&) const; void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); static Version DetectVersion(const Context&); NES_DECL_POKE( 7EF0_0 ); NES_DECL_POKE( 7EF0_1 ); NES_DECL_POKE( 7EF2 ); NES_DECL_PEEK( 7EF8 ); NES_DECL_POKE( 7EF8 ); NES_DECL_PEEK( 7F00 ); NES_DECL_POKE( 7F00 ); uint security; byte ram[0x80]; const Version version; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardTaitoX1017.cpp000066400000000000000000000126071411157722000226300ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstBoard.hpp" #include "NstBoardTaitoX1017.hpp" #include "../NstFile.hpp" namespace Nes { namespace Core { namespace Boards { namespace Taito { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif X1017::X1017(const Context& c) : Board(c) { std::memset( ram, 0, sizeof(ram) ); } void X1017::SubReset(const bool hard) { if (hard) { regs.ctrl = 0; regs.security[0] = 0; regs.security[1] = 0; regs.security[2] = 0; regs.unused[0] = 0; regs.unused[1] = 0; regs.unused[2] = 0; StoreChr(); } Map( 0x6000U, 0x73FFU, &X1017::Peek_6000, &X1017::Poke_6000 ); Map( 0x7EF0U, 0x7EF1U, &X1017::Poke_7EF0 ); Map( 0x7EF2U, 0x7EF5U, &X1017::Poke_7EF2 ); Map( 0x7EF6U, &X1017::Poke_7EF6 ); Map( 0x7EF7U, 0x7EF9U, &X1017::Poke_7EF7 ); Map( 0x7EFAU, &X1017::Poke_7EFA ); Map( 0x7EFBU, &X1017::Poke_7EFB ); Map( 0x7EFCU, &X1017::Poke_7EFC ); Map( 0x7EFDU, 0x7EFFU, &X1017::Poke_7EFD ); } void X1017::StoreChr() { for (uint i=0; i < 2; ++i) regs.chr[i] = chr.GetBank( i << 11 ); for (uint i=2; i < 6; ++i) regs.chr[i] = chr.GetBank( 0x1000 | (i - 2) << 10 ); } void X1017::Load(File& file) { if (board.HasBattery()) file.Load( File::BATTERY, ram, sizeof(ram) ); } void X1017::Save(File& file) const { if (board.HasBattery()) file.Save( File::BATTERY, ram, sizeof(ram) ); } void X1017::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'T','1','7'>::V) ); if (baseChunk == AsciiId<'T','1','7'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: { State::Loader::Data<7> data( state ); regs.ctrl = data[0]; regs.security[0] = data[1]; regs.security[1] = data[2]; regs.security[2] = data[3]; regs.unused[0] = data[4]; regs.unused[1] = data[5]; regs.unused[2] = data[6]; break; } case AsciiId<'R','A','M'>::V: state.Uncompress( ram ); break; } state.End(); } } StoreChr(); } void X1017::SubSave(State::Saver& state) const { state.Begin( AsciiId<'T','1','7'>::V ); const byte data[7] = { regs.ctrl, regs.security[0], regs.security[1], regs.security[2], regs.unused[0], regs.unused[1], regs.unused[2] }; state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End(); state.Begin( AsciiId<'R','A','M'>::V ).Compress( ram ).End(); state.End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void X1017::UpdateChr() const { ppu.Update(); const uint swap = regs.ctrl << 11 & 0x1000; chr.SwapBanks( 0x0000 ^ swap, regs.chr[0], regs.chr[1] ); chr.SwapBanks( 0x1000 ^ swap, regs.chr[2], regs.chr[3], regs.chr[4], regs.chr[5] ); } NES_PEEK_A(X1017,6000) { return ram[address - 0x6000]; } NES_POKE_AD(X1017,6000) { ram[address - 0x6000] = data; } NES_POKE_AD(X1017,7EF2) { address &= 0x7; if (regs.chr[address] != data) { regs.chr[address] = data; UpdateChr(); } } NES_POKE_AD(X1017,7EF0) { NES_DO_POKE( 7EF2, address, data >> 1 ); } NES_POKE_D(X1017,7EF6) { if (regs.ctrl != data) { regs.ctrl = data; UpdateChr(); ppu.SetMirroring( (regs.ctrl & 0x1) ? Ppu::NMT_V : Ppu::NMT_H ); } } NES_POKE_AD(X1017,7EF7) { regs.security[address - 0x7EF7] = data; } NES_POKE_D(X1017,7EFA) { prg.SwapBank( data >> 2 ); } NES_POKE_D(X1017,7EFB) { prg.SwapBank( data >> 2 ); } NES_POKE_D(X1017,7EFC) { prg.SwapBank( data >> 2 ); } NES_POKE_AD(X1017,7EFD) { regs.unused[address - 0x7EFD] = data; } } } } } nestopia-1.51.1/source/core/board/NstBoardTaitoX1017.hpp000066400000000000000000000043371411157722000226360ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_TAITO_X1017_H #define NST_BOARD_TAITO_X1017_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Taito { class X1017 : public Board { public: explicit X1017(const Context&); private: void SubReset(bool); void Load(File&); void Save(File&) const; void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void StoreChr(); void UpdateChr() const; enum { SECURITY_2K_0_0 = 0xCA, SECURITY_2K_0_1 = 0x69, SECURITY_1K_0_2 = 0x84, SECURITY_2K_1_0 = 0x35, SECURITY_2K_1_1 = 0x96, SECURITY_1K_1_2 = 0x7B }; NES_DECL_PEEK( 6000 ); NES_DECL_POKE( 6000 ); NES_DECL_POKE( 7EF0 ); NES_DECL_POKE( 7EF2 ); NES_DECL_POKE( 7EF6 ); NES_DECL_POKE( 7EF7 ); NES_DECL_POKE( 7EFA ); NES_DECL_POKE( 7EFB ); NES_DECL_POKE( 7EFC ); NES_DECL_POKE( 7EFD ); struct { uint ctrl; byte security[3]; byte unused[3]; byte chr[6]; } regs; byte ram[SIZE_5K]; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardTengen.cpp000066400000000000000000000044141411157722000223240ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstTimer.hpp" #include "NstBoard.hpp" #include "NstBoardNRom.hpp" #include "NstBoardNamcot.hpp" #include "NstBoardSunsoft.hpp" #include "NstBoardTengen.hpp" namespace Nes { namespace Core { namespace Boards { namespace Tengen { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void T800008::SubReset(bool) { Map( 0x8000U, 0xFFFFU, &T800008::Poke_8000 ); } void T800037::SubReset(const bool hard) { Rambo1::SubReset( hard ); for (uint i=0x0000; i < 0x1000; i += 0x2) Map( 0xA000 + i, NOP_POKE ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(T800008,8000) { ppu.Update(); data = GetBusData(address,data); chr.SwapBank( data ); prg.SwapBank( data >> 3 ); } void T800037::UpdateChr() const { Rambo1::UpdateChr(); nmt.SwapBanks ( regs.chr[(regs.ctrl & 0x80U) ? 2 : 0] >> 7 ^ 1U, regs.chr[(regs.ctrl & 0x80U) ? 3 : 0] >> 7 ^ 1U, regs.chr[(regs.ctrl & 0x80U) ? 4 : 1] >> 7 ^ 1U, regs.chr[(regs.ctrl & 0x80U) ? 5 : 1] >> 7 ^ 1U ); } } } } } nestopia-1.51.1/source/core/board/NstBoardTengen.hpp000066400000000000000000000036171411157722000223350ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_TENGEN_H #define NST_BOARD_TENGEN_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardTengenRambo1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Tengen { typedef Namcot::N34x3 Mimic1; typedef Sunsoft::S4 T337007; typedef Mimic1 T800002; typedef Mimic1 T800004; typedef Mimic1 T800030; typedef Rambo1 T800032; typedef T337007 T800042; class T800008 : public Board { public: explicit T800008(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; class T800037 : public Rambo1 { public: explicit T800037(const Context& c) : Rambo1(c) {} private: void SubReset(bool); void UpdateChr() const; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardTengenRambo1.cpp000066400000000000000000000170671411157722000233760ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardTengenRambo1.hpp" namespace Nes { namespace Core { namespace Boards { namespace Tengen { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Rambo1::Irq::Irq(Cpu& cpu,Ppu& ppu) : a12 ( cpu, ppu, unit ), m2 ( cpu, unit ) {} Rambo1::Rambo1(const Context& c) : Board (c), irq (*c.cpu,*c.ppu) {} void Rambo1::Irq::Unit::Reset(const bool hard) { if (hard) { count = 0; cycles = 0; reload = false; latch = 0; enabled = false; } } void Rambo1::Regs::Reset() { for (uint i=0; i < 8; ++i) chr[i] = i; for (uint i=0; i < 3; ++i) prg[i] = i; ctrl = 0; } void Rambo1::SubReset(const bool hard) { irq.a12.Reset( hard, !irq.m2.Connected() ); irq.m2.Reset( hard, irq.m2.Connected() ); if (hard) regs.Reset(); for (uint i=0x0000; i < 0x1000; i += 0x2) { Map( 0x8000 + i, &Rambo1::Poke_8000 ); Map( 0x8001 + i, &Rambo1::Poke_8001 ); Map( 0xA000 + i, NMT_SWAP_HV ); Map( 0xC000 + i, &Rambo1::Poke_C000 ); Map( 0xC001 + i, &Rambo1::Poke_C001 ); Map( 0xE000 + i, &Rambo1::Poke_E000 ); Map( 0xE001 + i, &Rambo1::Poke_E001 ); } UpdateChr(); UpdatePrg(); } void Rambo1::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'T','R','1'>::V) ); if (baseChunk == AsciiId<'T','R','1'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: { State::Loader::Data<1+8+3> data( state ); regs.ctrl = data[0]; for (uint i=0; i < 3; ++i) regs.prg[i] = data[1+i]; for (uint i=0; i < 8; ++i) regs.chr[i] = data[1+3+i]; break; } case AsciiId<'I','R','Q'>::V: { State::Loader::Data<4> data( state ); irq.unit.enabled = data[0] & 0x1; irq.unit.mode = data[0] & 0x2 ? 1 : 0; irq.a12.Connect( data[0] & 0x2 ); irq.m2.Connect( data[0] & 0x2 ); irq.unit.reload = data[0] & 0x4; irq.unit.latch = data[1]; irq.unit.count = data[2]; irq.unit.cycles = data[3]; break; } } state.End(); } } } void Rambo1::SubSave(State::Saver& state) const { state.Begin( AsciiId<'T','R','1'>::V ); { const byte data[1+8+3] = { regs.ctrl, regs.prg[0], regs.prg[1], regs.prg[2], regs.chr[0], regs.chr[1], regs.chr[2], regs.chr[3], regs.chr[4], regs.chr[5], regs.chr[6], regs.chr[7] }; state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End(); } { const byte data[4] = { (irq.unit.enabled ? 0x1U : 0x0U) | (irq.m2.Connected() ? 0x2U : 0x0U) | (irq.unit.reload ? 0x4U : 0x0U), irq.unit.latch, irq.unit.count & 0xFF, irq.unit.cycles, }; state.Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End(); } state.End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif bool Rambo1::Irq::Unit::Clock() { cycles++; if (latch == 1) { count = 0; } else if (reload) { reload = false; count = latch | (latch ? 1 : 0); if (mode) count |= 2; if (!latch && cycles > A12_FILTER) count = 1; else if (latch && (cycles > (A12_FILTER * 3))) count++; cycles = 0; } else if (!count) { count = latch; if (cycles > A12_FILTER) cycles = 0; } else { count--; } return (!count && enabled); } void Rambo1::Irq::Update() { a12.Update(); m2.Update(); } void Rambo1::UpdatePrg() { prg.SwapBanks ( regs.prg[(regs.ctrl & 0x40U) ? 2 : 0], regs.prg[(regs.ctrl & 0x40U) ? 0 : 1], regs.prg[(regs.ctrl & 0x40U) ? 1 : 2], 0xFF ); } void Rambo1::UpdateChr() const { ppu.Update(); const uint offset = (regs.ctrl & 0x80U) << 5; if (regs.ctrl & 0x20U) chr.SwapBanks( offset, regs.chr[0], regs.chr[6], regs.chr[1], regs.chr[7] ); else chr.SwapBanks( offset, regs.chr[0] >> 1, regs.chr[1] >> 1 ); chr.SwapBanks( offset ^ 0x1000, regs.chr[2], regs.chr[3], regs.chr[4], regs.chr[5] ); } NES_POKE_D(Rambo1,8000) { const uint diff = regs.ctrl ^ data; regs.ctrl = data; if (diff & 0x40) UpdatePrg(); if (diff & (0x20|0x80)) UpdateChr(); } NES_POKE_D(Rambo1,8001) { const uint index = regs.ctrl & 0xFU; if (index < 0x6) { if (regs.chr[index] != data) { regs.chr[index] = data; UpdateChr(); } } else switch (index) { case 0x6: case 0x7: if (regs.prg[index - 0x6] != data) { regs.prg[index - 0x6] = data; UpdatePrg(); } break; case 0x8: case 0x9: if (regs.chr[index - 0x2] != data) { regs.chr[index - 0x2] = data; UpdateChr(); } break; case 0xF: if (regs.prg[2] != data) { regs.prg[2] = data; UpdatePrg(); } break; } } NES_POKE_D(Rambo1,C000) { irq.Update(); irq.unit.latch = data; irq.unit.mode = irq.m2.Connected(); } NES_POKE_D(Rambo1,C001) { irq.Update(); irq.unit.reload = true; data &= Irq::SOURCE; irq.a12.Connect( data == Irq::SOURCE_PPU ); irq.m2.Connect( data == Irq::SOURCE_CPU ); } NES_POKE(Rambo1,E000) { irq.Update(); irq.unit.enabled = false; cpu.ClearIRQ(); } NES_POKE(Rambo1,E001) { irq.Update(); irq.unit.enabled = true; } void Rambo1::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) { irq.a12.VSync(); irq.m2.VSync(); } Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardTengenRambo1.hpp000066400000000000000000000051561411157722000233770ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_TENGEN_RAMBO1_H #define NST_BOARD_TENGEN_RAMBO1_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "../NstTimer.hpp" namespace Nes { namespace Core { namespace Boards { namespace Tengen { class Rambo1 : public Board { public: explicit Rambo1(const Context&); protected: void SubReset(bool); virtual void UpdateChr() const; private: void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void UpdatePrg(); void Sync(Event,Input::Controllers*); NES_DECL_POKE( 8000 ); NES_DECL_POKE( 8001 ); NES_DECL_POKE( C000 ); NES_DECL_POKE( C001 ); NES_DECL_POKE( E000 ); NES_DECL_POKE( E001 ); struct Regs { void Reset(); byte chr[8]; byte prg[3]; byte ctrl; }; struct Irq { Irq(Cpu&,Ppu&); void Update(); enum { M2_CLOCK = 4, A12_FILTER = 16, IRQ_DELAY = 2, SOURCE_PPU = 0x0, SOURCE_CPU = 0x1, SOURCE = 0x1 }; struct Unit { void Reset(bool); bool Clock(); uint count; uint cycles; uint latch; ibool reload; ibool enabled; ibool mode; }; typedef Timer::A12 A12; typedef Timer::M2 M2; Unit unit; A12 a12; M2 m2; }; protected: Regs regs; private: Irq irq; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardTxRom.cpp000066400000000000000000000034721411157722000221600ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardTxRom.hpp" namespace Nes { namespace Core { namespace Boards { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void TksRom::SubReset(const bool hard) { Mmc3::SubReset( hard ); for (uint i=0x0000; i < 0x2000; i += 0x2) Map( 0xA000 + i, NOP_POKE ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void NST_FASTCALL TksRom::UpdateChr(uint address,uint bank) const { if (address < 0x1000) nmt.SwapBank( address, bank >> 7 ^ 0x1 ); Mmc3::UpdateChr( address, bank ); } void NST_FASTCALL TqRom::UpdateChr(uint address,uint bank) const { chr.Source( bank >> 6 & 0x1 ).SwapBank( address, bank ); } } } } nestopia-1.51.1/source/core/board/NstBoardTxRom.hpp000066400000000000000000000037341411157722000221660ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_TXROM_H #define NST_BOARD_TXROM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardMmc3.hpp" namespace Nes { namespace Core { namespace Boards { class TxRom : public Mmc3 { public: explicit TxRom(const Context& c) : Mmc3(c,c.chips.Has(L"MMC3A") ? REV_A : c.chips.Has(L"MMC3C") ? REV_C : REV_B) {} }; class TksRom : public Mmc3 { public: explicit TksRom(const Context& c) : Mmc3(c,c.chips.Has(L"MMC3A") ? REV_A : c.chips.Has(L"MMC3C") ? REV_C : REV_B) {} private: void SubReset(bool); void NST_FASTCALL UpdateChr(uint,uint) const; }; typedef TksRom TlsRom; class TqRom : public Mmc3 { public: explicit TqRom(const Context& c) : Mmc3(c,c.chips.Has(L"MMC3A") ? REV_A : c.chips.Has(L"MMC3C") ? REV_C : REV_B) {} private: void NST_FASTCALL UpdateChr(uint,uint) const; }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardTxc.cpp000066400000000000000000000061571411157722000216500ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardTxc.hpp" namespace Nes { namespace Core { namespace Boards { namespace Txc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void T22211A::SubReset(const bool hard) { Map( 0x4100U, &T22211A::Peek_4100 ); Map( 0x4100U, 0x4103U, &T22211A::Poke_4100 ); Map( 0x8000U, 0xFFFFU, &T22211A::Poke_8000 ); if (hard) { for (uint i=0; i < 4; ++i) regs[i] = 0; prg.SwapBank(0); } } void T22211B::SubReset(const bool hard) { T22211A::SubReset( hard ); Map( 0x8000U, 0xFFFFU, &T22211B::Poke_8000 ); } void T22211C::SubReset(const bool hard) { T22211A::SubReset( hard ); Map( 0x4100U, &T22211C::Peek_4100 ); } void T22211A::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'T','2','1'>::V) ); if (baseChunk == AsciiId<'T','2','1'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) state.Read( regs ); state.End(); } } } void T22211A::SubSave(State::Saver& state) const { state.Begin( AsciiId<'T','2','1'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( regs ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK(T22211A,4100) { return (uint(regs[1]) ^ regs[2]) | 0x40; } NES_PEEK(T22211C,4100) { return (uint(regs[1]) ^ regs[2]) | 0x41; } NES_POKE_AD(T22211A,4100) { regs[address & 0x3] = data; } NES_POKE(T22211A,8000) { ppu.Update(); prg.SwapBank( regs[2] >> 2 ); chr.SwapBank( regs[2] ); } NES_POKE_D(T22211B,8000) { ppu.Update(); prg.SwapBank( regs[2] >> 2 ); chr.SwapBank( ((data^regs[2]) >> 3 & 0x2) | ((data^regs[2]) >> 5 & 0x1) ); } } } } } nestopia-1.51.1/source/core/board/NstBoardTxc.hpp000066400000000000000000000042171411157722000216500ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_TXC_H #define NST_BOARD_TXC_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardMmc3.hpp" #include "NstBoardTxcTw.hpp" #include "NstBoardTxcMxmdhtwo.hpp" #include "NstBoardTxcPoliceman.hpp" namespace Nes { namespace Core { namespace Boards { namespace Txc { class T22211A : public Board { public: explicit T22211A(const Context& c) : Board(c) {} protected: void SubReset(bool); byte regs[4]; private: void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); NES_DECL_PEEK( 4100 ); NES_DECL_POKE( 4100 ); NES_DECL_POKE( 8000 ); }; class T22211B : public T22211A { public: explicit T22211B(const Context& c) : T22211A(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; class T22211C : public T22211A { public: explicit T22211C(const Context& c) : T22211A(c) {} private: void SubReset(bool); NES_DECL_PEEK( 4100 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardTxcMxmdhtwo.cpp000066400000000000000000000027651411157722000234010ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardTxcMxmdhtwo.hpp" namespace Nes { namespace Core { namespace Boards { namespace Txc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Mxmdhtwo::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, PRG_SWAP_32K ); if (hard) prg.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } } } nestopia-1.51.1/source/core/board/NstBoardTxcMxmdhtwo.hpp000066400000000000000000000026511411157722000234000ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_TXC_MXMDHTWO_H #define NST_BOARD_TXC_MXMDHTWO_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Txc { class Mxmdhtwo : public Board { public: explicit Mxmdhtwo(const Context& c) : Board(c) {} private: void SubReset(bool); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardTxcPoliceman.cpp000066400000000000000000000033121411157722000234660ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardTxcPoliceman.hpp" namespace Nes { namespace Core { namespace Boards { namespace Txc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Policeman::SubReset(const bool hard) { Map( 0x8400U, 0xFFFEU, &Policeman::Poke_8400 ); if (hard) prg.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(Policeman,8400) { ppu.Update(); data = GetBusData(address,data); prg.SwapBank( data >> 4 ); chr.SwapBank( data ); } } } } } nestopia-1.51.1/source/core/board/NstBoardTxcPoliceman.hpp000066400000000000000000000027161411157722000235020ustar00rootroot00000000000000 //////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_TXC_POLICEMAN_H #define NST_BOARD_TXC_POLICEMAN_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Txc { class Policeman : public Board { public: explicit Policeman(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8400 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardTxcTw.cpp000066400000000000000000000033141411157722000221530ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardTxc.hpp" namespace Nes { namespace Core { namespace Boards { namespace Txc { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Tw::SubReset(const bool hard) { Mmc3::SubReset( hard ); Map( 0x4120U, 0x7FFFU, &Tw::Poke_4120 ); if (hard) prg.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Tw,4120) { prg.SwapBank( (data >> 4) | data ); } void NST_FASTCALL Tw::UpdatePrg(uint,uint) { // 4120..7FFF controlled } } } } } nestopia-1.51.1/source/core/board/NstBoardTxcTw.hpp000066400000000000000000000027361411157722000221670ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_TXC_TW_H #define NST_BOARD_TXC_TW_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Txc { class Tw : public Mmc3 { public: explicit Tw(const Context& c) : Mmc3(c) {} private: void SubReset(bool); void NST_FASTCALL UpdatePrg(uint,uint); NES_DECL_POKE( 4120 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardUnlA9746.cpp000066400000000000000000000077601411157722000223040ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardUnlA9746.hpp" namespace Nes { namespace Core { namespace Boards { namespace Unlicensed { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void A9746::SubReset(const bool hard) { exRegs[0] = 0; exRegs[1] = 0; exRegs[2] = 0; Mmc3::SubReset( hard ); for (uint i=0x8000; i < 0xA000; i += 0x4) { Map( i + 0x0, &A9746::Poke_8000 ); Map( i + 0x1, &A9746::Poke_8001 ); Map( i + 0x2, &A9746::Poke_8002 ); Map( i + 0x3, NOP_POKE ); } } void A9746::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'A','9','7'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<3> data( state ); exRegs[0] = data[0]; exRegs[1] = data[1]; exRegs[2] = data[2] << 4; } state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void A9746::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); const byte data[] = { exRegs[0], exRegs[1], exRegs[2] >> 4 }; state.Begin( AsciiId<'A','9','7'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(A9746,8000) { exRegs[0] = 0; exRegs[1] = data; } NES_POKE_D(A9746,8001) { ppu.Update(); if (exRegs[0] - 0x23 < 4) { prg.SwapBank ( (exRegs[0] - 0x23) << 13 ^ 0x6000, (data >> 5 & 0x1) | (data >> 3 & 0x2) | (data >> 1 & 0x4) | (data << 1 & 0x8) ); } switch (exRegs[1]) { case 0x08: case 0x0A: case 0x0E: case 0x12: case 0x16: case 0x1A: case 0x1E: exRegs[2] = data << 4; break; case 0x09: chr.SwapBank( exRegs[2] | (data >> 1 & 0xE) ); break; case 0x0B: chr.SwapBank( exRegs[2] | (data >> 1 | 0x1) ); break; case 0x0C: case 0x0D: chr.SwapBank( exRegs[2] | (data >> 1 & 0xE) ); break; case 0x0F: chr.SwapBank( exRegs[2] | (data >> 1 | 0x1) ); break; case 0x10: case 0x11: chr.SwapBank( exRegs[2] | (data >> 1 & 0xF) ); break; case 0x14: case 0x15: chr.SwapBank( exRegs[2] | (data >> 1 & 0xF) ); break; case 0x18: case 0x19: chr.SwapBank( exRegs[2] | (data >> 1 & 0xF) ); break; case 0x1C: case 0x1D: chr.SwapBank( exRegs[2] | (data >> 1 & 0xF) ); break; } } NES_POKE_AD(A9746,8002) { exRegs[0] = data; exRegs[1] = 0; } } } } } nestopia-1.51.1/source/core/board/NstBoardUnlA9746.hpp000066400000000000000000000033161411157722000223020ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_UNL_A9746_H #define NST_BOARD_UNL_A9746_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Unlicensed { class A9746 : public Mmc3 { public: explicit A9746(const Context& c) : Mmc3(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void NST_FASTCALL UpdatePrg(uint,uint) {} void NST_FASTCALL UpdateChr(uint,uint) const {} NES_DECL_POKE( 8000 ); NES_DECL_POKE( 8001 ); NES_DECL_POKE( 8002 ); uint exRegs[3]; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardUnlCc21.cpp000066400000000000000000000032001411157722000222430ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardUnlCc21.hpp" namespace Nes { namespace Core { namespace Boards { namespace Unlicensed { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Cc21::SubReset(bool) { Map( 0x8000U, 0xFFFFU, &Cc21::Poke_8000 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_A(Cc21,8000) { ppu.SetMirroring( (address & 0x2) ? Ppu::NMT_1 : Ppu::NMT_0 ); chr.SwapBank( address ); chr.SwapBank( address ); } } } } } nestopia-1.51.1/source/core/board/NstBoardUnlCc21.hpp000066400000000000000000000026771411157722000222710ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_UNL_CC21_H #define NST_BOARD_UNL_CC21_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Unlicensed { class Cc21 : public Board { public: explicit Cc21(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardUnlEdu2000.cpp000066400000000000000000000035761411157722000226120ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardUnlEdu2000.hpp" namespace Nes { namespace Core { namespace Boards { namespace Unlicensed { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Edu2000::SubReset(const bool hard) { Map( 0x6000U, 0x7FFFU, &Edu2000::Peek_6000, &Edu2000::Poke_6000 ); Map( 0x8000U, 0xFFFFU, &Edu2000::Poke_8000 ); if (hard) NES_DO_POKE(8000,0x8000,0x00); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(Edu2000,6000) { return wrk[0][address - 0x6000]; } NES_POKE_AD(Edu2000,6000) { wrk[0][address - 0x6000] = data; } NES_POKE_D(Edu2000,8000) { prg.SwapBank( data ); wrk.SwapBank( data >> 6 ); } } } } } nestopia-1.51.1/source/core/board/NstBoardUnlEdu2000.hpp000066400000000000000000000030051411157722000226020ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_UNL_EDU2000_H #define NST_BOARD_UNL_EDU2000_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Unlicensed { class Edu2000 : public Board { public: explicit Edu2000(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_PEEK( 6000 ); NES_DECL_POKE( 6000 ); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardUnlKingOfFighters96.cpp000066400000000000000000000103461411157722000246140ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardUnlKingOfFighters96.hpp" namespace Nes { namespace Core { namespace Boards { namespace Unlicensed { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void KingOfFighters96::SubReset(const bool hard) { for (uint i=0; i < 4; ++i) exRegs[i] = 0; Mmc3::SubReset( hard ); Map( 0x5000U, &KingOfFighters96::Peek_5000, &KingOfFighters96::Poke_5000 ); Map( 0x5001U, 0x5FFFU, &KingOfFighters96::Peek_5000, &KingOfFighters96::Poke_5001 ); for (uint i=0x8000; i < 0xA000; i += 0x4) { Map( i + 0x0, &KingOfFighters96::Poke_8000 ); Map( i + 0x1, &KingOfFighters96::Poke_8001 ); Map( i + 0x2, NOP_POKE ); Map( i + 0x3, &KingOfFighters96::Poke_8003 ); } } void KingOfFighters96::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'U','K','6'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) state.Read( exRegs ); state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void KingOfFighters96::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); state.Begin( AsciiId<'U','K','6'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( exRegs ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void NST_FASTCALL KingOfFighters96::UpdatePrg(uint address,uint bank) { if (!(exRegs[0] & 0x80U)) prg.SwapBank( address, bank ); } void NST_FASTCALL KingOfFighters96::UpdateChr(uint address,uint bank) const { if ((address & 0x1000) == (regs.ctrl0 << 5 & 0x1000)) bank |= 0x100; chr.SwapBank( address, bank ); } NES_PEEK(KingOfFighters96,5000) { static const byte security[4] = { 0x83,0x83,0x42,0x00 }; return security[exRegs[1] & 0x3U]; } NES_POKE_D(KingOfFighters96,5000) { exRegs[1] = data; if (exRegs[0] != data) { exRegs[0] = data; if (exRegs[0] & 0x80U) { const uint bank = exRegs[0] & 0x1FU; if (exRegs[0] & 0x20U) prg.SwapBank( bank >> 2 ); else prg.SwapBanks( bank, bank ); } else { Mmc3::UpdatePrg(); } } } NES_POKE_D(KingOfFighters96,5001) { exRegs[1] = data; if (!exRegs[3]) { exRegs[3] = true; cpu.Poke( 0x4017, 0x40 ); } } NES_POKE_AD(KingOfFighters96,8000) { exRegs[2] = true; Mmc3::NES_DO_POKE(8000,address,data); } NES_POKE_AD(KingOfFighters96,8001) { if (exRegs[2]) Mmc3::NES_DO_POKE(8001,address,data); } NES_POKE_D(KingOfFighters96,8003) { exRegs[2] = false; if (data == 0x28) { prg.SwapBank( 0x17 ); } else if (data == 0x2A) { prg.SwapBank( 0x0F ); } } } } } } nestopia-1.51.1/source/core/board/NstBoardUnlKingOfFighters96.hpp000066400000000000000000000035151411157722000246210ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_UNL_KINGOFFIGHTERS96_H #define NST_BOARD_UNL_KINGOFFIGHTERS96_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Unlicensed { class KingOfFighters96 : public Mmc3 { public: explicit KingOfFighters96(const Context& c) : Mmc3(c) {} private: void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void SubReset(bool); void NST_FASTCALL UpdateChr(uint,uint) const; void NST_FASTCALL UpdatePrg(uint,uint); NES_DECL_PEEK( 5000 ); NES_DECL_POKE( 5000 ); NES_DECL_POKE( 5001 ); NES_DECL_POKE( 8000 ); NES_DECL_POKE( 8001 ); NES_DECL_POKE( 8003 ); byte exRegs[4]; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardUnlKingOfFighters97.cpp000066400000000000000000000064411411157722000246160ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardUnlKingOfFighters97.hpp" namespace Nes { namespace Core { namespace Boards { namespace Unlicensed { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void KingOfFighters97::SubReset(const bool hard) { Mmc3::SubReset( hard ); for (uint i=0x0000; i < 0x2000; i += 0x2) { Map( 0x8000 + i, &KingOfFighters97::Poke_8000 ); Map( 0x8001 + i, &KingOfFighters97::Poke_8001 ); Map( 0xC000 + i, &KingOfFighters97::Poke_C000 ); Map( 0xC001 + i, &KingOfFighters97::Poke_C001 ); } Map( 0x9000U, &KingOfFighters97::Poke_8001 ); Map( 0xA000U, &KingOfFighters97::Poke_A000 ); Map( 0xB000U, &KingOfFighters97::Poke_A001 ); Map( 0xD000U, &KingOfFighters97::Poke_C001 ); for (uint i=0x0000; i < 0x1000; i += 0x2) { Map( 0xE000 + i, &KingOfFighters97::Poke_E000 ); Map( 0xE001 + i, &KingOfFighters97::Poke_E001 ); } Map( 0xF000U, &KingOfFighters97::Poke_E001 ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif uint KingOfFighters97::Unscramble(uint data) { return ( (data >> 1 & 0x01) | (data >> 4 & 0x02) | (data << 2 & 0x04) | (data >> 0 & 0xD8) | (data << 3 & 0x20) ); } NES_POKE_D(KingOfFighters97,8000) { Mmc3::NES_DO_POKE(8000,0x8000,Unscramble(data)); } NES_POKE_D(KingOfFighters97,8001) { Mmc3::NES_DO_POKE(8001,0x8001,Unscramble(data)); } NES_POKE_D(KingOfFighters97,A000) { ppu.SetMirroring( (data & 0x02) ? Ppu::NMT_H : Ppu::NMT_V ); } NES_POKE_D(KingOfFighters97,A001) { Mmc3::NES_DO_POKE(A001,0xA001,Unscramble(data)); } NES_POKE_D(KingOfFighters97,C000) { Mmc3::NES_DO_POKE(C000,0xC000,Unscramble(data)); } NES_POKE_D(KingOfFighters97,C001) { Mmc3::NES_DO_POKE(C001,0xC001,Unscramble(data)); } NES_POKE_D(KingOfFighters97,E000) { Mmc3::NES_DO_POKE(E000,0xE000,Unscramble(data)); } NES_POKE_D(KingOfFighters97,E001) { Mmc3::NES_DO_POKE(E001,0xE001,Unscramble(data)); } } } } } nestopia-1.51.1/source/core/board/NstBoardUnlKingOfFighters97.hpp000066400000000000000000000033361411157722000246230ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_UNL_KINGOFFIGHTERS97_H #define NST_BOARD_UNL_KINGOFFIGHTERS97_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Unlicensed { class KingOfFighters97 : public Mmc3 { public: explicit KingOfFighters97(const Context& c) : Mmc3(c) {} private: void SubReset(bool); static uint Unscramble(uint); NES_DECL_POKE( 8000 ); NES_DECL_POKE( 8001 ); NES_DECL_POKE( A000 ); NES_DECL_POKE( A001 ); NES_DECL_POKE( C000 ); NES_DECL_POKE( C001 ); NES_DECL_POKE( E000 ); NES_DECL_POKE( E001 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardUnlMortalKombat2.cpp000066400000000000000000000057511411157722000242460ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardUnlMortalKombat2.hpp" namespace Nes { namespace Core { namespace Boards { namespace Unlicensed { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif MortalKombat2::MortalKombat2(const Context& c) : Board(c), irq(*c.cpu,*c.ppu,false) {} void MortalKombat2::SubReset(const bool hard) { irq.Reset( hard ); for (uint i=0x0000; i < 0x1000; i += 0x4) { Map( 0x6000 + i, CHR_SWAP_2K_0 ); Map( 0x6001 + i, CHR_SWAP_2K_1 ); Map( 0x6002 + i, CHR_SWAP_2K_2 ); Map( 0x6003 + i, CHR_SWAP_2K_3 ); Map( 0x7000 + i, PRG_SWAP_8K_0 ); Map( 0x7001 + i, PRG_SWAP_8K_1 ); Map( 0x7002 + i, &MortalKombat2::Poke_7002 ); Map( 0x7003 + i, &MortalKombat2::Poke_7003 ); } } void MortalKombat2::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'U','M','2'>::V) ); if (baseChunk == AsciiId<'U','M','2'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'I','R','Q'>::V) irq.unit.LoadState( state ); state.End(); } } } void MortalKombat2::SubSave(State::Saver& state) const { state.Begin( AsciiId<'U','M','2'>::V ); irq.unit.SaveState( state, AsciiId<'I','R','Q'>::V ); state.End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE(MortalKombat2,7002) { irq.Update(); irq.unit.Disable( cpu ); irq.unit.SetLatch( 0 ); } NES_POKE(MortalKombat2,7003) { irq.Update(); irq.unit.Enable(); irq.unit.SetLatch( 7 ); } void MortalKombat2::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardUnlMortalKombat2.hpp000066400000000000000000000032031411157722000242410ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_UNL_MORTALKOMBAT2_H #define NST_BOARD_UNL_MORTALKOMBAT2_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Unlicensed { class MortalKombat2 : public Board { public: explicit MortalKombat2(const Context&); private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Sync(Event,Input::Controllers*); NES_DECL_POKE( 7002 ); NES_DECL_POKE( 7003 ); Mmc3::Irq<> irq; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardUnlN625092.cpp000066400000000000000000000060061411157722000224470ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardUnlN625092.hpp" namespace Nes { namespace Core { namespace Boards { namespace Unlicensed { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void N625092::SubReset(const bool hard) { Map( 0x8000U, 0xBFFFU, &N625092::Poke_8000 ); Map( 0xC000U, 0xFFFFU, &N625092::Poke_C000 ); if (hard) { regs[0] = 0; regs[1] = 0; UpdatePrg(); } } void N625092::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'N','6','2'>::V) ); if (baseChunk == AsciiId<'N','6','2'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<2> data( state ); regs[0] = data[0]; regs[1] = data[1]; } state.End(); } } } void N625092::SubSave(State::Saver& state) const { const byte data[] = { regs[0], regs[1] }; state.Begin( AsciiId<'N','6','2'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void N625092::UpdatePrg() { prg.SwapBanks ( (regs[0] >> 1 & 0x38) | ((regs[0] & 0x1) ? (regs[0] & 0x80) ? regs[1] : (regs[1] & 0x6) | 0x0 : regs[1]), (regs[0] >> 1 & 0x38) | ((regs[0] & 0x1) ? (regs[0] & 0x80) ? 0x7 : (regs[1] & 0x6) | 0x1 : regs[1]) ); } NES_POKE_A(N625092,8000) { ppu.SetMirroring( (address & 0x1) ? Ppu::NMT_H : Ppu::NMT_V ); address = address >> 1 & 0xFF; if (regs[0] != address) { regs[0] = address; UpdatePrg(); } } NES_POKE_A(N625092,C000) { address &= 0x7; if (regs[1] != address) { regs[1] = address; UpdatePrg(); } } } } } } nestopia-1.51.1/source/core/board/NstBoardUnlN625092.hpp000066400000000000000000000031511411157722000224520ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_UNL_N625092_H #define NST_BOARD_UNL_N625092_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Unlicensed { class N625092 : public Board { public: explicit N625092(const Context& c) : Board(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void UpdatePrg(); NES_DECL_POKE( 8000 ); NES_DECL_POKE( C000 ); uint regs[2]; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardUnlSuperFighter3.cpp000066400000000000000000000030721411157722000242540ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardUnlSuperFighter3.hpp" namespace Nes { namespace Core { namespace Boards { namespace Unlicensed { void NST_FASTCALL SuperFighter3::UpdateChr(uint address,uint bank) const { switch (address) { case 0x0000: chr.SwapBank( bank >> 1 ); break; case 0x1000: chr.SwapBank( bank >> 0 ); break; case 0x1400: chr.SwapBank( bank >> 0 ); break; } } } } } } nestopia-1.51.1/source/core/board/NstBoardUnlSuperFighter3.hpp000066400000000000000000000027331411157722000242640ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_UNL_SUPERFIGHTER3_H #define NST_BOARD_UNL_SUPERFIGHTER3_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Unlicensed { class SuperFighter3 : public Mmc3 { public: explicit SuperFighter3(const Context& c) : Mmc3(c) {} private: void NST_FASTCALL UpdateChr(uint,uint) const; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardUnlTf1201.cpp000066400000000000000000000115611411157722000224410ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstTimer.hpp" #include "NstBoard.hpp" #include "NstBoardUnlTf1201.hpp" namespace Nes { namespace Core { namespace Boards { namespace Unlicensed { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Tf1201::Tf1201(const Context& c) : Board(c), irq(*c.cpu,*c.ppu) {} void Tf1201::Irq::Reset(bool) { enabled = false; count = 0; } void Tf1201::SubReset(const bool hard) { irq.Reset( true ); if (hard) prgSelect = 0; for (uint i=0x0000; i < 0x1000; i += 0x4) { Map( 0x8000 + i, &Tf1201::Poke_8000 ); Map( 0x9000 + i, NMT_SWAP_HV ); Map( 0x9001 + i, &Tf1201::Poke_9001 ); Map( 0xA000 + i, PRG_SWAP_8K_1 ); Map( 0xF000 + i, &Tf1201::Poke_F000 ); Map( 0xF001 + i, &Tf1201::Poke_F001 ); Map( 0xF002 + i, &Tf1201::Poke_F002 ); Map( 0xF003 + i, &Tf1201::Poke_F001 ); } for (uint i=0x0000; i < 0x3004; i += 0x4) { Map( 0xB000 + i, 0xB001 + i, &Tf1201::Poke_B000 ); Map( 0xB002 + i, 0xB003 + i, &Tf1201::Poke_B002 ); } } void Tf1201::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'U','T','2'>::V) ); if (baseChunk == AsciiId<'U','T','2'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: prgSelect = state.Read8(); break; case AsciiId<'I','R','Q'>::V: { State::Loader::Data<2> data( state ); irq.unit.enabled = data[0] & 0x1; irq.unit.count = data[2]; break; } } state.End(); } } } void Tf1201::SubSave(State::Saver& state) const { state.Begin( AsciiId<'U','T','2'>::V ); state.Begin( AsciiId<'R','E','G'>::V ).Write8( prgSelect ).End(); const byte data[2] = { irq.unit.enabled ? 0x1 : 0x0, irq.unit.count & 0xFF }; state.Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End(); state.End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Tf1201::UpdatePrg(uint bank) { prg.SwapBank( (prgSelect & 0x2) ? ~1U : bank ); prg.SwapBank( (prgSelect & 0x2) ? bank : ~1U ); } NES_POKE_D(Tf1201,8000) { UpdatePrg( data ); } NES_POKE_D(Tf1201,9001) { prgSelect = data; UpdatePrg( prg.GetBank() ); } NES_POKE_AD(Tf1201,B000) { ppu.Update(); address = (((address >> 11) - 6) | (address & 0x1)) << 10 & 0x1FFF; chr.SwapBank( address, (chr.GetBank(address) & 0xF0) | (data << 0 & 0x0F) ); } NES_POKE_AD(Tf1201,B002) { ppu.Update(); address = (((address >> 11) - 6) | (address & 0x1)) << 10 & 0x1FFF; chr.SwapBank( address, (chr.GetBank(address) & 0x0F) | (data << 4 & 0xF0) ); } NES_POKE_D(Tf1201,F000) { irq.Update(); irq.unit.count = (irq.unit.count & 0xF0) | (data << 0 & 0x0F); } NES_POKE_D(Tf1201,F002) { irq.Update(); irq.unit.count = (irq.unit.count & 0x0F) | (data << 4 & 0xF0); } NES_POKE_D(Tf1201,F001) { irq.Update(); irq.unit.enabled = data & 0x2; irq.ClearIRQ(); ppu.Update(); if (ppu.GetScanline() != Ppu::SCANLINE_VBLANK) irq.unit.count -= 8; } bool Tf1201::Irq::Clock() { return enabled && (++count & 0xFF) == 238; } void Tf1201::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardUnlTf1201.hpp000066400000000000000000000037701411157722000224510ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_UNL_TF1201_H #define NST_BOARD_UNL_TF1201_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Unlicensed { class Tf1201 : public Board { public: explicit Tf1201(const Context&); private: void SubReset(bool); void SubLoad(State::Loader&,dword); void SubSave(State::Saver&) const; void UpdatePrg(uint); void Sync(Event,Input::Controllers*); NES_DECL_POKE( 8000 ); NES_DECL_POKE( 9001 ); NES_DECL_POKE( B000 ); NES_DECL_POKE( B002 ); NES_DECL_POKE( F000 ); NES_DECL_POKE( F001 ); NES_DECL_POKE( F002 ); struct Irq { void Reset(bool); bool Clock(); enum { CLOCK_FILTER = 16 }; ibool enabled; uint count; }; uint prgSelect; Timer::A12 irq; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardUnlWorldHero.cpp000066400000000000000000000110321411157722000234620ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstTimer.hpp" #include "NstBoard.hpp" #include "NstBoardKonamiVrc4.hpp" #include "NstBoardUnlWorldHero.hpp" namespace Nes { namespace Core { namespace Boards { namespace Unlicensed { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif WorldHero::WorldHero(const Context& c) : Board(c), irq(*c.cpu) {} void WorldHero::SubReset(const bool hard) { if (hard) prgSwap = 0; irq.Reset( hard, hard ? false : irq.Connected() ); for (dword i=0x8000; i <= 0xFFFF; ++i) { switch (i & 0xF0C3) { case 0x8000: Map( i, &WorldHero::Poke_8000 ); break; case 0x9000: Map( i, NMT_SWAP_VH01 ); break; case 0x9002: case 0x9080: Map( i, &WorldHero::Poke_9000 ); break; case 0xA000: Map( i, PRG_SWAP_8K_1 ); break; case 0xB000: case 0xB001: case 0xB002: case 0xB003: case 0xC000: case 0xC001: case 0xC002: case 0xC003: case 0xD000: case 0xD001: case 0xD002: case 0xD003: case 0xE000: case 0xE001: case 0xE002: case 0xE003: Map( i, &WorldHero::Poke_B000 ); break; case 0xF000: Map( i, &WorldHero::Poke_F000 ); break; case 0xF001: Map( i, &WorldHero::Poke_F001 ); break; case 0xF002: Map( i, &WorldHero::Poke_F002 ); break; case 0xF003: Map( i, &WorldHero::Poke_F003 ); break; } } } void WorldHero::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'U','W','H'>::V) ); if (baseChunk == AsciiId<'U','W','H'>::V) { while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: prgSwap = state.Read8() & 0x2; break; case AsciiId<'I','R','Q'>::V: irq.LoadState( state ); break; } state.End(); } } } void WorldHero::SubSave(State::Saver& state) const { state.Begin( AsciiId<'U','W','H'>::V ); state.Begin( AsciiId<'R','E','G'>::V ).Write8( prgSwap ).End(); irq.SaveState( state, AsciiId<'I','R','Q'>::V ); state.End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(WorldHero,8000) { prg.SwapBank( prgSwap << 13, data ); } NES_POKE_D(WorldHero,9000) { data &= 0x2; if (prgSwap != data) { prgSwap = data; prg.SwapBanks ( prg.GetBank(), prg.GetBank() ); } } NES_POKE_AD(WorldHero,B000) { ppu.Update(); const bool part = address & 0x1; address = ((address - 0xB000) >> 1 & 0x1800) | (address << 9 & 0x0400); chr.SwapBank( address, (chr.GetBank(address) & (part ? 0x00F : 0xFF0)) | (part ? data << 4 : data & 0xF) ); } NES_POKE_D(WorldHero,F000) { irq.WriteLatch0( data ); } NES_POKE_D(WorldHero,F001) { irq.WriteLatch1( data ); } NES_POKE_D(WorldHero,F002) { irq.Toggle( data ); } NES_POKE(WorldHero,F003) { irq.Toggle(); } void WorldHero::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardUnlWorldHero.hpp000066400000000000000000000034361411157722000235000ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_UNL_WORLDHERO_H #define NST_BOARD_UNL_WORLDHERO_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Unlicensed { class WorldHero : public Board { public: explicit WorldHero(const Context&); private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Sync(Event,Input::Controllers*); NES_DECL_POKE( 8000 ); NES_DECL_POKE( 9000 ); NES_DECL_POKE( B000 ); NES_DECL_POKE( F000 ); NES_DECL_POKE( F001 ); NES_DECL_POKE( F002 ); NES_DECL_POKE( F003 ); Konami::Vrc4::Irq irq; uint prgSwap; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardUnlXzy.cpp000066400000000000000000000030511411157722000223510ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardUnlXzy.hpp" namespace Nes { namespace Core { namespace Boards { namespace Unlicensed { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Xzy::SubReset(bool) { Map( 0x5FF1U, &Xzy::Poke_5FF1 ); Map( 0x5FF2U, CHR_SWAP_8K ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Xzy,5FF1) { prg.SwapBank( data >> 1 ); } } } } } nestopia-1.51.1/source/core/board/NstBoardUnlXzy.hpp000066400000000000000000000026731411157722000223670ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_UNL_XZY_H #define NST_BOARD_UNL_XZY_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Unlicensed { class Xzy : public Board { public: explicit Xzy(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 5FF1 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardUxRom.cpp000066400000000000000000000046161411157722000221620ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardUxRom.hpp" namespace Nes { namespace Core { namespace Boards { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void UxRom::SubReset(bool) { switch (board.GetId()) { case Type::STD_UNROM: case Type::STD_UOROM: Map( PRG_SWAP_16K_0_BC ); break; case Type::STD_UN1ROM: Map( 0x8000U, 0xFFFFU, &UxRom::Poke_8000_D2 ); break; case Type::STD_UNROM512: Map( 0x8000U, 0xFFFFU, &UxRom::Poke_8000_0 ); hasbattery = board.HasBattery(); mirr = board.GetNmt(); switch (mirr) { case 0: ppu.SetMirroring( Ppu::NMT_H ); break; case 1: ppu.SetMirroring( Ppu::NMT_V ); break; } break; default: Map( 0x8000U, 0xFFFFU, PRG_SWAP_16K_0 ); break; } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(UxRom,8000_D2) { prg.SwapBank( GetBusData(address,data) >> 2 ); } NES_POKE_AD(UxRom,8000_0) { if (!hasbattery) data = GetBusData(address,data); chr.SwapBank( ( data >> 5) & 0x3 ); prg.SwapBank( ( data ) & 0x1f ); if ( mirr == Type::NMT_FOURSCREEN ) ppu.SetMirroring( ( data & 0x80 ) ? Ppu::NMT_1 : Ppu::NMT_0 ); } } } } nestopia-1.51.1/source/core/board/NstBoardUxRom.hpp000066400000000000000000000027241411157722000221650ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_UXROM_H #define NST_BOARD_UXROM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { class UxRom : public Board { public: explicit UxRom(const Context& c) : Board(c) {} private: uint mirr; uint hasbattery; void SubReset(bool); NES_DECL_POKE( 8000_D2 ); NES_DECL_POKE( 8000_0 ); }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardVsSystem.cpp000066400000000000000000000034341411157722000227020ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardVsSystem.hpp" namespace Nes { namespace Core { namespace Boards { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void VsSystem::SubReset(const bool hard) { p4016 = cpu.Map( 0x4016 ); cpu.Map( 0x4016 ).Set( this, &VsSystem::Peek_4016, &VsSystem::Poke_4016 ); if (hard) prg.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(VsSystem,4016) { ppu.Update(); chr.SwapBank( data >> 2 ); prg.SwapBank( data & 0x4 ); p4016.Poke( 0x4016, data ); } NES_PEEK_A(VsSystem,4016) { return p4016.Peek( address ); } } } } nestopia-1.51.1/source/core/board/NstBoardVsSystem.hpp000066400000000000000000000027141411157722000227070ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_VSSYSTEM_H #define NST_BOARD_VSSYSTEM_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { class VsSystem : public Board { public: explicit VsSystem(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 4016 ); NES_DECL_PEEK( 4016 ); Io::Port p4016; }; } } } #endif nestopia-1.51.1/source/core/board/NstBoardWaixing.cpp000066400000000000000000000172231411157722000225140ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstBoard.hpp" #include "NstBoardWaixing.hpp" namespace Nes { namespace Core { namespace Boards { namespace Waixing { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void TypeA::SubReset(const bool hard) { TypeI::SubReset( hard ); for (uint i=0x0000; i < 0x2000; i += 0x2) { Map( 0xA000 + i, NMT_SWAP_VH01 ); Map( 0xA001 + i, NOP_POKE ); } } void TypeF::SubReset(const bool hard) { exPrg[0] = 0x00; exPrg[1] = 0x01; exPrg[2] = 0x4E; exPrg[3] = 0x4F; TypeA::SubReset( hard ); for (uint i=0x0000; i < 0x2000; i += 0x2) Map( 0x8001 + i, &TypeF::Poke_8001 ); } void TypeG::SubReset(const bool hard) { exPrg[0] = 0x00; exPrg[1] = 0x01; exPrg[2] = 0x3E; exPrg[3] = 0x3F; for (uint i=0; i < 8; ++i) exChr[0] = i; TypeA::SubReset( hard ); for (uint i=0x0000; i < 0x2000; i += 0x2) Map( 0x8001 + i, &TypeG::Poke_8001 ); } void TypeH::SubReset(const bool hard) { exPrg = 0; Mmc3::SubReset( hard ); wrk.Source().SetSecurity( true, true ); for (uint i=0x0000; i < 0x2000; i += 0x2) { Map( 0x8001 + i, &TypeH::Poke_8001 ); Map( 0xA001 + i, NOP_POKE ); } } void TypeI::SubReset(const bool hard) { Mmc3::SubReset( hard ); wrk.Source().SetSecurity( true, true ); if (board.GetWram() >= SIZE_8K+SIZE_1K) Map( 0x5000U, 0x5000U + NST_MIN(board.GetWram(),SIZE_4K) - 1, &TypeI::Peek_5000, &TypeI::Poke_5000 ); } void TypeJ::SubReset(const bool hard) { if (hard) { exPrg[0] = 0x01; exPrg[1] = 0x02; exPrg[2] = 0x7E; exPrg[3] = 0x7F; } TypeI::SubReset( hard ); for (uint i=0x8001; i < 0xA000; i += 0x2) Map( i, &TypeJ::Poke_8001 ); } void TypeF::SubLoad(State::Loader& state,const dword baseChunk) { TypeA::SubLoad( state, baseChunk ); for (uint i=0x0000; i < 0x8000; i += 0x2000) exPrg[GetPrgIndex(i)] = prg.GetBank(i); } void TypeG::SubLoad(State::Loader& state,const dword baseChunk) { TypeA::SubLoad( state, baseChunk ); for (uint i=0x0000; i < 0x8000; i += 0x2000) exPrg[GetPrgIndex(i)] = prg.GetBank(i); for (uint i=0x0000; i < 0x2000; i += 0x0400) exChr[GetChrIndex(i)] = chr.GetBank(i); } void TypeH::SubLoad(State::Loader& state,const dword baseChunk) { Mmc3::SubLoad( state, baseChunk ); exPrg = prg.GetBank() | 0x40; } void TypeJ::SubLoad(State::Loader& state,const dword baseChunk) { TypeI::SubLoad( state, baseChunk ); for (uint i=0x0000; i < 0x8000; i += 0x2000) exPrg[GetPrgIndex(i)] = prg.GetBank(i); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(TypeI,5000) { return wrk.Source()[address-(0x5000-0x2000)]; } NES_POKE_AD(TypeI,5000) { wrk.Source()[address-(0x5000-0x2000)] = data; } NES_POKE_AD(TypeF,8001) { if ((regs.ctrl0 & 7) >= 6) exPrg[(regs.ctrl0 & 7) - 6] = data & (data >= 0x40 ? 0x4F : 0x3F); Mmc3::NES_DO_POKE(8001,address,data); } NES_POKE_D(TypeG,8001) { switch (regs.ctrl0 & 0xF) { case 0x0: exChr[0] = data; Mmc3::UpdateChr(); break; case 0x1: exChr[2] = data; Mmc3::UpdateChr(); break; case 0x2: exChr[4] = data; Mmc3::UpdateChr(); break; case 0x3: exChr[5] = data; Mmc3::UpdateChr(); break; case 0x4: exChr[6] = data; Mmc3::UpdateChr(); break; case 0x5: exChr[7] = data; Mmc3::UpdateChr(); break; case 0x6: exPrg[0] = data; Mmc3::UpdatePrg(); break; case 0x7: exPrg[1] = data; Mmc3::UpdatePrg(); break; case 0x8: exPrg[2] = data; Mmc3::UpdatePrg(); break; case 0x9: exPrg[3] = data; Mmc3::UpdatePrg(); break; case 0xA: exChr[1] = data; Mmc3::UpdateChr(); break; case 0xB: exChr[3] = data; Mmc3::UpdateChr(); break; } } NES_POKE_AD(TypeH,8001) { if (!(regs.ctrl0 & 0x7)) { uint reg = data << 5 & 0x40; if (exPrg != reg) { exPrg = reg; Mmc3::UpdatePrg(); } } Mmc3::NES_DO_POKE(8001,address,data); } NES_POKE_AD(TypeJ,8001) { const uint index = (regs.ctrl0 & 0x7); if (index >= 6 && exPrg[index-6] != data) { exPrg[index-6] = data; Mmc3::UpdatePrg(); } Mmc3::NES_DO_POKE(8001,address,data); } uint TypeI::GetPrgIndex(uint address) const { return address >> 13 ^ (regs.ctrl0 >> 5 & ~address >> 12 & 0x2); } uint TypeI::GetChrIndex(uint address) const { return address >> 10 ^ (regs.ctrl0 >> 5 & 0x4); } void NST_FASTCALL TypeF::UpdatePrg(uint address,uint) { prg.SwapBank( address, exPrg[GetPrgIndex(address)] ); } void NST_FASTCALL TypeG::UpdatePrg(uint address,uint) { prg.SwapBank( address, exPrg[GetPrgIndex(address)] ); } void NST_FASTCALL TypeH::UpdatePrg(uint address,uint bank) { prg.SwapBank( address, exPrg | bank ); } void NST_FASTCALL TypeA::UpdateChr(uint address,uint bank) const { chr.Source( GetChrSource(bank) ).SwapBank( address, bank ); } void NST_FASTCALL TypeG::UpdateChr(uint address,uint) const { uint bank = exChr[GetChrIndex(address)]; chr.Source( bank <= 7 ).SwapBank( address, bank ); } void NST_FASTCALL TypeH::UpdateChr(uint address,uint bank) const { if (chr.Source().GetType() == Ram::ROM) chr.SwapBank( address, bank ); } void NST_FASTCALL TypeJ::UpdatePrg(uint address,uint bank) { prg.SwapBank( address, exPrg[GetPrgIndex(address)] ); } uint NST_FASTCALL TypeA::GetChrSource(uint bank) const { return bank - 8 <= 1; } uint NST_FASTCALL TypeB::GetChrSource(uint bank) const { return bank >> 7 & 0x1; } uint NST_FASTCALL TypeC::GetChrSource(uint bank) const { return bank - 8 <= 3; } uint NST_FASTCALL TypeD::GetChrSource(uint bank) const { return bank <= 1; } uint NST_FASTCALL TypeE::GetChrSource(uint bank) const { return bank <= 3; } uint NST_FASTCALL TypeF::GetChrSource(uint) const { return 0; } } } } } nestopia-1.51.1/source/core/board/NstBoardWaixing.hpp000066400000000000000000000104401411157722000225130ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_WAIXING_H #define NST_BOARD_WAIXING_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardMmc3.hpp" #include "NstBoardWaixingPs2.hpp" #include "NstBoardWaixingFfv.hpp" #include "NstBoardWaixingFs304.hpp" #include "NstBoardWaixingSh2.hpp" #include "NstBoardWaixingZs.hpp" #include "NstBoardWaixingSecurity.hpp" #include "NstBoardWaixingSgz.hpp" #include "NstBoardWaixingSgzlz.hpp" namespace Nes { namespace Core { namespace Boards { namespace Waixing { class TypeI : public Mmc3 { public: explicit TypeI(const Context& c) : Mmc3(c) {} protected: void SubReset(bool); uint GetChrIndex(uint) const; uint GetPrgIndex(uint) const; private: NES_DECL_PEEK( 5000 ); NES_DECL_POKE( 5000 ); }; class TypeA : public TypeI { public: explicit TypeA(const Context& c) : TypeI(c) {} protected: void SubReset(bool); private: virtual uint NST_FASTCALL GetChrSource(uint) const; void NST_FASTCALL UpdateChr(uint,uint) const; }; class TypeB : public TypeA { public: explicit TypeB(const Context& c) : TypeA(c) {} private: uint NST_FASTCALL GetChrSource(uint) const; }; class TypeC : public TypeA { public: explicit TypeC(const Context& c) : TypeA(c) {} private: uint NST_FASTCALL GetChrSource(uint) const; }; class TypeD : public TypeA { public: explicit TypeD(const Context& c) : TypeA(c) {} private: uint NST_FASTCALL GetChrSource(uint) const; }; class TypeE : public TypeA { public: explicit TypeE(const Context& c) : TypeA(c) {} private: uint NST_FASTCALL GetChrSource(uint) const; }; class TypeF : public TypeA { public: explicit TypeF(const Context& c) : TypeA(c) {} private: void SubReset(bool); void SubLoad(State::Loader&,dword); uint NST_FASTCALL GetChrSource(uint) const; void NST_FASTCALL UpdatePrg(uint,uint); NES_DECL_POKE( 8001 ); byte exPrg[4]; }; class TypeG : public TypeA { public: explicit TypeG(const Context& c) : TypeA(c) {} private: void SubReset(bool); void SubLoad(State::Loader&,dword); void NST_FASTCALL UpdatePrg(uint,uint); void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_POKE( 8001 ); byte exPrg[4]; byte exChr[8]; }; class TypeH : public Mmc3 { public: explicit TypeH(const Context& c) : Mmc3(c) {} private: void SubReset(bool); void SubLoad(State::Loader&,dword); void NST_FASTCALL UpdatePrg(uint,uint); void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_POKE( 8001 ); uint exPrg; }; class TypeJ : public TypeI { public: explicit TypeJ(const Context& c) : TypeI(c) {} private: void SubReset(bool); void SubLoad(State::Loader&,dword); void NST_FASTCALL UpdatePrg(uint,uint); NES_DECL_POKE( 8001 ); byte exPrg[4]; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardWaixingFfv.cpp000066400000000000000000000056631411157722000231630ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardWaixing.hpp" namespace Nes { namespace Core { namespace Boards { namespace Waixing { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Ffv::SubReset(bool) { for (uint i=0x5000; i < 0x6000; i += 0x400) Map( i + 0x00, i + 0x1FF, &Ffv::Poke_5000 ); for (uint i=0; i < 2; ++i) regs[i] = 0; prg.SwapBank(0x1F); } void Ffv::SubSave(State::Saver& state) const { const byte data[2] = { regs[0], regs[1] }; state.Begin( AsciiId<'W','F','V'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } void Ffv::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'W','F','V'>::V) ); if (baseChunk == AsciiId<'W','F','V'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<2> data( state ); regs[0] = data[0]; regs[1] = data[1]; } state.End(); } } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(Ffv,5000) { address = address >> 8 & 0x1; if (regs[address] != data) { regs[address] = data; data = regs[1] << 5 & 0x20; switch (regs[0] & 0x70) { case 0x00: case 0x20: case 0x40: case 0x60: prg.SwapBanks( data | (regs[0] >> 1 & 0x10) | (regs[0] & 0xF), data | 0x1F ); break; case 0x50: prg.SwapBank( (data >> 1) | (regs[0] & 0xF) ); break; case 0x70: prg.SwapBanks( data | (regs[0] << 1 & 0x10) | (regs[0] & 0xF), data | 0x1F ); break; } } } } } } } nestopia-1.51.1/source/core/board/NstBoardWaixingFfv.hpp000066400000000000000000000031011411157722000231510ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_WAIXING_FFV_H #define NST_BOARD_WAIXING_FFV_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Waixing { class Ffv : public Board { public: explicit Ffv(const Context& c) : Board(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void UpdatePrg(); NES_DECL_POKE( 5000 ); uint regs[2]; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardWaixingFs304.cpp000066400000000000000000000056221411157722000232340ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2021 Rupert Carmichael // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardWaixing.hpp" // Reference: https://github.com/TASVideos/fceux/blob/master/src/boards/164.cpp namespace Nes { namespace Core { namespace Boards { namespace Waixing { void Fs304::SubReset(bool) { Map( 0x5000U, 0x5FFFU, &Fs304::Poke_5000 ); regs[0] = 0x3; regs[1] = 0x0; regs[2] = 0x0; regs[3] = 0x7; UpdatePrg(); } void Fs304::SubSave(State::Saver& state) const { const byte data[4] = { regs[0], regs[1], regs[2], regs[3] }; state.Begin( AsciiId<'3','0','4'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); } void Fs304::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'3','0','4'>::V) ); if (baseChunk == AsciiId<'3','0','4'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) { State::Loader::Data<4> data( state ); regs[0] = data[0]; regs[1] = data[1]; regs[2] = data[2]; regs[3] = data[3]; } state.End(); } } } void Fs304::UpdatePrg() { switch (regs[3] & 0x5) { case 0: prg.SwapBank( 0x0000, ((regs[0] & 0xC) | (regs[1] & 0x2) | ((regs[2] & 0xF) << 4)) ); break; case 1: prg.SwapBank( 0x0000, ((regs[0] & 0xC) | (regs[2] & 0xF) << 4) ); break; case 4: prg.SwapBank( 0x0000, ((regs[0] & 0xE) | ((regs[1] >> 1) & 0x1) | ((regs[2] & 0xF) << 4)) ); break; case 5: prg.SwapBank( 0x0000, ((regs[0] & 0xF) | ((regs[2] & 0xF) << 4)) ); break; } } NES_POKE_AD(Fs304,5000) { regs[(address >> 8) & 0x3] = data; UpdatePrg(); } } } } } nestopia-1.51.1/source/core/board/NstBoardWaixingFs304.hpp000066400000000000000000000031111411157722000232300ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2021 Rupert Carmichael // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_WAIXING_FS304_H #define NST_BOARD_WAIXING_FS304_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Waixing { class Fs304 : public Board { public: explicit Fs304(const Context& c) : Board(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void UpdatePrg(); NES_DECL_POKE( 5000 ); uint regs[4]; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardWaixingPs2.cpp000066400000000000000000000041621411157722000230770ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardWaixing.hpp" namespace Nes { namespace Core { namespace Boards { namespace Waixing { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Ps2::SubReset(bool) { Map( 0x8000U, 0xFFFFU, &Ps2::Poke_8000 ); prg.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(Ps2,8000) { ppu.SetMirroring( (data & 0x40) ? Ppu::NMT_H : Ppu::NMT_V ); const uint flip = data >> 7; data = data << 1 & 0xFE; switch (address & 0xFFF) { case 0x000: prg.SwapBanks( (data+0) ^ flip, (data+1) ^ flip, (data+2) ^ flip, (data+3) ^ flip ); break; case 0x002: data |= flip; prg.SwapBanks( data, data, data, data ); break; case 0x001: case 0x003: data |= flip; prg.SwapBanks( data, data+1, data + (~address >> 1 & 1), data+1 ); break; } } } } } } nestopia-1.51.1/source/core/board/NstBoardWaixingPs2.hpp000066400000000000000000000026601411157722000231050ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_MAPPER_15_H #define NST_MAPPER_15_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Waixing { class Ps2 : public Board { public: explicit Ps2(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardWaixingSecurity.cpp000066400000000000000000000055621411157722000242470ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardWaixing.hpp" namespace Nes { namespace Core { namespace Boards { namespace Waixing { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Security::SubReset(const bool hard) { if (hard) exReg = 0; Mmc3::SubReset( hard ); Map( 0x5000U, &Security::Poke_5000 ); } void Security::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'W','S','C'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) exReg = state.Read8() & 0x2; state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void Security::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); state.Begin( AsciiId<'R','E','G'>::V ).Write8( exReg ).End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Security,5000) { data &= 0x2; if (exReg != data) { exReg = data; Mmc3::UpdatePrg(); Mmc3::UpdateChr(); } } void Security::UpdatePrg(uint address,uint bank) { prg.SwapBank ( address, !exReg ? bank : ( (bank << 0 & 0x01) | (bank >> 3 & 0x02) | (bank >> 1 & 0x04) | (bank << 2 & 0x18) ) ); } void Security::UpdateChr(uint address,uint bank) const { chr.SwapBank ( address, !exReg ? bank : ( (bank >> 0 & 0x03) | (bank >> 1 & 0x04) | (bank >> 4 & 0x08) | (bank >> 2 & 0x10) | (bank << 3 & 0x20) | (bank << 2 & 0x40) | (bank << 2 & 0x80) ) ); } } } } } nestopia-1.51.1/source/core/board/NstBoardWaixingSecurity.hpp000066400000000000000000000032351411157722000242470ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_WAIXING_SECURITY_H #define NST_BOARD_WAIXING_SECURITY_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Waixing { class Security : public Mmc3 { public: explicit Security(const Context& c) : Mmc3(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void NST_FASTCALL UpdatePrg(uint,uint); void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_POKE( 5000 ); uint exReg; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardWaixingSgz.cpp000066400000000000000000000066211411157722000232000ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstTimer.hpp" #include "NstBoard.hpp" #include "NstBoardWaixing.hpp" namespace Nes { namespace Core { namespace Boards { namespace Waixing { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Sgz::Sgz(const Context& c) : Board(c), irq(*c.cpu) {} void Sgz::SubReset(const bool hard) { irq.Reset( hard, hard ? false : irq.Connected() ); Map( 0x8000U, 0x8FFFU, PRG_SWAP_8K_0 ); Map( 0xA000U, 0xAFFFU, PRG_SWAP_8K_1 ); Map( 0xB000U, 0xEFFFU, &Sgz::Poke_B000 ); for (uint i=0x0000; i < 0x1000; i += 0x10) { Map( 0xF000 + i, 0xF003 + i, &Sgz::Poke_F000 ); Map( 0xF004 + i, 0xF007 + i, &Sgz::Poke_F004 ); Map( 0xF008 + i, 0xF00B + i, &Sgz::Poke_F008 ); Map( 0xF00C + i, 0xF00F + i, &Sgz::Poke_F00C ); } // hack chr.Source().WriteEnable( true ); } void Sgz::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'W','S','Z'>::V) ); if (baseChunk == AsciiId<'W','S','Z'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'I','R','Q'>::V) irq.LoadState( state ); state.End(); } } } void Sgz::SubSave(State::Saver& state) const { state.Begin( AsciiId<'W','S','Z'>::V ); irq.SaveState( state, AsciiId<'I','R','Q'>::V ); state.End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_AD(Sgz,B000) { ppu.Update(); const uint part = address & 0x4; address = ((address - 0xB000) >> 1 & 0x1800) | (address << 7 & 0x0400); chr.SwapBank( address, (chr.GetBank(address) & 0xF0U >> part) | (data & 0xF) << part ); } NES_POKE_D(Sgz,F000) { irq.Update(); irq.unit.latch = (irq.unit.latch & 0xF0) | (data & 0x0F); } NES_POKE_D(Sgz,F004) { irq.Update(); irq.unit.latch = (irq.unit.latch & 0x0F) | (data & 0x0F) << 4; } NES_POKE_D(Sgz,F008) { irq.Toggle( data ); } NES_POKE(Sgz,F00C) { irq.Toggle(); } void Sgz::Sync(Event event,Input::Controllers* controllers) { if (event == EVENT_END_FRAME) irq.VSync(); Board::Sync( event, controllers ); } } } } } nestopia-1.51.1/source/core/board/NstBoardWaixingSgz.hpp000066400000000000000000000033421411157722000232020ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_WAIXING_SGZ_H #define NST_BOARD_WAIXING_SGZ_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "NstBoardKonamiVrc4.hpp" namespace Nes { namespace Core { namespace Boards { namespace Waixing { class Sgz : public Board { public: explicit Sgz(const Context&); private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void Sync(Event,Input::Controllers*); NES_DECL_POKE( B000 ); NES_DECL_POKE( F000 ); NES_DECL_POKE( F004 ); NES_DECL_POKE( F008 ); NES_DECL_POKE( F00C ); Konami::Vrc4::Irq irq; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardWaixingSgzlz.cpp000066400000000000000000000045441411157722000235500ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardWaixing.hpp" namespace Nes { namespace Core { namespace Boards { namespace Waixing { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Sgzlz::SubReset(const bool hard) { Map( 0x4800U, NMT_SWAP_HV ); Map( 0x4801U, &Sgzlz::Poke_4801 ); Map( 0x4802U, &Sgzlz::Poke_4802 ); if (hard) { reg = 0; prg.SwapBank(0); } } void Sgzlz::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( baseChunk == (AsciiId<'W','L','Z'>::V) ); if (baseChunk == AsciiId<'W','L','Z'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) reg = state.Read8() & 0xF; state.End(); } } } void Sgzlz::SubSave(State::Saver& state) const { state.Begin( AsciiId<'W','L','Z'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( reg ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_D(Sgzlz,4801) { reg = (data >> 1 & 0x3) | (reg & 0xC); prg.SwapBank( reg ); } NES_POKE_D(Sgzlz,4802) { reg = (reg & 0x3) | (data << 2 & 0xC); } } } } } nestopia-1.51.1/source/core/board/NstBoardWaixingSgzlz.hpp000066400000000000000000000031121411157722000235430ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_WAIXING_SGZLZ_H #define NST_BOARD_WAIXING_SGZLZ_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Waixing { class Sgzlz : public Board { public: explicit Sgzlz(const Context& c) : Board(c) {} private: void SubReset(bool); void SubLoad(State::Loader&,dword); void SubSave(State::Saver&) const; NES_DECL_POKE( 4801 ); NES_DECL_POKE( 4802 ); uint reg; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardWaixingSh2.cpp000066400000000000000000000056711411157722000230750ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardWaixing.hpp" namespace Nes { namespace Core { namespace Boards { namespace Waixing { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Sh2::SubReset(const bool hard) { selector[1] = 0; selector[0] = 0; chr.SetAccessor( this, &Sh2::Access_Chr ); Mmc3::SubReset( hard ); } void Sh2::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); state.Begin( AsciiId<'W','S','2'>::V ).Begin( AsciiId<'L','T','C'>::V ).Write8( (selector[0] >> 1) | (selector[1] & 0x2) ).End().End(); } void Sh2::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'W','S','2'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'L','T','C'>::V) { const uint data = state.Read8(); selector[0] = data << 1 & 0x2; selector[1] = (data & 0x2) | 0x4; } state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif inline void Sh2::SwapChr(uint address) const { chr.Source( banks.chr[selector[address >> 12]] == 0 ).SwapBank( address, banks.chr[selector[address >> 12]] >> 2 ); } void NST_FASTCALL Sh2::UpdateChr(uint,uint) const { SwapChr( 0x0000 ); SwapChr( 0x1000 ); } NES_ACCESSOR(Sh2,Chr) { const uint data = chr.Peek( address ); uint bank; switch (address & 0xFF8) { case 0xFD0: bank = (address >> 10 & 0x4) | 0x0; break; case 0xFE8: bank = (address >> 10 & 0x4) | 0x2; break; default: return data; } selector[address >> 12] = bank; SwapChr( address & 0x1000 ); return data; } } } } } nestopia-1.51.1/source/core/board/NstBoardWaixingSh2.hpp000066400000000000000000000032151411157722000230720ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_WAIXING_SH2_H #define NST_BOARD_WAIXING_SH2_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Waixing { class Sh2 : public Mmc3 { public: explicit Sh2(const Context& c) : Mmc3(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); inline void SwapChr(uint) const; void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_ACCESSOR( Chr ); uint selector[2]; }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardWaixingZs.cpp000066400000000000000000000035551411157722000230340ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardWaixing.hpp" namespace Nes { namespace Core { namespace Boards { namespace Waixing { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Dqv7::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &Dqv7::Poke_8000 ); if (hard) prg.SwapBank(0); } void Zs::SubReset(const bool hard) { Map( 0x8000U, 0xFFFFU, &Zs::Poke_8000 ); if (hard) prg.SwapBank(0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_POKE_A(Dqv7,8000) { prg.SwapBank( address >> 3 ); } NES_POKE_AD(Zs,8000) { SetMirroringVH01( data ); Dqv7::NES_DO_POKE(8000,address,data); } } } } } nestopia-1.51.1/source/core/board/NstBoardWaixingZs.hpp000066400000000000000000000032011411157722000230250ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_WAIXING_ZS_H #define NST_BOARD_WAIXING_ZS_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Waixing { class Dqv7 : public Board { public: explicit Dqv7(const Context& c) : Board(c) {} protected: void SubReset(bool); NES_DECL_POKE( 8000 ); }; class Zs : public Dqv7 { public: explicit Zs(const Context& c) : Dqv7(c) {} private: void SubReset(bool); NES_DECL_POKE( 8000 ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardWhirlwind.cpp000066400000000000000000000033311411157722000230500ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardWhirlwind.hpp" namespace Nes { namespace Core { namespace Boards { namespace Whirlwind { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void W2706::SubReset(const bool hard) { Map( 0x6000U, 0x7FFFU, &W2706::Peek_6000 ); Map( 0x8FFFU, &W2706::Poke_8FFF ); if (hard) prg.SwapBank(~0U); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(W2706,6000) { return wrk[0][address - 0x6000]; } NES_POKE_D(W2706,8FFF) { wrk.SwapBank(data); } } } } } nestopia-1.51.1/source/core/board/NstBoardWhirlwind.hpp000066400000000000000000000027371411157722000230660ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_WHIRLWIND_H #define NST_BOARD_WHIRLWIND_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { namespace Whirlwind { class W2706 : public Board { public: explicit W2706(const Context& c) : Board(c) {} private: void SubReset(bool); NES_DECL_PEEK( 6000 ); NES_DECL_POKE( 8FFF ); }; } } } } #endif nestopia-1.51.1/source/core/board/NstBoardZz.cpp000066400000000000000000000050731411157722000215110ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstBoard.hpp" #include "NstBoardMmc3.hpp" #include "NstBoardZz.hpp" namespace Nes { namespace Core { namespace Boards { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Zz::SubReset(const bool hard) { if (hard) exReg = 0x0; Mmc3::SubReset( hard ); Map( 0x6000U, 0x7FFFU, &Zz::Poke_6000 ); } void Zz::SubLoad(State::Loader& state,const dword baseChunk) { if (baseChunk == AsciiId<'Z','Z'>::V) { while (const dword chunk = state.Begin()) { if (chunk == AsciiId<'R','E','G'>::V) exReg = state.Read8() & 0x7; state.End(); } } else { Mmc3::SubLoad( state, baseChunk ); } } void Zz::SubSave(State::Saver& state) const { Mmc3::SubSave( state ); state.Begin( AsciiId<'Z','Z'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( exReg ).End().End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void NST_FASTCALL Zz::UpdatePrg(uint address,uint bank) { prg.SwapBank ( address, (exReg << 2 & 0x10) | ((exReg & 0x3) == 0x3 ? 0x08 : 0x00) | (bank & (exReg << 1 | 0x7)) ); } void NST_FASTCALL Zz::UpdateChr(uint address,uint bank) const { chr.SwapBank( address, (exReg << 5 & 0x80) | (bank & 0x7F) ); } NES_POKE_D(Zz,6000) { data &= 0x7; if (exReg != data) { exReg = data; Mmc3::UpdatePrg(); Mmc3::UpdateChr(); } } } } } nestopia-1.51.1/source/core/board/NstBoardZz.hpp000066400000000000000000000031051411157722000215100ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_BOARD_ZZ_H #define NST_BOARD_ZZ_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Boards { class Zz : public Mmc3 { public: explicit Zz(const Context& c) : Mmc3(c) {} private: void SubReset(bool); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); void NST_FASTCALL UpdatePrg(uint,uint); void NST_FASTCALL UpdateChr(uint,uint) const; NES_DECL_POKE( 6000 ); uint exReg; }; } } } #endif nestopia-1.51.1/source/core/input/000077500000000000000000000000001411157722000170105ustar00rootroot00000000000000nestopia-1.51.1/source/core/input/NstInpAdapter.cpp000066400000000000000000000131621411157722000222330ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstInpDevice.hpp" #include "NstInpAdapter.hpp" namespace Nes { namespace Core { namespace Input { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Adapter::Adapter(Type t) : type(t) {} AdapterTwo::AdapterTwo(Device& a,Device& b,Type t) : Adapter(t) { devices[0] = &a; devices[1] = &b; } bool AdapterTwo::SetType(Type t) { if (type != t) { type = t; return true; } return false; } Device& AdapterTwo::Connect(uint port,Device& device) { NST_ASSERT( port < 2 ); Device& old = *devices[port]; devices[port] = &device; return old; } void AdapterTwo::Initialize(bool arcade) { for (uint i=0; i < 2; ++i) devices[i]->Initialize( arcade ); } void AdapterTwo::Reset() { for (uint i=0; i < 2; ++i) devices[i]->Reset(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif uint AdapterTwo::NumPorts() const { return 2; } Device& AdapterTwo::GetDevice(uint port) const { NST_ASSERT( port < 2 ); return *devices[port]; } void AdapterTwo::BeginFrame(Controllers* input) { devices[0]->BeginFrame( input ); devices[1]->BeginFrame( input ); } void AdapterTwo::EndFrame() { devices[0]->EndFrame(); devices[1]->EndFrame(); } void AdapterTwo::Poke(uint data) { devices[0]->Poke( data ); devices[1]->Poke( data ); } uint AdapterTwo::Peek(uint line) { NST_ASSERT( line < 2 ); return devices[line]->Peek( line ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif AdapterFour::AdapterFour(Device& a,Device& b,Device& c,Device& d,Type t) : Adapter(t), increaser(1) { count[0] = 0; count[1] = 0; devices[0] = &a; devices[1] = &b; devices[2] = &c; devices[3] = &d; } Device& AdapterFour::Connect(uint port,Device& device) { NST_ASSERT( port < 4 ); Device& old = *devices[port]; devices[port] = &device; return old; } void AdapterFour::Initialize(bool arcade) { for (uint i=0; i < 4; ++i) devices[i]->Initialize( arcade ); } void AdapterFour::Reset() { increaser = 1; count[0] = 0; count[1] = 0; for (uint i=0; i < 4; ++i) devices[i]->Reset(); } bool AdapterFour::SetType(Type t) { if (type != t) { type = t; increaser = 1; count[0] = 0; count[1] = 0; return true; } return false; } void AdapterFour::SaveState(State::Saver& state,const dword chunk) const { if (type == Api::Input::ADAPTER_NES) { const byte data[3] = { increaser ^ 1, count[0], count[1] }; state.Begin( chunk ).Write( data ).End(); } } void AdapterFour::LoadState(State::Loader& state) { if (type == Api::Input::ADAPTER_NES) { State::Loader::Data<3> data( state ); increaser = ~data[0] & 0x1; count[0] = (data[1] <= 20) ? data[1] : 0; count[1] = (data[2] <= 20) ? data[2] : 0; } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif uint AdapterFour::NumPorts() const { return 4; } Device& AdapterFour::GetDevice(uint port) const { NST_ASSERT( port < 4 ); return *devices[port]; } void AdapterFour::BeginFrame(Controllers* input) { for (uint i=0; i < 4; ++i) devices[i]->BeginFrame( input ); } void AdapterFour::EndFrame() { for (uint i=0; i < 4; ++i) devices[i]->EndFrame(); } void AdapterFour::Poke(const uint data) { if (type == Api::Input::ADAPTER_NES) { increaser = ~data & 0x1; if (!increaser) { count[0] = 0; count[1] = 0; } } for (uint i=0; i < 4; ++i) devices[i]->Poke( data ); } uint AdapterFour::Peek(const uint line) { NST_ASSERT( line < 2 ); if (type == Api::Input::ADAPTER_NES) { const uint index = count[line]; if (index < 20) { count[line] += increaser; if (index < 16) { return devices[line + (index < 8 ? 0 : 2)]->Peek( line ); } else if (index >= 18) { return (index - 18) ^ line; } } return 0; } else { return ( (devices[line+0]->Peek( line ) << 0 & 0x1) | (devices[line+2]->Peek( line ) << 1 & 0x2) ); } } } } } nestopia-1.51.1/source/core/input/NstInpAdapter.hpp000066400000000000000000000056011411157722000222370ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_ADAPTER_H #define NST_INPUT_ADAPTER_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Input { class NST_NO_VTABLE Adapter { protected: typedef Api::Input::Adapter Type; Type type; explicit Adapter(Type); public: virtual ~Adapter() {} virtual void Reset() = 0; virtual void BeginFrame(Controllers*) = 0; virtual void EndFrame() = 0; virtual void Initialize(bool) = 0; virtual void Poke(uint) = 0; virtual uint Peek(uint) = 0; virtual uint NumPorts() const = 0; virtual Device& GetDevice(uint) const = 0; virtual Device& Connect(uint,Device&) = 0; virtual bool SetType(Type) = 0; Type GetType() const { return type; } }; class AdapterTwo : public Adapter { ~AdapterTwo() {} void Reset(); void BeginFrame(Controllers*); void EndFrame(); void Initialize(bool); void Poke(uint); uint Peek(uint); uint NumPorts() const; Device& GetDevice(uint) const; Device& Connect(uint,Device&); bool SetType(Type); Device* devices[2]; public: AdapterTwo(Device&,Device&,Type=Api::Input::ADAPTER_NES); }; class AdapterFour : public Adapter { ~AdapterFour() {} void Reset(); void BeginFrame(Controllers*); void EndFrame(); void Initialize(bool); uint Peek(uint); void Poke(uint); uint NumPorts() const; Device& GetDevice(uint) const; Device& Connect(uint,Device&); bool SetType(Type); uint increaser; uint count[2]; Device* devices[4]; public: AdapterFour(Device&,Device&,Device&,Device&,Type=Api::Input::ADAPTER_NES); void SaveState(State::Saver&,dword) const; void LoadState(State::Loader&); }; } } } #endif nestopia-1.51.1/source/core/input/NstInpBandaiHyperShot.cpp000066400000000000000000000053271411157722000237030ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstInpDevice.hpp" #include "../NstPpu.hpp" #include "NstInpZapper.hpp" #include "NstInpBandaiHyperShot.hpp" namespace Nes { namespace Core { namespace Input { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif BandaiHyperShot::BandaiHyperShot(const Cpu& c,Ppu& p) : Device (c,Api::Input::BANDAIHYPERSHOT), ppu (p) { BandaiHyperShot::Reset(); } void BandaiHyperShot::Reset() { pos = ~0U; fire = 0; move = 0; } void BandaiHyperShot::SaveState(State::Saver& saver,const byte id) const { saver.Begin( AsciiId<'B','H'>::R(0,0,id) ).End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif uint BandaiHyperShot::Poll() { if (input) { Controllers::BandaiHyperShot& bandaiHyperShot = input->bandaiHyperShot; input = NULL; if (Controllers::BandaiHyperShot::callback( bandaiHyperShot )) { fire = (bandaiHyperShot.fire ? 0x10 : 0x00); move = (bandaiHyperShot.move ? 0x02 : 0x00); if (bandaiHyperShot.y < Video::Screen::HEIGHT && bandaiHyperShot.x < Video::Screen::WIDTH) pos = bandaiHyperShot.y * Video::Screen::WIDTH + bandaiHyperShot.x; else pos = ~0U; } } if (pos < Video::Screen::WIDTH * Video::Screen::HEIGHT) { ppu.Update(); uint pixel = ppu.GetPixelCycles(); if (pos < pixel && pos >= pixel - PHOSPHOR_DECAY) return Zapper::GetLightMap( ppu.GetPixel( pos ) ); } return 0; } uint BandaiHyperShot::Peek(uint) { uint data = (Poll() >= LIGHT_SENSOR ? 0x0 : 0x8); return data | fire | move; } } } } nestopia-1.51.1/source/core/input/NstInpBandaiHyperShot.hpp000066400000000000000000000032131411157722000237000ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_BANDAIHYPERSHOT_H #define NST_INPUT_BANDAIHYPERSHOT_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class Ppu; namespace Input { class BandaiHyperShot : public Device { public: BandaiHyperShot(const Cpu&,Ppu&); private: void Reset(); uint Poll(); uint Peek(uint); uint GetHitPixel() const; void SaveState(State::Saver&,byte) const; enum { PHOSPHOR_DECAY = 384, LIGHT_SENSOR = 0x40 }; uint pos; uint fire; uint move; Ppu& ppu; }; } } } #endif nestopia-1.51.1/source/core/input/NstInpBarcodeWorld.cpp000066400000000000000000000104201411157722000232140ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstInpDevice.hpp" #include "NstInpBarcodeWorld.hpp" namespace Nes { namespace Core { namespace Input { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif BarcodeWorld::BarcodeWorld(const Cpu& cpu) : Device(cpu,Api::Input::BARCODEWORLD) { BarcodeWorld::Reset(); } void BarcodeWorld::Reset() { reader.Reset(); } void BarcodeWorld::LoadState(State::Loader& loader,const dword id) { reader.LoadState( loader, id ); } void BarcodeWorld::SaveState(State::Saver& saver,const byte id) const { reader.SaveState( saver, id ); } void BarcodeWorld::Reader::Reset() { stream = data; std::memset( data, END, MAX_DATA_LENGTH ); } bool BarcodeWorld::Reader::IsDigitsSupported(uint count) const { return count == NUM_DIGITS; } bool BarcodeWorld::Reader::IsTransferring() const { return *stream != END; } void BarcodeWorld::Reader::LoadState(State::Loader& loader,const dword id) { if (id == AsciiId<'B','W'>::V) { Reset(); while (const dword chunk = loader.Begin()) { switch (chunk) { case AsciiId<'P','T','R'>::V: stream = data + (loader.Read8() & (MAX_DATA_LENGTH-1)); break; case AsciiId<'D','A','T'>::V: loader.Uncompress( data ); data[MAX_DATA_LENGTH-1] = END; break; } loader.End(); } } } void BarcodeWorld::Reader::SaveState(State::Saver& saver,const byte id) const { saver.Begin( AsciiId<'B','W'>::R(0,0,id) ); if (Reader::IsTransferring()) { saver.Begin( AsciiId<'P','T','R'>::V ).Write8( stream - data ).End(); saver.Begin( AsciiId<'D','A','T'>::V ).Compress( data ).End(); } saver.End(); } bool BarcodeWorld::Reader::Transfer(cstring const string,const uint length) { NST_COMPILE_ASSERT( MAX_DATA_LENGTH >= 191 ); Reset(); if (!string || length != NUM_DIGITS) return false; byte code[NUM_DIGITS+7]; for (uint i=0; i < NUM_DIGITS; ++i) { const int c = string[i]; if (c >= '0' && c <= '9') code[i] = c - '0' + Ascii<'0'>::V; else return false; } code[NUM_DIGITS+0] = Ascii<'S'>::V; code[NUM_DIGITS+1] = Ascii<'U'>::V; code[NUM_DIGITS+2] = Ascii<'N'>::V; code[NUM_DIGITS+3] = Ascii<'S'>::V; code[NUM_DIGITS+4] = Ascii<'O'>::V; code[NUM_DIGITS+5] = Ascii<'F'>::V; code[NUM_DIGITS+6] = Ascii<'T'>::V; byte* NST_RESTRICT output = data; *output++ = 0x04; for (uint i=0; i < NUM_DIGITS+7; ++i) { *output++ = 0x04; for (uint j=0x01, c=code[i]; j != 0x100; j <<= 1) *output++ = (c & j) ? 0x00 : 0x04; *output++ = 0x00; } return true; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif uint BarcodeWorld::Reader::Read() { if (Reader::IsTransferring()) { uint next = *stream; stream += (next != END); return next; } else { return 0; } } uint BarcodeWorld::Peek(uint port) { return port == 1 ? reader.Read() : 0; } } } } nestopia-1.51.1/source/core/input/NstInpBarcodeWorld.hpp000066400000000000000000000041371411157722000232310ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_BARCODEWORLD_H #define NST_INPUT_BARCODEWORLD_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "../NstBarcodeReader.hpp" namespace Nes { namespace Core { namespace Input { class BarcodeWorld : public Device { public: explicit BarcodeWorld(const Cpu&); private: void Reset(); void LoadState(State::Loader&,dword); void SaveState(State::Saver&,byte) const; uint Peek(uint); class Reader : public BarcodeReader { public: void Reset(); uint Read(); void LoadState(State::Loader&,dword); void SaveState(State::Saver&,byte) const; private: bool Transfer(cstring,uint); bool IsTransferring() const; bool IsDigitsSupported(uint) const; enum { NUM_DIGITS = 13, MAX_DATA_LENGTH = 0x100, END = 0xFF }; const byte* stream; byte data[MAX_DATA_LENGTH]; }; Reader reader; public: BarcodeReader& GetReader() { return reader; } }; } } } #endif nestopia-1.51.1/source/core/input/NstInpCrazyClimber.cpp000066400000000000000000000056041411157722000232430ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstInpDevice.hpp" #include "NstInpCrazyClimber.hpp" namespace Nes { namespace Core { namespace Input { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif CrazyClimber::CrazyClimber(const Cpu& c) : Device(c,Api::Input::CRAZYCLIMBER) { CrazyClimber::Reset(); } void CrazyClimber::Reset() { shifter = 1; stream[LEFT] = 0; stream[RIGHT] = 0; state[LEFT] = 0; state[RIGHT] = 0; } void CrazyClimber::SaveState(State::Saver& saver,const byte id) const { saver.Begin( AsciiId<'C','C'>::R(0,0,id) ).Write8( shifter ^ 1 ).End(); } void CrazyClimber::LoadState(State::Loader& loader,const dword id) { if (id == AsciiId<'C','C'>::V) shifter = ~loader.Read8() & 0x1; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif uint CrazyClimber::Peek(const uint port) { NST_ASSERT( port <= 1 ); const uint data = stream[port]; stream[port] >>= shifter; return data & 0x1; } void CrazyClimber::Poke(const uint data) { const uint prev = shifter; shifter = ~data & 0x1; if (prev < shifter) { if (input) { Controllers::CrazyClimber& crazy = input->crazyClimber; input = NULL; if (Controllers::CrazyClimber::callback( crazy )) { state[LEFT] = crazy.left; state[RIGHT] = crazy.right; for (uint i=0; i < 2; ++i) { if ((state[i] & (BUTTON_LEFT|BUTTON_RIGHT)) == (BUTTON_LEFT|BUTTON_RIGHT)) state[i] &= (BUTTON_LEFT|BUTTON_RIGHT) ^ 0xFFU; if ((state[i] & (BUTTON_UP|BUTTON_DOWN)) == (BUTTON_UP|BUTTON_DOWN)) state[i] &= (BUTTON_UP|BUTTON_DOWN) ^ 0xFFU; } } } stream[LEFT] = state[LEFT]; stream[RIGHT] = state[RIGHT]; } } } } } nestopia-1.51.1/source/core/input/NstInpCrazyClimber.hpp000066400000000000000000000033201411157722000232410ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_CRAZYCLIMBER_H #define NST_INPUT_CRAZYCLIMBER_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Input { class CrazyClimber : public Device { public: explicit CrazyClimber(const Cpu&); private: void Reset(); void Poke(uint); uint Peek(uint); void LoadState(State::Loader&,dword); void SaveState(State::Saver&,byte) const; enum {LEFT,RIGHT}; enum { BUTTON_RIGHT = 0x10, BUTTON_LEFT = 0x20, BUTTON_UP = 0x40, BUTTON_DOWN = 0x80 }; uint shifter; uint stream[2]; uint state[2]; }; } } } #endif nestopia-1.51.1/source/core/input/NstInpDevice.hpp000066400000000000000000000040461411157722000220600ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_DEVICE_H #define NST_INPUT_DEVICE_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "../NstState.hpp" #include "../api/NstApiInput.hpp" namespace Nes { namespace Core { class Cpu; namespace Input { class Device { protected: typedef Api::Input::Type Type; const Type type; Controllers* input; const Cpu& cpu; public: explicit Device(const Cpu& c,Type t=Api::Input::UNCONNECTED) : type(t), input(NULL), cpu(c) {} virtual ~Device() {} virtual void Initialize(bool) {} virtual void Reset() {} virtual void LoadState(State::Loader&,dword) {} virtual void SaveState(State::Saver&,byte) const {} virtual void BeginFrame(Controllers* i) { input = i; } virtual void EndFrame() { } virtual void Poke(uint) { } virtual uint Peek(uint) { return 0; } Type GetType() const { return type; } }; } } } #endif nestopia-1.51.1/source/core/input/NstInpDoremikkoKeyboard.cpp000066400000000000000000000043551411157722000242640ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstInpDevice.hpp" #include "NstInpDoremikkoKeyboard.hpp" namespace Nes { namespace Core { namespace Input { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif DoremikkoKeyboard::DoremikkoKeyboard(const Cpu& c) : Device(c,Api::Input::DOREMIKKOKEYBOARD) { DoremikkoKeyboard::Reset(); } void DoremikkoKeyboard::Reset() { reg = 0; mode = 0; part = 0; } void DoremikkoKeyboard::SaveState(State::Saver& saver,const byte id) const { saver.Begin( AsciiId<'D','K'>::R(0,0,id) ).End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void DoremikkoKeyboard::Poke(const uint data) { if ((data & 0x2) > (reg & 0x2)) { part = 0; mode = 0; } if ((data & 0x1) > (reg & 0x1)) { ++part; mode = 0; } reg = data; } uint DoremikkoKeyboard::Peek(uint port) { if (port) { port = mode; mode ^= 1; if (input) { Controllers::DoremikkoKeyboard::callback( input->doremikkoKeyboard, part, port ); return input->doremikkoKeyboard.keys & 0x1E; } } return 0; } } } } nestopia-1.51.1/source/core/input/NstInpDoremikkoKeyboard.hpp000066400000000000000000000030141411157722000242600ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_DOREMIKKOKEYBOARD_H #define NST_INPUT_DOREMIKKOKEYBOARD_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Input { class DoremikkoKeyboard : public Device { public: explicit DoremikkoKeyboard(const Cpu&); private: void Reset(); void Poke(uint); uint Peek(uint); void SaveState(State::Saver&,byte) const; uint reg; uint mode; uint part; }; } } } #endif nestopia-1.51.1/source/core/input/NstInpExcitingBoxing.cpp000066400000000000000000000037631411157722000236020ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstInpDevice.hpp" #include "NstInpExcitingBoxing.hpp" namespace Nes { namespace Core { namespace Input { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif ExcitingBoxing::ExcitingBoxing(const Cpu& c) : Device(c,Api::Input::EXCITINGBOXING) { ExcitingBoxing::Reset(); } void ExcitingBoxing::Reset() { state = 0x1E; } void ExcitingBoxing::SaveState(State::Saver& saver,const byte id) const { saver.Begin( AsciiId<'E','B'>::R(0,0,id) ).End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void ExcitingBoxing::Poke(const uint data) { if (input) { Controllers::ExcitingBoxing::callback( input->excitingBoxing, data & 0x2 ); state = ~input->excitingBoxing.buttons & 0x1E; } else { state = 0x1E; } } uint ExcitingBoxing::Peek(const uint port) { return port ? state : 0; } } } } nestopia-1.51.1/source/core/input/NstInpExcitingBoxing.hpp000066400000000000000000000027421411157722000236030ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_EXCITINGBOXING_H #define NST_INPUT_EXCITINGBOXING_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Input { class ExcitingBoxing : public Device { public: explicit ExcitingBoxing(const Cpu&); private: void Reset(); void Poke(uint); uint Peek(uint); void SaveState(State::Saver&,byte) const; uint state; }; } } } #endif nestopia-1.51.1/source/core/input/NstInpFamilyKeyboard.cpp000066400000000000000000000257561411157722000235710ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstInpDevice.hpp" #include "NstInpFamilyKeyboard.hpp" #include "../NstCpu.hpp" #include "../NstHook.hpp" #include "../NstFile.hpp" #include "../api/NstApiTapeRecorder.hpp" namespace Nes { namespace Core { namespace Input { class FamilyKeyboard::DataRecorder { public: explicit DataRecorder(Cpu&); ~DataRecorder(); Result Record(); Result Play(); void SaveState(State::Saver&,dword) const; void LoadState(State::Loader&); private: NST_NO_INLINE void Start(); NST_NO_INLINE Result Stop(bool); NES_DECL_HOOK( Tape ); enum { MAX_LENGTH = SIZE_4096K, TAPE_CLOCK = 32000 }; enum Status { STOPPED, PLAYING, RECORDING }; qaword cycles; Cpu& cpu; dword multiplier; dword clock; Status status; Vector stream; dword pos; uint in; uint out; File file; public: bool IsStopped() const { return status == STOPPED; } bool IsRecording() const { return status == RECORDING; } bool IsPlaying() const { return status == PLAYING; } bool Playable() const { return stream.Size(); } Result Stop() { return Stop( false ); } void Reset() { clock = 0; Stop( false ); } void Poke(uint data) { out = data; } uint Peek() const { return in; } NST_SINGLE_CALL void EndFrame() { if (!clock) return; if (multiplier) { const qaword frame = qaword(cpu.GetFrameCycles()) * multiplier; NST_VERIFY( cycles >= frame ); if (cycles > frame) cycles -= frame; else cycles = 0; } else { clock = 0; cpu.RemoveHook( Hook(this,&DataRecorder::Hook_Tape) ); } } }; #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif FamilyKeyboard::FamilyKeyboard(Cpu& c,bool connectDataRecorder) : Device (c,Api::Input::FAMILYKEYBOARD), dataRecorder (connectDataRecorder ? new DataRecorder(c) : NULL) { FamilyKeyboard::Reset(); } FamilyKeyboard::DataRecorder::DataRecorder(Cpu& c) : cycles(0), cpu(c), multiplier(0), clock(0), status(STOPPED), pos(0), in(0), out(0) { file.Load( File::TAPE, stream, MAX_LENGTH ); } FamilyKeyboard::~FamilyKeyboard() { delete dataRecorder; } FamilyKeyboard::DataRecorder::~DataRecorder() { Stop( true ); if (stream.Size()) file.Save( File::TAPE, stream.Begin(), stream.Size() ); } void FamilyKeyboard::Reset() { scan = 0; mode = 0; if (dataRecorder) dataRecorder->Reset(); } void FamilyKeyboard::SaveState(State::Saver& saver,const byte id) const { saver.Begin( AsciiId<'F','B'>::R(0,0,id) ); saver.Begin( AsciiId<'K','B','D'>::V ).Write8( mode | (scan << 1) ).End(); if (dataRecorder) dataRecorder->SaveState( saver, AsciiId<'D','T','R'>::V ); saver.End(); } void FamilyKeyboard::DataRecorder::SaveState(State::Saver& state,const dword baseChunk) const { if (stream.Size() || status != STOPPED) { state.Begin( baseChunk ); if (status == PLAYING) { state.Begin( AsciiId<'P','L','Y'>::V ).Write32( pos ).Write8( in ).Write32( cycles ).Write32( multiplier ).End(); } else if (status == RECORDING) { state.Begin( AsciiId<'R','E','C'>::V ).Write8( out ).Write32( cycles ).Write32( multiplier ).End(); } if (stream.Size()) state.Begin( AsciiId<'D','A','T'>::V ).Write32( stream.Size() ).Compress( stream.Begin(), stream.Size() ).End(); state.End(); } } void FamilyKeyboard::LoadState(State::Loader& loader,const dword id) { if (dataRecorder) dataRecorder->Stop(); if (id == AsciiId<'F','B'>::V) { while (const dword chunk = loader.Begin()) { switch (chunk) { case AsciiId<'K','B','D'>::V: { const uint data = loader.Read8(); mode = data & 0x1; scan = data >> 1 & 0xF; if (scan > 9) scan = 0; break; } case AsciiId<'D','T','R'>::V: NST_VERIFY( dataRecorder ); if (dataRecorder) dataRecorder->LoadState( loader ); break; } loader.End(); } } } void FamilyKeyboard::DataRecorder::LoadState(State::Loader& state) { Stop( true ); while (const dword chunk = state.Begin()) { switch (chunk) { case AsciiId<'P','L','Y'>::V: NST_VERIFY( status == STOPPED ); if (status == STOPPED) { status = PLAYING; pos = state.Read32(); in = state.Read8() & 0x2; cycles = state.Read32(); if (const dword multiplier = state.Read32()) cycles = cycles * (cpu.GetClockDivider() * TAPE_CLOCK) / multiplier; else cycles = 0; } break; case AsciiId<'R','E','C'>::V: NST_VERIFY( status == STOPPED ); if (status == STOPPED) { status = RECORDING; out = state.Read8(); cycles = state.Read32(); if (const dword multiplier = state.Read32()) cycles = cycles * (cpu.GetClockDivider() * TAPE_CLOCK) / multiplier; else cycles = 0; } break; case AsciiId<'D','A','T'>::V: { const dword size = state.Read32(); NST_VERIFY( size > 0 && size <= MAX_LENGTH ); if (size > 0 && size <= MAX_LENGTH) { stream.Resize( size ); state.Uncompress( stream.Begin(), size ); } break; } } state.End(); } if (status == PLAYING) { NST_VERIFY( pos < stream.Size() ); if (pos < stream.Size()) { Start(); } else { status = STOPPED; cycles = 0; pos = 0; in = 0; } } else if (status == RECORDING) { Start(); } } Result FamilyKeyboard::PlayTape() { return dataRecorder ? dataRecorder->Play() : RESULT_ERR_NOT_READY; } Result FamilyKeyboard::RecordTape() { return dataRecorder ? dataRecorder->Record() : RESULT_ERR_NOT_READY; } Result FamilyKeyboard::StopTape() { return dataRecorder ? dataRecorder->Stop() : RESULT_NOP; } bool FamilyKeyboard::IsTapeRecording() const { return dataRecorder ? dataRecorder->IsRecording() : false; } bool FamilyKeyboard::IsTapePlaying() const { return dataRecorder ? dataRecorder->IsPlaying() : false; } bool FamilyKeyboard::IsTapeStopped() const { return dataRecorder ? dataRecorder->IsStopped() : false; } bool FamilyKeyboard::IsTapePlayable() const { return dataRecorder ? dataRecorder->Playable() : false; } Result FamilyKeyboard::DataRecorder::Record() { if (status == RECORDING) return RESULT_NOP; if (status == PLAYING) return RESULT_ERR_NOT_READY; status = RECORDING; stream.Destroy(); Start(); return RESULT_OK; } Result FamilyKeyboard::DataRecorder::Play() { if (status == PLAYING) return RESULT_NOP; if (status == RECORDING || !Playable()) return RESULT_ERR_NOT_READY; status = PLAYING; Start(); return RESULT_OK; } NST_NO_INLINE void FamilyKeyboard::DataRecorder::Start() { clock = cpu.GetClockBase(); multiplier = cpu.GetClockDivider() * TAPE_CLOCK; cpu.AddHook( Hook(this,&DataRecorder::Hook_Tape) ); Api::TapeRecorder::eventCallback( status == PLAYING ? Api::TapeRecorder::EVENT_PLAYING : Api::TapeRecorder::EVENT_RECORDING ); } NST_NO_INLINE Result FamilyKeyboard::DataRecorder::Stop(const bool removeHook) { if (removeHook) cpu.RemoveHook( Hook(this,&DataRecorder::Hook_Tape) ); if (status == STOPPED) return RESULT_NOP; status = STOPPED; cycles = 0; multiplier = 0; in = 0; out = 0; pos = 0; Api::TapeRecorder::eventCallback( Api::TapeRecorder::EVENT_STOPPED ); return RESULT_OK; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void FamilyKeyboard::EndFrame() { if (dataRecorder) dataRecorder->EndFrame(); } void FamilyKeyboard::Poke(const uint data) { if (dataRecorder) dataRecorder->Poke( data ); if (data & COMMAND_KEY) { const uint out = data & COMMAND_SCAN; if (mode && !out && ++scan > 9) scan = 0; mode = out >> 1; if (data & COMMAND_RESET) scan = 0; } } uint FamilyKeyboard::Peek(uint port) { if (port == 0) { return dataRecorder ? dataRecorder->Peek() : 0; } else if (input && scan < 9) { Controllers::FamilyKeyboard::callback( input->familyKeyboard, scan, mode ); return ~uint(input->familyKeyboard.parts[scan]) & 0x1E; } else { return 0x1E; } } NES_HOOK(FamilyKeyboard::DataRecorder,Tape) { for (const qaword next = qaword(cpu.GetCycles()) * multiplier; cycles < next; cycles += clock) { if (status == PLAYING) { if (pos < stream.Size()) { const uint data = stream[pos++]; if (data >= 0x8C) { in = 0x2; } else if (data <= 0x74) { in = 0x0; } } else { Stop( false ); break; } } else { NST_ASSERT( status == RECORDING ); if (stream.Size() < MAX_LENGTH) { stream.Append( (out & 0x7) == 0x7 ? 0x90 : 0x70 ); } else { Stop( false ); break; } } } } } } } nestopia-1.51.1/source/core/input/NstInpFamilyKeyboard.hpp000066400000000000000000000037201411157722000235610ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_FAMILYKEYBOARD_H #define NST_INPUT_FAMILYKEYBOARD_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Input { class FamilyKeyboard : public Device { public: explicit FamilyKeyboard(Cpu&,bool); Result PlayTape(); Result RecordTape(); Result StopTape(); bool IsTapeRecording() const; bool IsTapePlaying() const; bool IsTapePlayable() const; bool IsTapeStopped() const; private: class DataRecorder; ~FamilyKeyboard(); void Reset(); void Poke(uint); uint Peek(uint); void EndFrame(); void LoadState(State::Loader&,dword); void SaveState(State::Saver&,byte) const; enum { COMMAND_RESET = 0x01, COMMAND_SCAN = 0x02, COMMAND_KEY = 0x04 }; uint mode; uint scan; DataRecorder* const dataRecorder; }; } } } #endif nestopia-1.51.1/source/core/input/NstInpFamilyTrainer.cpp000066400000000000000000000065161411157722000234260ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstInpDevice.hpp" #include "NstInpFamilyTrainer.hpp" namespace Nes { namespace Core { namespace Input { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif FamilyTrainer::FamilyTrainer(const Cpu& c) : Device(c,Api::Input::FAMILYTRAINER) { FamilyTrainer::Reset(); } void FamilyTrainer::Reset() { output = 0; state = ~0U; } void FamilyTrainer::SaveState(State::Saver& saver,const byte id) const { saver.Begin( AsciiId<'F','T'>::R(0,0,id) ).Write8( output ).End(); } void FamilyTrainer::LoadState(State::Loader& loader,const dword id) { if (id == AsciiId<'F','T'>::V) output = loader.Read8() & 0x1E; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void FamilyTrainer::Poll() { Controllers::FamilyTrainer& trainer = input->familyTrainer; input = NULL; if (Controllers::FamilyTrainer::callback( trainer )) { static const word lut[Controllers::FamilyTrainer::NUM_SIDE_A_BUTTONS] = { 1U << 1 ^ 0x1FFF, 1U << 2 ^ 0x1FFF, 1U << 3 ^ 0x1FFF, 1U << 4 ^ 0x1FFF, 1U << 5 ^ 0x1FFF, 1U << 6 ^ 0x1FFF, 1U << 7 ^ 0x1FFF, 1U << 8 ^ 0x1FFF, 1U << 9 ^ 0x1FFF, 1U << 10 ^ 0x1FFF, 1U << 11 ^ 0x1FFF, 1U << 12 ^ 0x1FFF }; uint bits = ~0U; for (uint i=0; i < Controllers::FamilyTrainer::NUM_SIDE_A_BUTTONS; ++i) { if (trainer.sideA[i]) bits &= lut[i]; } static const byte index[Controllers::FamilyTrainer::NUM_SIDE_B_BUTTONS] = { 2,1,7,6,5,4,10,9 }; for (uint i=0; i < Controllers::FamilyTrainer::NUM_SIDE_B_BUTTONS; ++i) { if (trainer.sideB[i]) bits &= lut[index[i]]; } state = bits; } } uint FamilyTrainer::Peek(uint port) { return port == 1 ? output : 0; } void FamilyTrainer::Poke(const uint data) { if (input) Poll(); if ((data & 0x1) == 0) { output = state >> 8 & 0x1E; } else if ((data & 0x2) == 0) { output = state >> 4 & 0x1E; } else if ((data & 0x4) == 0) { output = state >> 0 & 0x1E; } else { output = 0; } } } } } nestopia-1.51.1/source/core/input/NstInpFamilyTrainer.hpp000066400000000000000000000030551411157722000234260ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_FAMILYTRAINER_H #define NST_INPUT_FAMILYTRAINER_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Input { class FamilyTrainer : public Device { public: explicit FamilyTrainer(const Cpu&); private: void Reset(); void Poll(); void Poke(uint); uint Peek(uint); void LoadState(State::Loader&,dword); void SaveState(State::Saver&,byte) const; uint output; uint state; }; } } } #endif nestopia-1.51.1/source/core/input/NstInpHoriTrack.cpp000066400000000000000000000107011411157722000225350ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstInpDevice.hpp" #include "NstInpHoriTrack.hpp" namespace Nes { namespace Core { namespace Input { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif HoriTrack::HoriTrack(const Cpu& c) : Device(c,Api::Input::HORITRACK) { HoriTrack::Reset(); } void HoriTrack::Reset() { strobe = 0; stream = 0; state = 0xFF00U|CONNECTED; } void HoriTrack::SaveState(State::Saver& saver,const byte id) const { saver.Begin( AsciiId<'H','T'>::R(0,0,id) ).Write8( strobe ).Write32( stream ).End(); } void HoriTrack::LoadState(State::Loader& loader,const dword id) { if (id == AsciiId<'H','T'>::V) { strobe = loader.Read8() & 0x1; stream = loader.Read32(); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif uint HoriTrack::Peek(uint port) { if (port == 0) { port = stream; stream >>= 1; return port & 0x2; } else { return 0; } } void HoriTrack::Poke(uint data) { const uint prev = strobe; strobe = data & 0x1; if (prev > strobe) { if (input) { Controllers::HoriTrack& horiTrack = input->horiTrack; input = NULL; if (Controllers::HoriTrack::callback( horiTrack )) { dword bits = (horiTrack.buttons & 0xFF) | CONNECTED; if (horiTrack.mode & Controllers::HoriTrack::MODE_REVERSED) bits |= REVERSED; static const schar speeds[2][5] = { {0,4,8,16,24}, {1,16,32,48,56} }; const schar* NST_RESTRICT speed = speeds[0]; if (horiTrack.mode & Controllers::HoriTrack::MODE_LOWSPEED) { speed = speeds[1]; bits |= LOWSPEED; } int ox = x; int oy = y; x = NST_MIN(horiTrack.x,255); y = NST_MIN(horiTrack.y,239); ox -= x; oy -= y; if (ox > speed[0]) { bits |= ( (ox >= +speed[4]) ? (0x0000U|0x0100U) : (ox >= +speed[3]) ? (0x0800U|0x0100U) : (ox >= +speed[2]) ? (0x0400U|0x0100U) : (ox >= +speed[1]) ? (0x0200U|0x0100U) : (0x0600U|0x0100U) ); } else if (ox < -speed[0]) { bits |= ( (ox <= -speed[4]) ? (0x0600U|0x0000U) : (ox <= -speed[3]) ? (0x0200U|0x0000U) : (ox <= -speed[2]) ? (0x0400U|0x0000U) : (ox <= -speed[1]) ? (0x0800U|0x0000U) : (0x0000U|0x0000U) ); } else { bits |= 0x0F00; } if (oy > speed[0]) { bits |= ( (oy >= +speed[4]) ? (0x6000U|0x0000U) : (oy >= +speed[3]) ? (0x2000U|0x0000U) : (oy >= +speed[2]) ? (0x4000U|0x0000U) : (oy >= +speed[1]) ? (0x8000U|0x0000U) : (0x0000U|0x0000U) ); } else if (oy < -speed[0]) { bits |= ( (oy <= -speed[4]) ? (0x0000U|0x1000U) : (oy <= -speed[3]) ? (0x8000U|0x1000U) : (oy <= -speed[2]) ? (0x4000U|0x1000U) : (oy <= -speed[1]) ? (0x2000U|0x1000U) : (0x6000U|0x1000U) ); } else { bits |= 0xF000; } state = bits << 1; } } stream = state; } } } } } nestopia-1.51.1/source/core/input/NstInpHoriTrack.hpp000066400000000000000000000032471411157722000225510ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_HORITRACK_H #define NST_INPUT_HORITRACK_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Input { class HoriTrack : public Device { public: explicit HoriTrack(const Cpu&); private: enum { REVERSED = 0x010000, LOWSPEED = 0x020000, CONNECTED = 0x080000 }; void Reset(); void Poke(uint); uint Peek(uint); void LoadState(State::Loader&,dword); void SaveState(State::Saver&,byte) const; uint strobe; dword stream; dword state; uint x; uint y; }; } } } #endif nestopia-1.51.1/source/core/input/NstInpKonamiHyperShot.cpp000066400000000000000000000043461411157722000237430ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstInpDevice.hpp" #include "NstInpKonamiHyperShot.hpp" namespace Nes { namespace Core { namespace Input { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif KonamiHyperShot::KonamiHyperShot(const Cpu& c) : Device(c,Api::Input::KONAMIHYPERSHOT) { KonamiHyperShot::Reset(); } void KonamiHyperShot::Reset() { strobe = 0; state = 0; } void KonamiHyperShot::SaveState(State::Saver& saver,const byte id) const { saver.Begin( AsciiId<'H','S'>::R(0,0,id) ).Write8( strobe ).End(); } void KonamiHyperShot::LoadState(State::Loader& loader,const dword id) { if (id == AsciiId<'H','S'>::V) strobe = loader.Read8() & 0x1; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void KonamiHyperShot::Poke(const uint data) { const uint prev = strobe; strobe = data & 0x1; if (prev > strobe && input) { Controllers::KonamiHyperShot::callback( input->konamiHyperShot ); state = input->konamiHyperShot.buttons & 0x1E; input = NULL; } } uint KonamiHyperShot::Peek(const uint port) { return port ? state : 0; } } } } nestopia-1.51.1/source/core/input/NstInpKonamiHyperShot.hpp000066400000000000000000000030431411157722000237410ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_KONAMIHYPERSHOT_H #define NST_INPUT_KONAMIHYPERSHOT_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Input { class KonamiHyperShot : public Device { public: explicit KonamiHyperShot(const Cpu&); private: void Reset(); void Poke(uint); uint Peek(uint); void LoadState(State::Loader&,dword); void SaveState(State::Saver&,byte) const; uint strobe; uint state; }; } } } #endif nestopia-1.51.1/source/core/input/NstInpMahjong.cpp000066400000000000000000000037461411157722000222450ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstInpDevice.hpp" #include "NstInpMahjong.hpp" namespace Nes { namespace Core { namespace Input { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Mahjong::Mahjong(const Cpu& c) : Device(c,Api::Input::MAHJONG) { Mahjong::Reset(); } void Mahjong::Reset() { stream = 0; } void Mahjong::SaveState(State::Saver& saver,const byte id) const { saver.Begin( AsciiId<'M','J'>::R(0,0,id) ).End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Mahjong::Poke(uint data) { data &= PART; if (data && input) { Controllers::Mahjong::callback( input->mahjong, data ); stream = input->mahjong.buttons << 1; } else { stream = 0; } } uint Mahjong::Peek(uint port) { if (port) { port = stream & 0x2; stream >>= 1; } return port; } } } } nestopia-1.51.1/source/core/input/NstInpMahjong.hpp000066400000000000000000000027641411157722000222510ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_MAHJONG_H #define NST_INPUT_MAHJONG_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Input { class Mahjong : public Device { public: explicit Mahjong(const Cpu&); private: void Reset(); void Poke(uint); uint Peek(uint); void SaveState(State::Saver&,byte) const; enum { PART = 0x06 }; uint stream; }; } } } #endif nestopia-1.51.1/source/core/input/NstInpMouse.cpp000066400000000000000000000055671411157722000217550ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstInpDevice.hpp" #include "NstInpMouse.hpp" namespace Nes { namespace Core { namespace Input { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Mouse::Mouse(const Cpu& c) : Device(c,Api::Input::MOUSE) { Mouse::Reset(); } void Mouse::Reset() { strobe = 0; stream = 0; state = 0; } void Mouse::SaveState(State::Saver& saver,const byte id) const { const byte data[2] = { strobe, stream ^ 0xFF }; saver.Begin( AsciiId<'M','S'>::R(0,0,id) ).Write( data ).End(); } void Mouse::LoadState(State::Loader& loader,const dword id) { if (id == AsciiId<'M','S'>::V) { State::Loader::Data<2> data( loader ); strobe = data[0] & 0x1; stream = data[1] ^ 0xFF; } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif uint Mouse::Peek(uint) { const uint data = stream; stream >>= 1; return ~data & 0x1; } void Mouse::Poke(uint data) { const uint prev = strobe; strobe = data & 0x1; if (prev > strobe) { if (input) { Controllers::Mouse& mouse = input->mouse; input = NULL; if (Controllers::Mouse::callback( mouse )) { data = 0x00; if (mouse.button) data = 0x01; int ox = x; int oy = y; x = NST_MIN(mouse.x,255); y = NST_MIN(mouse.y,239); ox -= x; oy -= y; if (ox > 0) { data |= 0x0C; } else if (ox < 0) { data |= 0x04; } if (oy > 0) { data |= 0x30; } else if (oy < 0) { data |= 0x10; } state = data ^ 0xFF; } } stream = state; } } } } } nestopia-1.51.1/source/core/input/NstInpMouse.hpp000066400000000000000000000030471411157722000217510ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_MOUSE_H #define NST_INPUT_MOUSE_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Input { class Mouse : public Device { public: explicit Mouse(const Cpu&); private: void Reset(); void Poke(uint); uint Peek(uint); void LoadState(State::Loader&,dword); void SaveState(State::Saver&,byte) const; uint strobe; uint stream; uint state; uint x; uint y; }; } } } #endif nestopia-1.51.1/source/core/input/NstInpOekaKidsTablet.cpp000066400000000000000000000052641411157722000235050ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstInpDevice.hpp" #include "NstInpOekaKidsTablet.hpp" namespace Nes { namespace Core { namespace Input { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif OekaKidsTablet::OekaKidsTablet(const Cpu& c) : Device(c,Api::Input::OEKAKIDSTABLET) { OekaKidsTablet::Reset(); } void OekaKidsTablet::Reset() { latch = 0; state = 0; stream = 0; bits = 0; } void OekaKidsTablet::SaveState(State::Saver& saver,const byte id) const { saver.Begin( AsciiId<'O','T'>::R(0,0,id) ).End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void OekaKidsTablet::Poke(uint data) { if (data & 0x1) { if (~latch & data & 0x2) stream <<= 1; state = (data & 0x2) ? (~stream >> 15 & 0x8) : 0x4; latch = data; } else { state = 0; if (input) { Controllers::OekaKidsTablet& tablet = input->oekaKidsTablet; input = NULL; if (Controllers::OekaKidsTablet::callback( tablet )) { if (tablet.x <= 255 && tablet.y <= 239) { dword data = tablet.y * 256U / 240; if (data > 12) data = (data - 12) << 2; else data = 0; data |= (tablet.x * 240U / 256 + 8UL) << 10; if (tablet.button) { data |= 0x3; } else if (tablet.y >= 48) { data |= 0x2; } bits = data; } } } stream = bits; } } uint OekaKidsTablet::Peek(uint port) { return port ? state : 0; } } } } nestopia-1.51.1/source/core/input/NstInpOekaKidsTablet.hpp000066400000000000000000000030271411157722000235050ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_OEKAKIDSTABLET_H #define NST_INPUT_OEKAKIDSTABLET_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Input { class OekaKidsTablet : public Device { public: explicit OekaKidsTablet(const Cpu&); private: void Reset(); void Poke(uint); uint Peek(uint); void SaveState(State::Saver&,byte) const; uint latch; uint state; dword bits; dword stream; }; } } } #endif nestopia-1.51.1/source/core/input/NstInpPachinko.cpp000066400000000000000000000055401411157722000224100ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstInpDevice.hpp" #include "NstInpPachinko.hpp" namespace Nes { namespace Core { namespace Input { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Pachinko::Pachinko(const Cpu& c) : Device(c,Api::Input::PACHINKO) { Pachinko::Reset(); } void Pachinko::Reset() { strobe = 0; stream = 0; state = 0xFF0000; } void Pachinko::SaveState(State::Saver& saver,const byte id) const { saver.Begin( AsciiId<'P','A'>::R(0,0,id) ).Write8( strobe ).Write32( stream ).End(); } void Pachinko::LoadState(State::Loader& loader,const dword id) { if (id == AsciiId<'P','A'>::V) { strobe = loader.Read8() & 0x1; stream = loader.Read32(); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif uint Pachinko::Peek(uint port) { if (port == 0) { port = stream; stream >>= 1; return port & 0x2; } else { return 0; } } void Pachinko::Poke(uint data) { const uint prev = strobe; strobe = data & 0x1; if (prev > strobe) { if (input) { Controllers::Pachinko& pachinko = input->pachinko; input = NULL; if (Controllers::Pachinko::callback( pachinko )) { uint throttle = Clamp<-64,+63>(pachinko.throttle) + 192; throttle = ( (throttle >> 7 & 0x01) | (throttle >> 5 & 0x02) | (throttle >> 3 & 0x04) | (throttle >> 1 & 0x08) | (throttle << 1 & 0x10) | (throttle << 3 & 0x20) | (throttle << 5 & 0x40) | (throttle << 7 & 0x80) ); state = ((pachinko.buttons & 0xFF) | (throttle << 8) | 0xFF0000UL) << 1; } } stream = state; } } } } } nestopia-1.51.1/source/core/input/NstInpPachinko.hpp000066400000000000000000000030331411157722000224100ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_PACHINKO_H #define NST_INPUT_PACHINKO_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Input { class Pachinko : public Device { public: explicit Pachinko(const Cpu&); private: void Reset(); void Poke(uint); uint Peek(uint); void LoadState(State::Loader&,dword); void SaveState(State::Saver&,byte) const; uint strobe; dword stream; dword state; }; } } } #endif nestopia-1.51.1/source/core/input/NstInpPad.cpp000066400000000000000000000067221411157722000213630ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstInpDevice.hpp" #include "NstInpPad.hpp" #include "../NstCpu.hpp" namespace Nes { namespace Core { namespace Input { uint Pad::mic; #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Pad::Pad(const Cpu& c,uint i) : Device(c,Type(uint(Api::Input::PAD1) + i)) { NST_ASSERT( i < 4 ); NST_COMPILE_ASSERT ( ( Api::Input::PAD2 - Api::Input::PAD1 ) == 1 && ( Api::Input::PAD3 - Api::Input::PAD1 ) == 2 && ( Api::Input::PAD4 - Api::Input::PAD1 ) == 3 ); Pad::Reset(); } void Pad::Reset() { strobe = 0; stream = 0xFF; state = 0; mic = 0; } void Pad::SaveState(State::Saver& saver,const byte id) const { const byte data[2] = { strobe, stream ^ 0xFF }; saver.Begin( AsciiId<'P','D'>::R(0,0,id) ).Write( data ).End(); } void Pad::LoadState(State::Loader& loader,const dword id) { if (id == AsciiId<'P','D'>::V) { State::Loader::Data<2> data( loader ); strobe = data[0] & 0x1; stream = data[1] ^ 0xFF; } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Pad::BeginFrame(Controllers* i) { input = i; mic = 0; } void Pad::Poll() { if (input) { Controllers::Pad& pad = input->pad[type - Api::Input::PAD1]; input = NULL; if (Controllers::Pad::callback( pad, type - Api::Input::PAD1 )) { uint buttons = pad.buttons; enum { UP = Controllers::Pad::UP, RIGHT = Controllers::Pad::RIGHT, DOWN = Controllers::Pad::DOWN, LEFT = Controllers::Pad::LEFT }; if (!pad.allowSimulAxes) { if ((buttons & (UP|DOWN)) == (UP|DOWN)) buttons &= (UP|DOWN) ^ 0xFFU; if ((buttons & (LEFT|RIGHT)) == (LEFT|RIGHT)) buttons &= (LEFT|RIGHT) ^ 0xFFU; } state = buttons; } mic |= pad.mic; } } uint Pad::Peek(uint port) { if (strobe == 0) { const uint data = stream; stream >>= 1; return (~data & 0x1) | (mic & ~port << 2); } else { Poll(); return state & 0x1; } } void Pad::Poke(const uint data) { const uint prev = strobe; strobe = data & 0x1; if (prev > strobe) { Poll(); stream = state ^ 0xFF; } } } } } nestopia-1.51.1/source/core/input/NstInpPad.hpp000066400000000000000000000031171411157722000213630ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_PAD_H #define NST_INPUT_PAD_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Input { class Pad : public Device { public: Pad(const Cpu&,uint); private: void BeginFrame(Controllers*); void Reset(); void Poll(); void Poke(uint); uint Peek(uint); void LoadState(State::Loader&,dword); void SaveState(State::Saver&,byte) const; uint strobe; uint stream; uint state; static uint mic; }; } } } #endif nestopia-1.51.1/source/core/input/NstInpPaddle.cpp000066400000000000000000000057511411157722000220510ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstInpDevice.hpp" #include "NstInpPaddle.hpp" namespace Nes { namespace Core { namespace Input { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Paddle::Paddle(const Cpu& c,bool p) : Device(c,Api::Input::PADDLE), expPort(p) { Paddle::Reset(); } void Paddle::Reset() { stream[0] = 0; stream[1] = 0; shifter = 1; x = 0; button = 0; } void Paddle::SaveState(State::Saver& saver,const byte id) const { saver.Begin( AsciiId<'P','L'>::R(0,0,id) ).Write8( shifter ^ 1 ).End(); } void Paddle::LoadState(State::Loader& loader,const dword id) { if (id == AsciiId<'P','L'>::V) shifter = ~loader.Read8() & 0x1; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif uint Paddle::Peek(uint port) { if (!expPort) { port = stream[0]; stream[0] >>= shifter; return (port & 0x10) | stream[1]; } else if (port) { port = stream[0]; stream[0] >>= shifter; return port & 0x02; } else { return stream[1]; } } void Paddle::Poke(uint data) { const uint prev = shifter; shifter = ~data & 0x1; if (prev < shifter) { if (input) { Controllers::Paddle& paddle = input->paddle; input = NULL; if (Controllers::Paddle::callback( paddle )) { data = 0xFF - ((82 + 172 * (Clamp<32,176>(paddle.x) - 32U) / 144) & 0xFF); x = ( ( data & 0x01 ) << 7 | ( data & 0x02 ) << 5 | ( data & 0x04 ) << 3 | ( data & 0x08 ) << 1 | ( data & 0x10 ) >> 1 | ( data & 0x20 ) >> 3 | ( data & 0x40 ) >> 5 | ( data & 0x80 ) >> 7 ) << (expPort ? 1 : 4); button = (paddle.button ? expPort ? 0x2 : 0x8 : 0x0); } } stream[0] = x; stream[1] = button; } } } } } nestopia-1.51.1/source/core/input/NstInpPaddle.hpp000066400000000000000000000030711411157722000220470ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_PADDLE_H #define NST_INPUT_PADDLE_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Input { class Paddle : public Device { public: Paddle(const Cpu&,bool); private: void Reset(); uint Peek(uint); void Poke(uint); void LoadState(State::Loader&,dword); void SaveState(State::Saver&,byte) const; uint stream[2]; uint shifter; uint x; uint button; const ibool expPort; }; } } } #endif nestopia-1.51.1/source/core/input/NstInpPartyTap.cpp000066400000000000000000000042431411157722000224170ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstInpDevice.hpp" #include "NstInpPartyTap.hpp" namespace Nes { namespace Core { namespace Input { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif PartyTap::PartyTap(const Cpu& c) : Device(c,Api::Input::PARTYTAP) { PartyTap::Reset(); } void PartyTap::Reset() { strobe = 0; state = 0; mode = 0xE0; stream = 0; } void PartyTap::SaveState(State::Saver& saver,const byte id) const { saver.Begin( AsciiId<'P','T'>::R(0,0,id) ).End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void PartyTap::Poke(const uint data) { mode = 0xE0 - ((data & 0x4) << 4); const uint prev = strobe; strobe = data & 0x1; if (prev > strobe) { if (input) { Controllers::PartyTap::callback( input->partyTap ); state = input->partyTap.units; input = NULL; } stream = state; } } uint PartyTap::Peek(uint port) { if (port) { port = stream & 0x1C; stream = stream >> 3 | mode; } return port; } } } } nestopia-1.51.1/source/core/input/NstInpPartyTap.hpp000066400000000000000000000027761411157722000224350ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_PARTYTAP_H #define NST_INPUT_PARTYTAP_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Input { class PartyTap : public Device { public: explicit PartyTap(const Cpu&); private: void Reset(); void Poke(uint); uint Peek(uint); void SaveState(State::Saver&,byte) const; uint strobe; uint state; uint mode; uint stream; }; } } } #endif nestopia-1.51.1/source/core/input/NstInpPokkunMoguraa.cpp000066400000000000000000000037501411157722000234400ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstInpDevice.hpp" #include "NstInpPokkunMoguraa.hpp" namespace Nes { namespace Core { namespace Input { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif PokkunMoguraa::PokkunMoguraa(const Cpu& c) : Device(c,Api::Input::POKKUNMOGURAA) { PokkunMoguraa::Reset(); } void PokkunMoguraa::Reset() { state = 0x1E; } void PokkunMoguraa::SaveState(State::Saver& saver,const byte id) const { saver.Begin( AsciiId<'P','M'>::R(0,0,id) ).End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void PokkunMoguraa::Poke(const uint data) { if (input) { Controllers::PokkunMoguraa::callback( input->pokkunMoguraa, ~data & 0x7 ); state = ~input->pokkunMoguraa.buttons & 0x1E; } else { state = 0x1E; } } uint PokkunMoguraa::Peek(const uint port) { return port ? state : 0; } } } } nestopia-1.51.1/source/core/input/NstInpPokkunMoguraa.hpp000066400000000000000000000027361411157722000234500ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_POKKUNMOGURAA_H #define NST_INPUT_POKKUNMOGURAA_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Input { class PokkunMoguraa : public Device { public: explicit PokkunMoguraa(const Cpu&); private: void Reset(); void Poke(uint); uint Peek(uint); void SaveState(State::Saver&,byte) const; uint state; }; } } } #endif nestopia-1.51.1/source/core/input/NstInpPowerGlove.cpp000066400000000000000000000107041411157722000227430ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstInpDevice.hpp" #include "NstInpPowerGlove.hpp" namespace Nes { namespace Core { namespace Input { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif PowerGlove::PowerGlove(const Cpu& c) : Device(c,Api::Input::POWERGLOVE) { buffer[0x0] = 0xA0; buffer[0x1] = 0x00; buffer[0x2] = 0x00; buffer[0x3] = 0x00; buffer[0x4] = 0x00; buffer[0x5] = 0x00; buffer[0x6] = 0x00; buffer[0x7] = 0x00; buffer[0x8] = 0x00; buffer[0x9] = 0x3F; buffer[0xA] = 0xFF; buffer[0xB] = 0xFF; PowerGlove::Reset(); } void PowerGlove::Reset() { latch = 0; stream = ~0U; output = 0; counter = 0; buffer[1] = 0; buffer[2] = 0; buffer[3] = 0; buffer[4] = 0; buffer[5] = 0; buffer[6] = 0; z = 32; r = 32; } void PowerGlove::SaveState(State::Saver& saver,const byte id) const { const byte data[4] = { latch, stream == ~0U ? 0xFF : stream, output, counter }; saver.Begin( AsciiId<'P','G'>::R(0,0,id) ).Write( data ).End(); } void PowerGlove::LoadState(State::Loader& loader,const dword id) { buffer[3] = 0; buffer[4] = 0; z = 32; r = 32; if (id == AsciiId<'P','G'>::V) { State::Loader::Data<4> data( loader ); latch = data[0]; stream = data[1] < (12U << 3) ? data[1] : ~0U; output = data[2]; counter = NST_MIN(data[3],8+3); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void PowerGlove::BeginFrame(Controllers* i) { input = i; } void PowerGlove::Poll() { Controllers::PowerGlove& glove = input->powerGlove; input = NULL; if (Controllers::PowerGlove::callback( glove )) { buffer[1] = (glove.x - 128U) & 0xFF; buffer[2] = (128U - glove.y) & 0xFF; if (glove.distance < 0) { z += (z < 63); } else if (glove.distance > 0) { z -= (z > 0); } buffer[3] = (z/2 - 16U) & 0xFF; if (glove.distance < 0) { r += (r < 63); } else if (glove.distance > 0) { r -= (r > 0); } else if (r < 32) { ++r; } else if (r > 32) { --r; } buffer[4] = (r/2 - 16U) & 0xFF; buffer[5] = glove.gesture; if (glove.buttons & Controllers::PowerGlove::START) { buffer[6] = 0x82; } else if (glove.buttons & Controllers::PowerGlove::SELECT) { buffer[6] = 0x83; } else { buffer[6] = 0xFF; } } } uint PowerGlove::Peek(uint) { uint data = 0; if (stream != ~0U) { data = stream++; if (!(data & 0x7)) { if (input) Poll(); output = buffer[data >> 3] ^ 0xFFU; } else if (data == (12U << 3) - 1) { stream = 0; } data = output >> 7; output = output << 1 & 0xFFU; } return data; } void PowerGlove::Poke(const uint data) { latch = (latch << 1 & 0xFE) | (data & 0x01); if (latch == 0x06 && counter == 0) { stream = ~0U; } else if (latch == 0xFF) { stream = ~0U; counter = 1; } else if (counter && counter++ == 8+3) { stream = 0; counter = 0; } } } } } nestopia-1.51.1/source/core/input/NstInpPowerGlove.hpp000066400000000000000000000032321411157722000227460ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_POWERGLOVE_H #define NST_INPUT_POWERGLOVE_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Input { class PowerGlove : public Device { public: explicit PowerGlove(const Cpu&); private: void BeginFrame(Controllers*); void Reset(); void Poll(); void Poke(uint); uint Peek(uint); void LoadState(State::Loader&,dword); void SaveState(State::Saver&,byte) const; uint latch; uint stream; byte buffer[12]; byte output; byte counter; byte z; byte r; }; } } } #endif nestopia-1.51.1/source/core/input/NstInpPowerPad.cpp000066400000000000000000000067561411157722000224070ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstInpDevice.hpp" #include "NstInpPowerPad.hpp" namespace Nes { namespace Core { namespace Input { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif PowerPad::PowerPad(const Cpu& c) : Device(c,Api::Input::POWERPAD) { PowerPad::Reset(); } void PowerPad::Reset() { shifter = 2; stream = 0x55FFUL << 3; state = 0x55FFUL << 3; } void PowerPad::SaveState(State::Saver& saver,const byte id) const { saver.Begin( AsciiId<'P','P'>::R(0,0,id) ).Write8( shifter >> 1 ^ 0x1 ).Write16( stream >> 3 ^ 0x55FFU ).End(); } void PowerPad::LoadState(State::Loader& loader,const dword id) { if (id == AsciiId<'P','P'>::V) { shifter = (~loader.Read8() & 0x1) << 1; stream = ((loader.Read16() & 0x55FFUL) ^ 0x55FFUL) << 3; } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif uint PowerPad::Peek(uint) { const uint data = stream; stream >>= shifter; return ~data & 0x18; } void PowerPad::Poke(uint data) { const uint prev = shifter; shifter = (~data & 0x1) << 1; if (prev > shifter) { if (input) { Controllers::PowerPad& power = input->powerPad; input = NULL; if (Controllers::PowerPad::callback( power )) { static const dword lut[Controllers::PowerPad::NUM_SIDE_A_BUTTONS] = { ( 0x02UL << 4 | 0x00UL ), ( 0x01UL << 3 | 0x00UL ), ( 0x00UL | 0x02UL << 5 ), ( 0x00UL | 0x01UL << 4 ), ( 0x04UL << 5 | 0x00UL ), ( 0x10UL << 7 | 0x00UL ), ( 0x80UL << 10 | 0x00UL ), ( 0x00UL | 0x08UL << 7 ), ( 0x08UL << 6 | 0x00UL ), ( 0x20UL << 8 | 0x00UL ), ( 0x40UL << 9 | 0x00UL ), ( 0x00UL | 0x04UL << 6 ) }; data = 0; for (uint i=0; i < Controllers::PowerPad::NUM_SIDE_A_BUTTONS; ++i) { if (power.sideA[i]) data |= lut[i]; } static const byte index[Controllers::PowerPad::NUM_SIDE_B_BUTTONS] = { 2,1,7,6,5,4,10,9 }; for (uint i=0; i < Controllers::PowerPad::NUM_SIDE_B_BUTTONS; ++i) { if (power.sideB[i]) data |= lut[index[i]]; } state = data ^ (0x55FFUL << 3); } } stream = state; } } } } } nestopia-1.51.1/source/core/input/NstInpPowerPad.hpp000066400000000000000000000030341411157722000223760ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_POWERPAD_H #define NST_INPUT_POWERPAD_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Input { class PowerPad : public Device { public: explicit PowerPad(const Cpu&); private: void Reset(); void Poke(uint); uint Peek(uint); void LoadState(State::Loader&,dword); void SaveState(State::Saver&,byte) const; dword stream; uint shifter; dword state; }; } } } #endif nestopia-1.51.1/source/core/input/NstInpRob.cpp000066400000000000000000000070121411157722000213720ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstInpDevice.hpp" #include "NstInpRob.hpp" #include "../NstPpu.hpp" namespace Nes { namespace Core { namespace Input { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Rob::Rob(const Cpu& c,const Ppu& ppu) : Device(c,Api::Input::ROB), palette(ppu.GetPalette().ram) { Rob::Reset(); } void Rob::Reset() { strobe = 0; stream = 0xFF; state = 0; shifter = 1; code = 0; } void Rob::SaveState(State::Saver& saver,const byte id) const { byte data[6] = { strobe, stream ^ 0xFF, state, 0, code & 0xFF, code >> 8 }; while (!(shifter & 1U << data[3])) ++data[3]; saver.Begin( AsciiId<'R','O'>::R(0,0,id) ).Write( data ).End(); } void Rob::LoadState(State::Loader& loader,const dword id) { if (id == AsciiId<'R','O'>::V) { State::Loader::Data<6> data( loader ); strobe = data[0] & 0x1; stream = data[1] ^ 0xFF; state = data[2]; shifter = 1U << NST_MIN(data[3],13); code = data[4] | (data[5] << 8 & 0x100); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Rob::BeginFrame(Controllers*) { for (uint i=1; i < 16; ++i) { if (palette[0] != palette[i]) { shifter = 1; code = 0; return; } } if (palette[0] - uint(SIGNAL_COLOR) < uint(SIGNAL_RANGE)) code |= shifter; if (shifter != 0x1000) { shifter <<= 1; if (shifter == 0x40 && code == 0) shifter = 1; } else { uint tmp = code; code = 0; shifter = 1; switch (tmp) { case CODE_OPEN_ARM: state ^= 0x01; break; case CODE_CLOSE_ARM: state ^= 0x02; break; case CODE_TEST: state ^= 0x04; break; case CODE_UNUSED: state ^= 0x08; break; case CODE_RAISE_ARM: state ^= 0x10; break; case CODE_LOWER_ARM: state ^= 0x20; break; case CODE_TURN_LEFT: state ^= 0x40; break; case CODE_TURN_RIGHT: state ^= 0x80; break; } } } uint Rob::Peek(uint) { if (strobe == 0) { const uint data = stream; stream >>= 1; return ~data & 0x1; } else { return state & 0x1; } } void Rob::Poke(uint data) { const uint prev = strobe; strobe = data & 0x1; if (prev > strobe) stream = state ^ 0xFF; } } } } nestopia-1.51.1/source/core/input/NstInpRob.hpp000066400000000000000000000037471411157722000214120ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_ROB_H #define NST_INPUT_ROB_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class Ppu; namespace Input { class Rob : public Device { public: Rob(const Cpu&,const Ppu&); private: enum { SIGNAL_COLOR = 0x29, SIGNAL_RANGE = 3 }; enum { CODE_OPEN_ARM = 0x0EE8, CODE_CLOSE_ARM = 0x0FA8, CODE_TEST = 0x1AE8, CODE_UNUSED = 0x0AAA, CODE_RAISE_ARM = 0x1BA8, CODE_LOWER_ARM = 0x1BE8, CODE_TURN_LEFT = 0x0BA8, CODE_TURN_RIGHT = 0x0AE8 }; void BeginFrame(Controllers*); void Reset(); void Poke(uint); uint Peek(uint); void LoadState(State::Loader&,dword); void SaveState(State::Saver&,byte) const; uint strobe; uint stream; uint state; uint shifter; uint code; const byte (&palette)[32]; }; } } } #endif nestopia-1.51.1/source/core/input/NstInpSuborKeyboard.cpp000066400000000000000000000051731411157722000234310ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstInpDevice.hpp" #include "NstInpSuborKeyboard.hpp" namespace Nes { namespace Core { namespace Input { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif SuborKeyboard::SuborKeyboard(const Cpu& c) : Device(c,Api::Input::SUBORKEYBOARD) { SuborKeyboard::Reset(); } void SuborKeyboard::Reset() { scan = 0; mode = 0; } void SuborKeyboard::SaveState(State::Saver& saver,const byte id) const { saver.Begin( AsciiId<'S','K'>::R(0,0,id) ).Write8( mode | (scan << 1) ).End(); } void SuborKeyboard::LoadState(State::Loader& loader,const dword id) { if (id == AsciiId<'S','K'>::V) { const uint data = loader.Read8(); mode = data & 0x1; scan = data >> 1 & 0xF; if (scan > 12) scan = 0; } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void SuborKeyboard::Poke(const uint data) { if (data & COMMAND_KEY) { const uint out = data & COMMAND_SCAN; if (mode && !out && ++scan > 12) scan = 0; mode = out >> 1; if (data & COMMAND_RESET) scan = 0; } } uint SuborKeyboard::Peek(uint port) { if (port == 0) { return 0x00; } else if (input && scan < 10) { Controllers::SuborKeyboard::callback( input->suborKeyboard, scan, mode ); return ~uint(input->suborKeyboard.parts[scan]) & 0x1E; } else { return 0x1E; } } } } } nestopia-1.51.1/source/core/input/NstInpSuborKeyboard.hpp000066400000000000000000000032061411157722000234310ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_SUBORKEYBOARD_H #define NST_INPUT_SUBORKEYBOARD_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Input { class SuborKeyboard : public Device { public: explicit SuborKeyboard(const Cpu&); private: void Reset(); void Poke(uint); uint Peek(uint); void LoadState(State::Loader&,dword); void SaveState(State::Saver&,byte) const; enum { COMMAND_RESET = 0x01, COMMAND_SCAN = 0x02, COMMAND_KEY = 0x04 }; uint mode; uint scan; }; } } } #endif nestopia-1.51.1/source/core/input/NstInpTopRider.cpp000066400000000000000000000106261411157722000224050ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstInpDevice.hpp" #include "NstInpTopRider.hpp" namespace Nes { namespace Core { namespace Input { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif TopRider::TopRider(const Cpu& c) : Device(c,Api::Input::TOPRIDER) { TopRider::Reset(); } void TopRider::Reset() { state[0] = 0; state[1] = 0; stream[0] = 0; stream[1] = 0; strobe = 0; buttons = 0; brake = 0; accel = 0; pos = 0; } void TopRider::SaveState(State::Saver& saver,const byte id) const { saver.Begin( AsciiId<'T','R'>::R(0,0,id) ).End(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void TopRider::BeginFrame(Controllers* const controllers) { if (controllers) { Controllers::TopRider::callback( controllers->topRider ); uint data = controllers->topRider.buttons; if ((data & STEERING) == STEERING) data &= STEERING ^ 0xFFU; if ( !(data & STEERING) ) pos += (pos > 0 ? -1 : pos < 0 ? +1 : 0); else if ( data & STEER_LEFT ) pos -= (pos > -MAX_STEER); else if ( data & STEER_RIGHT ) pos += (pos < +MAX_STEER); if (data & BRAKE) brake += (brake < MAX_BRAKE); else brake -= (brake > 0); if (data & ACCEL) accel += (accel < MAX_ACCEL); else accel -= (accel > 0); buttons &= (0x80U|0x40U); if (data & SHIFT_GEAR) { if (!(buttons & 0x40)) { buttons ^= 0x80; buttons |= 0x40; } } else { buttons &= 0x40U ^ 0xFFU; } buttons |= ( (( data & REAR ) >> 5) | (( data & SELECT ) << 3) | (( data & START ) << 1) ); data = 0; if (pos > 0) { if (pos > DEADZONE_MAX) data = (0x20U | 0x080U); else if (pos > DEADZONE_MID) data = (0x20U | 0x000U); else if (pos > DEADZONE_MIN) data = (0x00U | 0x080U); } else { if (pos < -DEADZONE_MAX) data = (0x40U | 0x100U); else if (pos < -DEADZONE_MID) data = (0x40U | 0x000U); else if (pos < -DEADZONE_MIN) data = (0x00U | 0x100U); } state[0] = data | ((buttons & 0x01) << (4+7)) | ((buttons & 0x80) << (4-1)); data = 0; if (accel > 8 || brake < 8) { if (accel > DEADZONE_MAX) data = 0x008; else if (accel > DEADZONE_MID) data = 0x080; else if (accel > DEADZONE_MIN) data = 0x100; } else { state[0] |= 0x200; if (brake > DEADZONE_MAX) data = 0x10; else if (brake > DEADZONE_MID) data = 0x20; else if (brake > DEADZONE_MIN) data = 0x40; } state[1] = data | ((buttons & 0x30) << (3+2)); } else { buttons = 0; brake = 0; accel = 0; pos = 0; state[0] = 0; state[1] = 0; } } void TopRider::Poke(uint data) { const uint prev = strobe; strobe = data & 0x1; if (prev > strobe) { stream[0] = state[0]; stream[1] = state[1]; } } uint TopRider::Peek(uint port) { if (port) { port = (stream[0] & 0x10) | (stream[1] & 0x08); stream[0] >>= 1, stream[1] >>= 1; } return port; } } } } nestopia-1.51.1/source/core/input/NstInpTopRider.hpp000066400000000000000000000040171411157722000224070ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_TOPRIDER_H #define NST_INPUT_TOPRIDER_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { namespace Input { class TopRider : public Device { public: explicit TopRider(const Cpu&); private: void Reset(); void BeginFrame(Controllers*); void Poke(uint); uint Peek(uint); void SaveState(State::Saver&,byte) const; enum { DEADZONE_MAX = 16, DEADZONE_MID = 10, DEADZONE_MIN = 4, MAX_STEER = 20, MAX_BRAKE = 20, MAX_ACCEL = 20, BRAKE = 0x01, ACCEL = 0x02, SELECT = 0x04, START = 0x08, SHIFT_GEAR = 0x10, REAR = 0x20, STEER_LEFT = 0x40, STEER_RIGHT = 0x80, STEERING = STEER_LEFT|STEER_RIGHT }; uint stream[2]; uint state[2]; uint strobe; int pos; uint accel; uint brake; uint buttons; }; } } } #endif nestopia-1.51.1/source/core/input/NstInpTurboFile.cpp000066400000000000000000000065471411157722000225570ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstInpDevice.hpp" #include "NstInpTurboFile.hpp" namespace Nes { namespace Core { namespace Input { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif TurboFile::TurboFile(const Cpu& cpu) : Device(cpu,Api::Input::TURBOFILE) { std::memset( ram, 0, SIZE ); file.Load( File::TURBOFILE, ram, SIZE ); } TurboFile::~TurboFile() { file.Save( File::TURBOFILE, ram, SIZE ); } void TurboFile::Reset() { pos = 0x00; bit = 0x01; old = 0x00; out = 0x00; } void TurboFile::SaveState(State::Saver& saver,const byte id) const { saver.Begin( AsciiId<'T','F'>::R(0,0,id) ); uint count; for (count=0; bit && bit != (1U << count); ++count); const byte data[3] = { pos & 0xFF, pos >> 8, count | (old << 1) | (out << 2) }; saver.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End(); saver.Begin( AsciiId<'R','A','M'>::V ).Compress( ram ).End(); saver.End(); } void TurboFile::LoadState(State::Loader& loader,const dword id) { if (id == AsciiId<'T','F'>::V) { while (const dword chunk = loader.Begin()) { switch (chunk) { case AsciiId<'R','E','G'>::V: { State::Loader::Data<3> data( loader ); pos = data[0] | (data[1] << 8 & 0x1F00); bit = 1U << (data[2] & 0x7); old = data[2] >> 1 & WRITE_BIT; out = data[2] >> 2 & READ_BIT; break; } case AsciiId<'R','A','M'>::V: loader.Uncompress( ram ); break; } loader.End(); } } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void TurboFile::Poke(uint data) { if (!(data & NO_RESET)) { pos = 0x00; bit = 0x01; } const uint advance = old; old = data & WRITE_ENABLE; if (old) { ram[pos] = (ram[pos] & ~bit) | (bit * (data & WRITE_BIT)); } else if (advance) { if (bit != 0x80) { bit <<= 1; } else { bit = 0x01; pos = (pos + 1) & (SIZE-1); } } out = (ram[pos] & bit) ? READ_BIT : 0; } uint TurboFile::Peek(uint port) { return port ? out : 0; } } } } nestopia-1.51.1/source/core/input/NstInpTurboFile.hpp000066400000000000000000000034611411157722000225540ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_TURBOFILE_H #define NST_INPUT_TURBOFILE_H #ifdef NST_PRAGMA_ONCE #pragma once #endif #include "../NstFile.hpp" namespace Nes { namespace Core { namespace Input { class TurboFile : public Device { public: explicit TurboFile(const Cpu&); private: ~TurboFile(); void Reset(); void LoadState(State::Loader&,dword); void SaveState(State::Saver&,byte) const; void Poke(uint); uint Peek(uint); enum { SIZE = SIZE_8K }; enum { WRITE_BIT = 0x01, NO_RESET = 0x02, WRITE_ENABLE = 0x04, READ_BIT = 0x04 }; uint pos; uint bit; uint old; uint out; byte ram[SIZE]; File file; }; } } } #endif nestopia-1.51.1/source/core/input/NstInpZapper.cpp000066400000000000000000000157231411157722000221210ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstInpDevice.hpp" #include "../NstPpu.hpp" #include "NstInpZapper.hpp" namespace Nes { namespace Core { namespace Input { const byte Zapper::lightMap[Video::Screen::PALETTE] = { 0x66, 0x28, 0x23, 0x24, 0x29, 0x28, 0x25, 0x2B, 0x2F, 0x2E, 0x30, 0x2F, 0x2E, 0x00, 0x00, 0x00, 0xAD, 0x56, 0x56, 0x56, 0x56, 0x56, 0x57, 0x5C, 0x60, 0x60, 0x5B, 0x5A, 0x59, 0x00, 0x00, 0x00, 0xFF, 0xA2, 0x9D, 0x9D, 0xA3, 0xA4, 0xA5, 0xA7, 0xA9, 0xA8, 0xA7, 0xA7, 0xA7, 0x4F, 0x00, 0x00, 0xFF, 0xD9, 0xD7, 0xD8, 0xDA, 0xDA, 0xDB, 0xDC, 0xDC, 0xDC, 0xDB, 0xDC, 0xDC, 0xB8, 0x00, 0x00, 0x5C, 0x19, 0x1B, 0x26, 0x2C, 0x2B, 0x24, 0x22, 0x25, 0x26, 0x23, 0x22, 0x21, 0x00, 0x00, 0x00, 0xA0, 0x48, 0x48, 0x48, 0x4A, 0x49, 0x49, 0x50, 0x55, 0x54, 0x4E, 0x49, 0x49, 0x20, 0x00, 0x00, 0xE6, 0x92, 0x8D, 0x8E, 0x90, 0x8A, 0x8C, 0x95, 0x99, 0x98, 0x96, 0x95, 0x95, 0x46, 0x00, 0x00, 0xE6, 0xC9, 0xC7, 0xC8, 0xC4, 0xC1, 0xC1, 0xC5, 0xC9, 0xCA, 0xCA, 0xC9, 0xC9, 0xA9, 0x00, 0x00, 0x5C, 0x25, 0x1A, 0x19, 0x1E, 0x1C, 0x1F, 0x26, 0x29, 0x2C, 0x32, 0x30, 0x2B, 0x00, 0x00, 0x00, 0x9F, 0x4C, 0x48, 0x48, 0x48, 0x48, 0x4C, 0x55, 0x5A, 0x5A, 0x59, 0x57, 0x54, 0x10, 0x00, 0x00, 0xEA, 0x95, 0x94, 0x94, 0x95, 0x95, 0x95, 0x9B, 0x9F, 0x9F, 0x99, 0x96, 0x95, 0x46, 0x00, 0x00, 0xEA, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xCA, 0xCA, 0xCA, 0xC9, 0xCA, 0xC9, 0xA9, 0x00, 0x00, 0x50, 0x16, 0xF0, 0x1A, 0x20, 0x1E, 0x1B, 0x1A, 0x1D, 0x1E, 0x23, 0x22, 0x1D, 0x00, 0x00, 0x00, 0x8F, 0x38, 0x38, 0x38, 0x39, 0x38, 0x3B, 0x44, 0x49, 0x48, 0x46, 0x43, 0x41, 0x00, 0x00, 0x00, 0xD7, 0x7F, 0x7E, 0x7E, 0x7F, 0x7F, 0x80, 0x85, 0x89, 0x89, 0x83, 0x7F, 0x7F, 0x3B, 0x00, 0x00, 0xD7, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0x98, 0x00, 0x00, 0x5C, 0x24, 0x19, 0x20, 0x26, 0x25, 0x1C, 0x1E, 0x21, 0x23, 0x29, 0x2B, 0x2A, 0x00, 0x00, 0x00, 0x9F, 0x4B, 0x44, 0x44, 0x48, 0x48, 0x49, 0x4A, 0x4F, 0x4E, 0x4E, 0x55, 0x53, 0x10, 0x00, 0x00, 0xE8, 0x8A, 0x85, 0x86, 0x8C, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x93, 0x46, 0x00, 0x00, 0xE8, 0xC2, 0xC0, 0xC0, 0xC2, 0xC6, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC6, 0xA9, 0x00, 0x00, 0x50, 0x16, 0x14, 0x1F, 0x25, 0x23, 0x1C, 0x15, 0x19, 0x19, 0x1E, 0x1D, 0x1C, 0x00, 0x00, 0x00, 0x8F, 0x38, 0x37, 0x39, 0x40, 0x3E, 0x38, 0x3E, 0x42, 0x42, 0x3F, 0x41, 0x40, 0x00, 0x00, 0x00, 0xD7, 0x7A, 0x75, 0x75, 0x7B, 0x7F, 0x7F, 0x80, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x3B, 0x00, 0x00, 0xD7, 0xB2, 0xAF, 0xB0, 0xB2, 0xB3, 0xB3, 0xB4, 0xB4, 0xB3, 0xB3, 0xB4, 0xB3, 0x98, 0x00, 0x00, 0x4F, 0x1C, 0x12, 0x17, 0x1C, 0x1B, 0x15, 0x17, 0x1A, 0x22, 0x27, 0x25, 0x23, 0x00, 0x00, 0x00, 0x8F, 0x40, 0x38, 0x37, 0x38, 0x38, 0x38, 0x41, 0x45, 0x45, 0x4A, 0x4A, 0x49, 0x00, 0x00, 0x00, 0xD7, 0x7E, 0x79, 0x7A, 0x7F, 0x7F, 0x7F, 0x80, 0x84, 0x84, 0x80, 0x80, 0x7F, 0x3B, 0x00, 0x00, 0xD7, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB4, 0xB4, 0xB4, 0xB3, 0xB4, 0xB3, 0x98, 0x00, 0x00, 0x45, 0x15, 0x10, 0x19, 0x1F, 0x1D, 0x18, 0x14, 0x17, 0x1B, 0x21, 0x1F, 0x1C, 0x00, 0x00, 0x00, 0x85, 0x3A, 0x36, 0x36, 0x3A, 0x38, 0x37, 0x40, 0x45, 0x44, 0x44, 0x44, 0x43, 0x00, 0x00, 0x00, 0xCE, 0x7E, 0x79, 0x7A, 0x7F, 0x7F, 0x7F, 0x80, 0x85, 0x85, 0x80, 0x80, 0x7F, 0x30, 0x00, 0x00, 0xCE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAF, 0xAF, 0xAE, 0xAE, 0xAE, 0x8E, 0x00, 0x00 }; #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Zapper::Zapper(const Cpu& c,Ppu& p) : Device (c,Api::Input::ZAPPER), arcade (false), ppu (p) { Zapper::Reset(); } void Zapper::Reset() { shifter = 1; stream = 0x10; pos = ~0U; fire = 0; } void Zapper::Initialize(bool a) { arcade = a; } void Zapper::SaveState(State::Saver& saver,const byte id) const { const byte data[2] = { arcade ? shifter ? 0x1 : 0x3 : 0x0, arcade ? stream : 0x00 }; saver.Begin( AsciiId<'Z','P'>::R(0,0,id) ).Write( data ).End(); } void Zapper::LoadState(State::Loader& loader,const dword id) { if (id == AsciiId<'Z','P'>::V) { State::Loader::Data<2> data( loader ); if (data[0] & 0x1U) { shifter = ~data[0] >> 1 & 0x1; stream = data[1]; } } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif uint Zapper::Poll() { if (input) { Controllers::Zapper& zapper = input->zapper; input = NULL; if (Controllers::Zapper::callback( zapper )) { fire = (zapper.fire ? arcade ? 0x80 : 0x10 : 0x00); if (zapper.y < Video::Screen::HEIGHT && zapper.x < Video::Screen::WIDTH) pos = zapper.y * Video::Screen::WIDTH + zapper.x; else pos = ~0U; } } if (pos < Video::Screen::WIDTH * Video::Screen::HEIGHT) { ppu.Update(); uint pixel = ppu.GetPixelCycles(); if (pos < pixel && pos >= pixel - PHOSPHOR_DECAY) { pixel = ppu.GetPixel( pos ); if (arcade) { NST_COMPILE_ASSERT( LIGHT_SENSOR >= 0x3F ); NST_VERIFY( pixel <= 0x3F ); if (pixel > 0x3F) return pixel; pixel = ppu.GetYuvColor( pixel ); } return GetLightMap( pixel ); } } return 0; } void Zapper::Poke(const uint data) { if (arcade) { shifter = ~data & 0x1; stream = (Poll() >= LIGHT_SENSOR ? 0x40 : 0x00); stream |= 0x10 | fire; } } uint Zapper::Peek(uint) { if (!arcade) { uint data = (Poll() >= LIGHT_SENSOR ? 0x0 : 0x8); return data | fire; } else { const uint data = stream; stream >>= shifter; return data & 0x1; } } } } } nestopia-1.51.1/source/core/input/NstInpZapper.hpp000066400000000000000000000037001411157722000221160ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_INPUT_ZAPPER_H #define NST_INPUT_ZAPPER_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class Ppu; namespace Input { class Zapper : public Device { public: Zapper(const Cpu&,Ppu&); private: void Reset(); void Initialize(bool); uint Poll(); void Poke(uint); uint Peek(uint); uint GetHitPixel() const; void LoadState(State::Loader&,dword); void SaveState(State::Saver&,byte) const; enum { PHOSPHOR_DECAY = 384, LIGHT_SENSOR = 0x40 }; ibool arcade; uint stream; uint shifter; uint pos; uint fire; Ppu& ppu; static const byte lightMap[Video::Screen::PALETTE]; public: static uint GetLightMap(uint pixel) { NST_ASSERT( pixel < Video::Screen::PALETTE ); return lightMap[pixel]; } }; } } } #endif nestopia-1.51.1/source/core/vssystem/000077500000000000000000000000001411157722000175465ustar00rootroot00000000000000nestopia-1.51.1/source/core/vssystem/NstVsRbiBaseball.cpp000066400000000000000000000040611411157722000234130ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstCpu.hpp" #include "../NstState.hpp" #include "../vssystem/NstVsSystem.hpp" #include "../vssystem/NstVsRbiBaseball.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Cartridge::VsSystem::RbiBaseball::Reset() { cpu.Map( 0x5E00 ).Set( &RbiBaseball::Peek_5E00 ); cpu.Map( 0x5E01 ).Set( &RbiBaseball::Peek_5E01 ); counter = 0; } void Cartridge::VsSystem::RbiBaseball::SubSave(State::Saver& state) const { state.Begin( AsciiId<'R','B','I'>::V ).Write8( counter & 0xFF ).End(); } void Cartridge::VsSystem::RbiBaseball::SubLoad(State::Loader& state,const dword chunk) { if (chunk == AsciiId<'R','B','I'>::V) counter = state.Read8(); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK(Cartridge::VsSystem::RbiBaseball,5E00) { counter = 0; return 0x00; } NES_PEEK(Cartridge::VsSystem::RbiBaseball,5E01) { return (counter++ == 0x9) ? 0x6F : 0xB4; } } } nestopia-1.51.1/source/core/vssystem/NstVsRbiBaseball.hpp000066400000000000000000000030471411157722000234230ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_VS_RBIBASEBALL_H #define NST_VS_RBIBASEBALL_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class Cartridge::VsSystem::RbiBaseball : public Cartridge::VsSystem { public: explicit RbiBaseball(Context& c) : VsSystem(c) {} private: ~RbiBaseball() {} void Reset(); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); NES_DECL_PEEK( 5E00 ); NES_DECL_PEEK( 5E01 ); uint counter; }; } } #endif nestopia-1.51.1/source/core/vssystem/NstVsSuperXevious.cpp000066400000000000000000000037651411157722000237440ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstCpu.hpp" #include "../vssystem/NstVsSystem.hpp" #include "../vssystem/NstVsSuperXevious.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Cartridge::VsSystem::SuperXevious::Reset() { cpu.Map( 0x54FF ).Set( &SuperXevious::Peek_54FF ); cpu.Map( 0x5567 ).Set( &SuperXevious::Peek_5567 ); cpu.Map( 0x5678 ).Set( &SuperXevious::Peek_5678 ); cpu.Map( 0x578F ).Set( &SuperXevious::Peek_578F ); protection = 0; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK(Cartridge::VsSystem::SuperXevious,54FF) { return 0x05; } NES_PEEK(Cartridge::VsSystem::SuperXevious,5567) { return (protection ^= 0x1) ? 0x37 : 0x3E; } NES_PEEK(Cartridge::VsSystem::SuperXevious,5678) { return protection ? 0x00 : 0x01; } NES_PEEK(Cartridge::VsSystem::SuperXevious,578F) { return protection ? 0xD1 : 0x89; } } } nestopia-1.51.1/source/core/vssystem/NstVsSuperXevious.hpp000066400000000000000000000030261411157722000237370ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_VS_SUPERXEVIOUS_H #define NST_VS_SUPERXEVIOUS_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class Cartridge::VsSystem::SuperXevious : public Cartridge::VsSystem { public: explicit SuperXevious(Context& c) : VsSystem(c) {} private: ~SuperXevious() {} void Reset(); NES_DECL_PEEK( 54FF ); NES_DECL_PEEK( 5678 ); NES_DECL_PEEK( 578F ); NES_DECL_PEEK( 5567 ); uint protection; }; } } #endif nestopia-1.51.1/source/core/vssystem/NstVsSystem.cpp000066400000000000000000002020311411157722000225320ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstLog.hpp" #include "../NstCpu.hpp" #include "../NstPpu.hpp" #include "../NstState.hpp" #include "NstVsSystem.hpp" #include "NstVsRbiBaseball.hpp" #include "NstVsTkoBoxing.hpp" #include "NstVsSuperXevious.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif class Cartridge::VsSystem::Dip { class Proxy; struct Setting { uint data; cstring name; }; Setting* settings; uint size; uint selection; uint mask; cstring name; public: struct Value { cstring const name; const uint data; const uint selection; Value(cstring n,uint d,uint s=0) : name(n), data(d), selection(s) {} }; void operator = (const Value&); private: class Proxy { Dip& dip; const uint index; public: Proxy(Dip& d,uint i) : dip(d), index(i) {} void operator = (const Value& value) { dip.settings[index].data = value.data; dip.settings[index].name = value.name; } operator uint() const { return dip.settings[index].data; } cstring Name() const { return dip.settings[index].name; } }; public: Dip() : settings(NULL) {} ~Dip() { delete [] settings; } uint Size() const { return size; } void Select(uint i) { NST_ASSERT( i < size ); selection = i; } uint Selection() const { return selection; } Proxy operator [] (uint i) { NST_ASSERT( i < size ); return Proxy(*this,i); } cstring Name() const { return name; } }; void Cartridge::VsSystem::Dip::operator = (const Value& value) { NST_ASSERT( settings == NULL && value.data && value.selection < value.data ); name = value.name; size = value.data; selection = value.selection; settings = new Setting [size]; } Cartridge::VsSystem::VsDipSwitches::VsDipSwitches(Dip*& old,uint n) : table(old), size(n) { old = NULL; regs[0] = 0; regs[1] = 0; for (uint i=0; i < n; ++i) { regs[0] |= (table[i][table[i].Selection()] & DIPSWITCH_4016_MASK) << DIPSWITCH_4016_SHIFT; regs[1] |= (table[i][table[i].Selection()] & DIPSWITCH_4017_MASK) << DIPSWITCH_4017_SHIFT; } } Cartridge::VsSystem::VsDipSwitches::~VsDipSwitches() { delete [] table; } inline void Cartridge::VsSystem::VsDipSwitches::Reset() { coinTimer = 0; regs[0] &= ~uint(COIN); } inline uint Cartridge::VsSystem::VsDipSwitches::Reg(uint i) const { return regs[i]; } uint Cartridge::VsSystem::VsDipSwitches::NumDips() const { return size; } uint Cartridge::VsSystem::VsDipSwitches::NumValues(uint dip) const { NST_ASSERT( dip < size ); return table[dip].Size(); } cstring Cartridge::VsSystem::VsDipSwitches::GetDipName(uint dip) const { NST_ASSERT( dip < size ); return table[dip].Name(); } cstring Cartridge::VsSystem::VsDipSwitches::GetValueName(uint dip,uint value) const { NST_ASSERT( dip < size && value < table[dip].Size() ); return table[dip][value].Name(); } uint Cartridge::VsSystem::VsDipSwitches::GetValue(uint dip) const { NST_ASSERT( dip < size ); return table[dip].Selection(); } void Cartridge::VsSystem::VsDipSwitches::SetValue(uint dip,uint value) { NST_ASSERT( dip < size && value < table[dip].Size() ); const uint old = table[dip].Selection(); regs[0] &= ~((table[dip][old] & DIPSWITCH_4016_MASK) << DIPSWITCH_4016_SHIFT); regs[1] &= ~((table[dip][old] & DIPSWITCH_4017_MASK) << DIPSWITCH_4017_SHIFT); table[dip].Select( value ); regs[0] |= (table[dip][value] & DIPSWITCH_4016_MASK) << DIPSWITCH_4016_SHIFT; regs[1] |= (table[dip][value] & DIPSWITCH_4017_MASK) << DIPSWITCH_4017_SHIFT; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Cartridge::VsSystem::VsDipSwitches::BeginFrame(Input::Controllers* const input) { if (!coinTimer) { if (input) { Input::Controllers::VsSystem::callback( input->vsSystem ); if (input->vsSystem.insertCoin & COIN) { regs[0] |= input->vsSystem.insertCoin & COIN; coinTimer = 20; } } } else if (--coinTimer == 15) { regs[0] &= ~uint(COIN); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif struct Cartridge::VsSystem::Context { Dip* dips; uint numDips; Cpu& cpu; Ppu& ppu; PpuModel ppuModel; Mode mode; InputMapper::Type inputMapper; Context(Cpu& c,Ppu& p) : dips (NULL), numDips (0), cpu (c), ppu (p), ppuModel (PPU_RP2C03B), mode (MODE_STD), inputMapper (InputMapper::TYPE_NONE) { } void SetDips(uint n) { numDips = n; dips = new Dip [n]; } }; Cartridge::VsSystem* Cartridge::VsSystem::Create ( Cpu& cpu, Ppu& ppu, const PpuModel ppuModel, const dword prgCrc ) { switch (prgCrc) { // VS. Dual-System Games are unsupported case 0xB90497AA: // Tennis case 0x2A909613: // Tennis (alt) case 0xBC202DB6: // Tennis P2 case 0x008A9C16: // Wrecking Crew P1 case 0x30C42B1E: // Wrecking Crew P2 case 0xAD407F52: // Balloon Fight P1 case 0x6AD67502: // Balloon Fight P2 case 0x18A93B7B: // Mahjong (J) case 0xA2AD7D61: // Mahjong (J) (alt) case 0xA9A4A6C5: // Mahjong (J) P1 case 0x78D1D213: // Mahjong (J) P2 case 0x13A91937: // Baseball P1 case 0xC4DD2523: // Baseball P1 (alt 1) case 0xB5853830: // Baseball P1 (alt 2) case 0x968A6E9D: // Baseball P2 case 0xF64D7252: // Baseball P2 (alt 1) case 0xF5DEBF88: // Baseball P2 (alt 2) case 0xF42DAB14: // Ice Climber P1 case 0x7D6B764F: // Ice Climber P2 throw RESULT_ERR_UNSUPPORTED_VSSYSTEM; } Context context( cpu, ppu ); try { // Credit to the MAME devs for much of the DIP switch info. switch (prgCrc) { case 0xEB2DBA63: // TKO Boxing context.SetDips(7); context.dips[0] = Dip::Value( "Coinage", 4, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x01 ); context.dips[0][2] = Dip::Value( "2 Coins / 1 Credit", 0x02 ); context.dips[0][3] = Dip::Value( "3 Coins / 1 Credit", 0x03 ); context.dips[1] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[1][0] = Dip::Value( "Off", 0x00 ); context.dips[1][1] = Dip::Value( "On", 0x04 ); context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[2][0] = Dip::Value( "Off", 0x00 ); context.dips[2][1] = Dip::Value( "On", 0x08 ); context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[3][0] = Dip::Value( "Off", 0x00 ); context.dips[3][1] = Dip::Value( "On", 0x10 ); context.dips[4] = Dip::Value( "Palette Color", 2, 1 ); context.dips[4][0] = Dip::Value( "Black", 0x00 ); context.dips[4][1] = Dip::Value( "White", 0x20 ); context.dips[5] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[5][0] = Dip::Value( "Off", 0x00 ); context.dips[5][1] = Dip::Value( "On", 0x40 ); context.dips[6] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[6][0] = Dip::Value( "Off", 0x00 ); context.dips[6][1] = Dip::Value( "On", 0x80 ); context.inputMapper = InputMapper::TYPE_1; context.mode = MODE_TKO; break; case 0x135ADF7C: // RBI Baseball context.SetDips(4); context.dips[0] = Dip::Value( "Coinage", 4, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x01 ); context.dips[0][2] = Dip::Value( "2 Coins / 1 Credit", 0x02 ); context.dips[0][3] = Dip::Value( "3 Coins / 1 Credit", 0x03 ); context.dips[1] = Dip::Value( "Max. 1p/in, 2p/in, Min", 4, 1 ); context.dips[1][0] = Dip::Value( "2, 1, 3", 0x04 ); context.dips[1][1] = Dip::Value( "2, 2, 4", 0x0C ); context.dips[1][2] = Dip::Value( "3, 2, 6", 0x00 ); context.dips[1][3] = Dip::Value( "4, 3, 7", 0x08 ); context.dips[2] = Dip::Value( "Demo Sounds", 2, 1 ); context.dips[2][0] = Dip::Value( "Off", 0x00 ); context.dips[2][1] = Dip::Value( "On", 0x10 ); context.dips[3] = Dip::Value( "PPU", 5, 0 ); context.dips[3][0] = Dip::Value( "RP2C03", 0x20 ); context.dips[3][1] = Dip::Value( "RP2C04-0001", 0x00 ); context.dips[3][2] = Dip::Value( "RP2C04-0002", 0x40 ); context.dips[3][3] = Dip::Value( "RP2C04-0003", 0x80 ); context.dips[3][4] = Dip::Value( "RP2C04-0004", 0xC0 ); context.inputMapper = InputMapper::TYPE_2; context.mode = MODE_RBI; break; case 0xED588F00: // Duck Hunt context.SetDips(4); context.dips[0] = Dip::Value( "Coinage", 8, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); context.dips[0][3] = Dip::Value( "2 Coins / 1 Credit", 0x06 ); context.dips[0][4] = Dip::Value( "3 Coins / 1 Credit", 0x01 ); context.dips[0][5] = Dip::Value( "4 Coins / 1 Credit", 0x05 ); context.dips[0][6] = Dip::Value( "5 Coins / 1 Credit", 0x03 ); context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); context.dips[1] = Dip::Value( "Difficulty", 4, 1 ); context.dips[1][0] = Dip::Value( "Easy", 0x00 ); context.dips[1][1] = Dip::Value( "Normal", 0x08 ); context.dips[1][2] = Dip::Value( "Hard", 0x10 ); context.dips[1][3] = Dip::Value( "Very Hard", 0x18 ); context.dips[2] = Dip::Value( "Misses per Game", 2, 1 ); context.dips[2][0] = Dip::Value( "3", 0x00 ); context.dips[2][1] = Dip::Value( "5", 0x20 ); context.dips[3] = Dip::Value( "Bonus Life", 4, 0 ); context.dips[3][0] = Dip::Value( "30000", 0x00 ); context.dips[3][1] = Dip::Value( "50000", 0x40 ); context.dips[3][2] = Dip::Value( "80000", 0x80 ); context.dips[3][3] = Dip::Value( "100000", 0xC0 ); break; case 0x16D3F469: // Ninja Jajamaru Kun (J) context.SetDips(5); context.dips[0] = Dip::Value( "Coinage", 8, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); context.dips[0][3] = Dip::Value( "1 Coin / 4 Credits", 0x06 ); context.dips[0][4] = Dip::Value( "2 Coins / 1 Credit", 0x01 ); context.dips[0][5] = Dip::Value( "3 Coins / 1 Credit", 0x05 ); context.dips[0][6] = Dip::Value( "4 Coins / 1 Credit", 0x03 ); context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); context.dips[1] = Dip::Value( "Lives", 3, 0 ); context.dips[1][0] = Dip::Value( "3", 0x00 ); context.dips[1][1] = Dip::Value( "4", 0x10 ); context.dips[1][2] = Dip::Value( "5", 0x08 ); context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[2][0] = Dip::Value( "Off", 0x00 ); context.dips[2][1] = Dip::Value( "On", 0x20 ); context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[3][0] = Dip::Value( "Off", 0x00 ); context.dips[3][1] = Dip::Value( "On", 0x40 ); context.dips[4] = Dip::Value( "Demo Sounds", 2, 1 ); context.dips[4][0] = Dip::Value( "Off", 0x00 ); context.dips[4][1] = Dip::Value( "On", 0x80 ); context.ppuModel = PPU_RC2C05_01; context.inputMapper = InputMapper::TYPE_3; break; case 0x8850924B: // Tetris context.SetDips(6); context.dips[0] = Dip::Value( "Coinage", 4, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x02 ); context.dips[0][2] = Dip::Value( "2 Coins / 1 Credit", 0x01 ); context.dips[0][3] = Dip::Value( "3 Coins / 1 Credit", 0x03 ); context.dips[1] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[1][0] = Dip::Value( "Off", 0x00 ); context.dips[1][1] = Dip::Value( "On", 0x04 ); context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[2][0] = Dip::Value( "Off", 0x00 ); context.dips[2][1] = Dip::Value( "On", 0x08 ); context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[3][0] = Dip::Value( "Off", 0x00 ); context.dips[3][1] = Dip::Value( "On", 0x10 ); context.dips[4] = Dip::Value( "Palette Color", 3, 2 ); context.dips[4][0] = Dip::Value( "Black", 0x40 ); context.dips[4][1] = Dip::Value( "Green", 0x20 ); context.dips[4][2] = Dip::Value( "Grey", 0x60 ); context.dips[5] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[5][0] = Dip::Value( "Off", 0x00 ); context.dips[5][1] = Dip::Value( "On", 0x80 ); context.inputMapper = InputMapper::TYPE_2; break; case 0x8C0C2DF5: // Top Gun context.SetDips(5); context.dips[0] = Dip::Value( "Coinage", 8, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); context.dips[0][3] = Dip::Value( "2 Coins / 1 Credit", 0x06 ); context.dips[0][4] = Dip::Value( "3 Coins / 1 Credit", 0x01 ); context.dips[0][5] = Dip::Value( "4 Coins / 1 Credit", 0x05 ); context.dips[0][6] = Dip::Value( "5 Coins / 1 Credit", 0x03 ); context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); context.dips[1] = Dip::Value( "Lives per Coin", 2, 0 ); context.dips[1][0] = Dip::Value( "3 - 12 Max", 0x00 ); context.dips[1][1] = Dip::Value( "2 - 9 Max", 0x08 ); context.dips[2] = Dip::Value( "Bonus", 4, 0 ); context.dips[2][0] = Dip::Value( "30k and every 50k", 0x00 ); context.dips[2][1] = Dip::Value( "50k and every 100k", 0x20 ); context.dips[2][2] = Dip::Value( "100k and every 150k", 0x10 ); context.dips[2][3] = Dip::Value( "200k and every 200k", 0x30 ); context.dips[3] = Dip::Value( "Difficulty", 2, 0 ); context.dips[3][0] = Dip::Value( "Normal", 0x00 ); context.dips[3][1] = Dip::Value( "Hard", 0x40 ); context.dips[4] = Dip::Value( "Demo Sounds", 2, 1 ); context.dips[4][0] = Dip::Value( "Off", 0x00 ); context.dips[4][1] = Dip::Value( "On", 0x80 ); context.ppuModel = PPU_RC2C05_04; context.inputMapper = InputMapper::TYPE_1; break; case 0x70901B25: // Slalom context.SetDips(5); context.dips[0] = Dip::Value( "Coinage", 8, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); context.dips[0][3] = Dip::Value( "2 Coins / 1 Credit", 0x06 ); context.dips[0][4] = Dip::Value( "3 Coins / 1 Credit", 0x01 ); context.dips[0][5] = Dip::Value( "4 Coins / 1 Credit", 0x05 ); context.dips[0][6] = Dip::Value( "5 Coins / 1 Credit", 0x03 ); context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); context.dips[1] = Dip::Value( "Freestyle Points", 2, 0 ); context.dips[1][0] = Dip::Value( "Left / Right", 0x00 ); context.dips[1][1] = Dip::Value( "Hold Time", 0x08 ); context.dips[2] = Dip::Value( "Difficulty", 4, 1 ); context.dips[2][0] = Dip::Value( "Easy", 0x00 ); context.dips[2][1] = Dip::Value( "Normal", 0x10 ); context.dips[2][2] = Dip::Value( "Hard", 0x20 ); context.dips[2][3] = Dip::Value( "Hardest", 0x30 ); context.dips[3] = Dip::Value( "Allow Continue", 2, 1 ); context.dips[3][0] = Dip::Value( "No", 0x40 ); context.dips[3][1] = Dip::Value( "Yes", 0x00 ); context.dips[4] = Dip::Value( "Inverted input", 2, 0 ); context.dips[4][0] = Dip::Value( "Off", 0x00 ); context.dips[4][1] = Dip::Value( "On", 0x80 ); context.ppuModel = PPU_RP2C04_0002; context.inputMapper = InputMapper::TYPE_1; break; case 0xCF36261E: // Super Sky Kid context.SetDips(5); context.dips[0] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[0][0] = Dip::Value( "Off", 0x00 ); context.dips[0][1] = Dip::Value( "On", 0x01 ); context.dips[1] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[1][0] = Dip::Value( "Off", 0x00 ); context.dips[1][1] = Dip::Value( "On", 0x02 ); context.dips[2] = Dip::Value( "Lives", 2, 0 ); context.dips[2][0] = Dip::Value( "2", 0x00 ); context.dips[2][1] = Dip::Value( "3", 0x04 ); context.dips[3] = Dip::Value( "Coinage", 4, 0 ); context.dips[3][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[3][1] = Dip::Value( "1 Coin / 2 Credits", 0x08 ); context.dips[3][2] = Dip::Value( "2 Coins / 1 Credit", 0x10 ); context.dips[3][3] = Dip::Value( "3 Coins / 1 Credit", 0x18 ); context.dips[4] = Dip::Value( "PPU", 5, 0 ); context.dips[4][0] = Dip::Value( "RP2C03", 0x20 ); context.dips[4][1] = Dip::Value( "RP2C04-0001", 0x00 ); context.dips[4][2] = Dip::Value( "RP2C04-0002", 0x40 ); context.dips[4][3] = Dip::Value( "RP2C04-0003", 0x80 ); context.dips[4][4] = Dip::Value( "RP2C04-0004", 0xC0 ); context.inputMapper = InputMapper::TYPE_3; break; case 0xE1AA8214: // Star Luster context.SetDips(6); context.dips[0] = Dip::Value( "Coinage", 4, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x02 ); context.dips[0][2] = Dip::Value( "2 Coins / 1 Credit", 0x01 ); context.dips[0][3] = Dip::Value( "3 Coins / 1 Credit", 0x03 ); context.dips[1] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[1][0] = Dip::Value( "Off", 0x00 ); context.dips[1][1] = Dip::Value( "On", 0x04 ); context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[2][0] = Dip::Value( "Off", 0x00 ); context.dips[2][1] = Dip::Value( "On", 0x08 ); context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[3][0] = Dip::Value( "Off", 0x00 ); context.dips[3][1] = Dip::Value( "On", 0x10 ); context.dips[4] = Dip::Value( "Palette Color", 3, 0 ); context.dips[4][0] = Dip::Value( "Black", 0x40 ); context.dips[4][1] = Dip::Value( "Green", 0x20 ); context.dips[4][2] = Dip::Value( "Grey", 0x60 ); context.dips[5] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[5][0] = Dip::Value( "Off", 0x00 ); context.dips[5][1] = Dip::Value( "On", 0x80 ); context.inputMapper = InputMapper::TYPE_1; break; case 0xD5D7EAC4: // Dr. Mario context.SetDips(5); context.dips[0] = Dip::Value( "Drop Rate Increases After", 4, 0 ); context.dips[0][0] = Dip::Value( "7 Pills", 0x00 ); context.dips[0][1] = Dip::Value( "8 Pills", 0x01 ); context.dips[0][2] = Dip::Value( "9 Pills", 0x02 ); context.dips[0][3] = Dip::Value( "10 Pills", 0x03 ); context.dips[1] = Dip::Value( "Virus Level", 4, 0 ); context.dips[1][0] = Dip::Value( "1", 0x00 ); context.dips[1][1] = Dip::Value( "3", 0x04 ); context.dips[1][2] = Dip::Value( "5", 0x08 ); context.dips[1][3] = Dip::Value( "7", 0x0C ); context.dips[2] = Dip::Value( "Drop Speed Up", 4, 0 ); context.dips[2][0] = Dip::Value( "Slow", 0x00 ); context.dips[2][1] = Dip::Value( "Medium", 0x10 ); context.dips[2][2] = Dip::Value( "Fast", 0x20 ); context.dips[2][3] = Dip::Value( "Fastest", 0x30 ); context.dips[3] = Dip::Value( "Free Play", 2, 0 ); context.dips[3][0] = Dip::Value( "Off", 0x00 ); context.dips[3][1] = Dip::Value( "On", 0x40 ); context.dips[4] = Dip::Value( "Demo Sounds", 2, 1 ); context.dips[4][0] = Dip::Value( "Off", 0x00 ); context.dips[4][1] = Dip::Value( "On", 0x80 ); context.ppuModel = PPU_RP2C04_0003; context.inputMapper = InputMapper::TYPE_2; break; case 0xFFBEF374: // Castlevania context.SetDips(4); context.dips[0] = Dip::Value( "Coinage", 8, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); context.dips[0][3] = Dip::Value( "2 Coins / 1 Credit", 0x06 ); context.dips[0][4] = Dip::Value( "3 Coins / 1 Credit", 0x01 ); context.dips[0][5] = Dip::Value( "4 Coins / 1 Credit", 0x05 ); context.dips[0][6] = Dip::Value( "5 Coins / 1 Credit", 0x03 ); context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); context.dips[1] = Dip::Value( "Lives", 2, 1 ); context.dips[1][0] = Dip::Value( "2", 0x08 ); context.dips[1][1] = Dip::Value( "3", 0x00 ); context.dips[2] = Dip::Value( "Bonus", 4, 0 ); context.dips[2][0] = Dip::Value( "100k", 0x00 ); context.dips[2][1] = Dip::Value( "200k", 0x20 ); context.dips[2][2] = Dip::Value( "300k", 0x10 ); context.dips[2][3] = Dip::Value( "400k", 0x30 ); context.dips[3] = Dip::Value( "Difficulty", 2, 0 ); context.dips[3][0] = Dip::Value( "Normal", 0x00 ); context.dips[3][1] = Dip::Value( "Hard", 0x40 ); context.ppuModel = PPU_RP2C04_0002; context.inputMapper = InputMapper::TYPE_1; break; case 0xE2C0A2BE: // Platoon context.SetDips(6); context.dips[0] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[0][0] = Dip::Value( "Off", 0x00 ); context.dips[0][1] = Dip::Value( "On", 0x01 ); context.dips[1] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[1][0] = Dip::Value( "Off", 0x00 ); context.dips[1][1] = Dip::Value( "On", 0x02 ); context.dips[2] = Dip::Value( "Demo Sounds", 2, 1 ); context.dips[2][0] = Dip::Value( "Off", 0x00 ); context.dips[2][1] = Dip::Value( "On", 0x04 ); context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[3][0] = Dip::Value( "Off", 0x00 ); context.dips[3][1] = Dip::Value( "On", 0x08 ); context.dips[4] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[4][0] = Dip::Value( "Off", 0x00 ); context.dips[4][1] = Dip::Value( "On", 0x10 ); context.dips[5] = Dip::Value( "Coinage", 8, 0 ); context.dips[5][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[5][1] = Dip::Value( "1 Coin / 2 Credits", 0x20 ); context.dips[5][2] = Dip::Value( "1 Coin / 3 Credits", 0x40 ); context.dips[5][3] = Dip::Value( "2 Coins / 1 Credit", 0x60 ); context.dips[5][4] = Dip::Value( "3 Coins / 1 Credit", 0x80 ); context.dips[5][5] = Dip::Value( "4 Coins / 1 Credit", 0xA0 ); context.dips[5][6] = Dip::Value( "5 Coins / 1 Credit", 0xC0 ); context.dips[5][7] = Dip::Value( "Free Play", 0xE0 ); context.ppuModel = PPU_RP2C04_0001; context.inputMapper = InputMapper::TYPE_1; break; case 0xCBE85490: // Excitebike case 0x29155E0C: // Excitebike (alt) context.SetDips(4); context.dips[0] = Dip::Value( "Coinage", 8, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); context.dips[0][3] = Dip::Value( "1 Coin / 4 Credits", 0x06 ); context.dips[0][4] = Dip::Value( "2 Coins / 1 Credit", 0x01 ); context.dips[0][5] = Dip::Value( "3 Coins / 1 Credit", 0x05 ); context.dips[0][6] = Dip::Value( "4 Coins / 1 Credit", 0x03 ); context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); context.dips[1] = Dip::Value( "Bonus", 4, 0 ); context.dips[1][0] = Dip::Value( "100k and Every 50k", 0x00 ); context.dips[1][1] = Dip::Value( "Every 100k", 0x10 ); context.dips[1][2] = Dip::Value( "100k Only", 0x08 ); context.dips[1][3] = Dip::Value( "None", 0x18 ); context.dips[2] = Dip::Value( "1st Half Qualifying Time", 2, 0 ); context.dips[2][0] = Dip::Value( "Normal", 0x00 ); context.dips[2][1] = Dip::Value( "Hard", 0x20 ); context.dips[3] = Dip::Value( "2nd Half Qualifying Time", 2, 0 ); context.dips[3][0] = Dip::Value( "Normal", 0x00 ); context.dips[3][1] = Dip::Value( "Hard", 0x40 ); if (prgCrc == 0x29155E0C) context.ppuModel = PPU_RP2C04_0004; else context.ppuModel = PPU_RP2C04_0003; context.inputMapper = InputMapper::TYPE_1; break; case 0x07138C06: // Clu Clu Land context.SetDips(5); context.dips[0] = Dip::Value( "Coinage", 8, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); context.dips[0][3] = Dip::Value( "1 Coin / 4 Credits", 0x06 ); context.dips[0][4] = Dip::Value( "2 Coins / 1 Credit", 0x01 ); context.dips[0][5] = Dip::Value( "3 Coins / 1 Credit", 0x05 ); context.dips[0][6] = Dip::Value( "4 Coins / 1 Credit", 0x03 ); context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); context.dips[1] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[1][0] = Dip::Value( "Off", 0x00 ); context.dips[1][1] = Dip::Value( "On", 0x08 ); context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[2][0] = Dip::Value( "Off", 0x00 ); context.dips[2][1] = Dip::Value( "On", 0x10 ); context.dips[3] = Dip::Value( "Lives", 4, 1 ); context.dips[3][0] = Dip::Value( "2", 0x60 ); context.dips[3][1] = Dip::Value( "3", 0x00 ); context.dips[3][2] = Dip::Value( "4", 0x40 ); context.dips[3][3] = Dip::Value( "5", 0x20 ); context.dips[4] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[4][0] = Dip::Value( "Off", 0x00 ); context.dips[4][1] = Dip::Value( "On", 0x80 ); context.ppuModel = PPU_RP2C04_0004; context.inputMapper = InputMapper::TYPE_2; break; case 0x43A357EF: // Ice Climber case 0xD4EB5923: // -||- context.SetDips(4); context.dips[0] = Dip::Value( "Coinage", 8, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); context.dips[0][3] = Dip::Value( "1 Coin / 4 Credits", 0x06 ); context.dips[0][4] = Dip::Value( "2 Coins / 1 Credit", 0x01 ); context.dips[0][5] = Dip::Value( "3 Coins / 1 Credit", 0x05 ); context.dips[0][6] = Dip::Value( "4 Coins / 1 Credit", 0x03 ); context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); context.dips[1] = Dip::Value( "Lives", 4, 0 ); context.dips[1][0] = Dip::Value( "3", 0x00 ); context.dips[1][1] = Dip::Value( "4", 0x10 ); context.dips[1][2] = Dip::Value( "5", 0x08 ); context.dips[1][3] = Dip::Value( "7", 0x18 ); context.dips[2] = Dip::Value( "Difficulty", 2, 0 ); context.dips[2][0] = Dip::Value( "Normal", 0x00 ); context.dips[2][1] = Dip::Value( "Hard", 0x20 ); context.dips[3] = Dip::Value( "Time before the bear", 2, 0 ); context.dips[3][0] = Dip::Value( "Long", 0x00 ); context.dips[3][1] = Dip::Value( "Short", 0x40 ); context.ppuModel = PPU_RP2C04_0004; if (prgCrc == 0x43A357EF) context.inputMapper = InputMapper::TYPE_2; else context.inputMapper = InputMapper::TYPE_4; break; case 0x737DD1BF: // Super Mario Bros case 0x4BF3972D: // -||- case 0x8B60CC58: // -||- case 0x8192C804: // -||- context.SetDips(5); context.dips[0] = Dip::Value( "Coinage", 8, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x06 ); context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x01 ); context.dips[0][3] = Dip::Value( "1 Coin / 4 Credits", 0x05 ); context.dips[0][4] = Dip::Value( "1 Coin / 5 Credits", 0x03 ); context.dips[0][5] = Dip::Value( "2 Coins / 1 Credit", 0x04 ); context.dips[0][6] = Dip::Value( "3 Coins / 1 Credit", 0x02 ); context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); context.dips[1] = Dip::Value( "Lives", 2, 1 ); context.dips[1][0] = Dip::Value( "2", 0x08 ); context.dips[1][1] = Dip::Value( "3", 0x00 ); context.dips[2] = Dip::Value( "Bonus Life", 4, 0 ); context.dips[2][0] = Dip::Value( "100", 0x00 ); context.dips[2][1] = Dip::Value( "150", 0x20 ); context.dips[2][2] = Dip::Value( "200", 0x10 ); context.dips[2][3] = Dip::Value( "250", 0x30 ); context.dips[3] = Dip::Value( "Timer", 2, 0 ); context.dips[3][0] = Dip::Value( "Normal", 0x00 ); context.dips[3][1] = Dip::Value( "Fast", 0x40 ); context.dips[4] = Dip::Value( "Continue Lives", 2, 0 ); context.dips[4][0] = Dip::Value( "3", 0x80 ); context.dips[4][1] = Dip::Value( "4", 0x00 ); context.ppuModel = PPU_RP2C04_0004; context.inputMapper = InputMapper::TYPE_1; break; case 0xEC461DB9: // Pinball case 0xE528F651: // -||- (alt) context.SetDips(5); context.dips[0] = Dip::Value( "Coinage", 8, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x01 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x06 ); context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); context.dips[0][3] = Dip::Value( "1 Coin / 4 Credits", 0x04 ); context.dips[0][4] = Dip::Value( "2 Coins / 1 Credit", 0x05 ); context.dips[0][5] = Dip::Value( "3 Coins / 1 Credit", 0x03 ); context.dips[0][6] = Dip::Value( "4 Coins / 1 Credit", 0x07 ); context.dips[0][7] = Dip::Value( "Free Play", 0x00 ); context.dips[1] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[1][0] = Dip::Value( "Off", 0x00 ); context.dips[1][1] = Dip::Value( "On", 0x08 ); context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[2][0] = Dip::Value( "Off", 0x00 ); context.dips[2][1] = Dip::Value( "On", 0x10 ); context.dips[3] = Dip::Value( "Balls", 4, 1 ); context.dips[3][0] = Dip::Value( "2", 0x60 ); context.dips[3][1] = Dip::Value( "3", 0x00 ); context.dips[3][2] = Dip::Value( "4", 0x40 ); context.dips[3][3] = Dip::Value( "5", 0x20 ); context.dips[4] = Dip::Value( "Ball Speed", 2, 0 ); context.dips[4][0] = Dip::Value( "Normal", 0x00 ); context.dips[4][1] = Dip::Value( "Fast", 0x80 ); if (prgCrc == 0xEC461DB9) { context.ppuModel = PPU_RP2C04_0001; context.inputMapper = InputMapper::TYPE_1; } else { context.inputMapper = InputMapper::TYPE_5; } break; case 0xAE8063EF: // Mach Rider - Fighting Course context.SetDips(5); context.dips[0] = Dip::Value( "Coinage", 8, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); context.dips[0][3] = Dip::Value( "1 Coin / 4 Credits", 0x06 ); context.dips[0][4] = Dip::Value( "2 Coins / 1 Credit", 0x01 ); context.dips[0][5] = Dip::Value( "3 Coins / 1 Credit", 0x05 ); context.dips[0][6] = Dip::Value( "4 Coins / 1 Credit", 0x03 ); context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); context.dips[1] = Dip::Value( "Km 1st Race", 2, 0 ); context.dips[1][0] = Dip::Value( "12", 0x00 ); context.dips[1][1] = Dip::Value( "15", 0x10 ); context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[2][0] = Dip::Value( "Off", 0x00 ); context.dips[2][1] = Dip::Value( "On", 0x20 ); context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[3][0] = Dip::Value( "Off", 0x00 ); context.dips[3][1] = Dip::Value( "On", 0x40 ); context.dips[4] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[4][0] = Dip::Value( "Off", 0x00 ); context.dips[4][1] = Dip::Value( "On", 0x80 ); context.ppuModel = PPU_RP2C04_0001; context.inputMapper = InputMapper::TYPE_1; break; case 0x0B65A917: // Mach Rider case 0x8A6A9848: // -||- context.SetDips(5); context.dips[0] = Dip::Value( "Coinage", 8, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); context.dips[0][3] = Dip::Value( "1 Coin / 4 Credits", 0x06 ); context.dips[0][4] = Dip::Value( "2 Coins / 1 Credit", 0x01 ); context.dips[0][5] = Dip::Value( "3 Coins / 1 Credit", 0x05 ); context.dips[0][6] = Dip::Value( "4 Coins / 1 Credit", 0x03 ); context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); context.dips[1] = Dip::Value( "Time", 4, 0 ); context.dips[1][0] = Dip::Value( "280", 0x00 ); context.dips[1][1] = Dip::Value( "250", 0x10 ); context.dips[1][2] = Dip::Value( "220", 0x08 ); context.dips[1][3] = Dip::Value( "200", 0x18 ); context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[2][0] = Dip::Value( "Off", 0x00 ); context.dips[2][1] = Dip::Value( "On", 0x20 ); context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[3][0] = Dip::Value( "Off", 0x00 ); context.dips[3][1] = Dip::Value( "On", 0x40 ); context.dips[4] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[4][0] = Dip::Value( "Off", 0x00 ); context.dips[4][1] = Dip::Value( "On", 0x80 ); context.ppuModel = PPU_RP2C04_0002; context.inputMapper = InputMapper::TYPE_1; break; case 0x46914E3E: // Soccer context.SetDips(3); context.dips[0] = Dip::Value( "Coinage", 8, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); context.dips[0][3] = Dip::Value( "1 Coin / 4 Credits", 0x06 ); context.dips[0][4] = Dip::Value( "2 Coins / 1 Credit", 0x01 ); context.dips[0][5] = Dip::Value( "3 Coins / 1 Credit", 0x05 ); context.dips[0][6] = Dip::Value( "4 Coins / 1 Credit", 0x03 ); context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); context.dips[1] = Dip::Value( "Points Timer", 4, 2 ); context.dips[1][0] = Dip::Value( "600 Pts", 0x00 ); context.dips[1][1] = Dip::Value( "800 Pts", 0x10 ); context.dips[1][2] = Dip::Value( "1000 Pts", 0x08 ); context.dips[1][3] = Dip::Value( "1200 Pts", 0x18 ); context.dips[2] = Dip::Value( "Difficulty", 4, 1 ); context.dips[2][0] = Dip::Value( "Easy", 0x00 ); context.dips[2][1] = Dip::Value( "Normal", 0x40 ); context.dips[2][2] = Dip::Value( "Hard", 0x20 ); context.dips[2][3] = Dip::Value( "Very Hard", 0x60 ); context.ppuModel = PPU_RP2C04_0003; context.inputMapper = InputMapper::TYPE_2; break; case 0x70433F2C: // Battle City context.SetDips(7); context.dips[0] = Dip::Value( "Credits for 2 Players", 2, 1 ); context.dips[0][0] = Dip::Value( "1", 0x00 ); context.dips[0][1] = Dip::Value( "2", 0x01 ); context.dips[1] = Dip::Value( "Lives", 2, 0 ); context.dips[1][0] = Dip::Value( "3", 0x00 ); context.dips[1][1] = Dip::Value( "5", 0x02 ); context.dips[2] = Dip::Value( "Demo Sounds", 2, 1 ); context.dips[2][0] = Dip::Value( "Off", 0x00 ); context.dips[2][1] = Dip::Value( "On", 0x04 ); context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[3][0] = Dip::Value( "Off", 0x00 ); context.dips[3][1] = Dip::Value( "On", 0x08 ); context.dips[4] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[4][0] = Dip::Value( "Off", 0x00 ); context.dips[4][1] = Dip::Value( "On", 0x10 ); context.dips[5] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[5][0] = Dip::Value( "Off", 0x00 ); context.dips[5][1] = Dip::Value( "On", 0x20 ); context.dips[6] = Dip::Value( "PPU", 4, 0 ); context.dips[6][0] = Dip::Value( "RP2C04-0001", 0x00 ); context.dips[6][1] = Dip::Value( "RP2C04-0002", 0x40 ); context.dips[6][2] = Dip::Value( "RP2C04-0003", 0x80 ); context.dips[6][3] = Dip::Value( "RP2C04-0004", 0xC0 ); context.ppuModel = PPU_RP2C04_0001; context.inputMapper = InputMapper::TYPE_2; break; case 0xD99A2087: // Gradius context.SetDips(5); context.dips[0] = Dip::Value( "Coinage", 8, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); context.dips[0][3] = Dip::Value( "2 Coins / 1 Credit", 0x06 ); context.dips[0][4] = Dip::Value( "3 Coins / 1 Credit", 0x01 ); context.dips[0][5] = Dip::Value( "4 Coins / 1 Credit", 0x05 ); context.dips[0][6] = Dip::Value( "5 Coins / 1 Credit", 0x03 ); context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); context.dips[1] = Dip::Value( "Lives", 2, 0 ); context.dips[1][0] = Dip::Value( "3", 0x08 ); context.dips[1][1] = Dip::Value( "4", 0x00 ); context.dips[2] = Dip::Value( "Bonus", 4, 0 ); context.dips[2][0] = Dip::Value( "100k", 0x00 ); context.dips[2][1] = Dip::Value( "200k", 0x20 ); context.dips[2][2] = Dip::Value( "300k", 0x10 ); context.dips[2][3] = Dip::Value( "400k", 0x30 ); context.dips[3] = Dip::Value( "Difficulty", 2, 0 ); context.dips[3][0] = Dip::Value( "Normal", 0x00 ); context.dips[3][1] = Dip::Value( "Hard", 0x40 ); context.dips[4] = Dip::Value( "Demo Sounds", 2, 1 ); context.dips[4][0] = Dip::Value( "Off", 0x00 ); context.dips[4][1] = Dip::Value( "On", 0x80 ); context.ppuModel = PPU_RP2C04_0001; context.inputMapper = InputMapper::TYPE_2; break; case 0x1E438D52: // Goonies context.SetDips(6); context.dips[0] = Dip::Value( "Coinage", 8, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); context.dips[0][3] = Dip::Value( "2 Coins / 1 Credit", 0x06 ); context.dips[0][4] = Dip::Value( "3 Coins / 1 Credit", 0x01 ); context.dips[0][5] = Dip::Value( "4 Coins / 1 Credit", 0x05 ); context.dips[0][6] = Dip::Value( "5 Coins / 1 Credit", 0x03 ); context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); context.dips[1] = Dip::Value( "Lives", 2, 0 ); context.dips[1][0] = Dip::Value( "3", 0x00 ); context.dips[1][1] = Dip::Value( "2", 0x08 ); context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[2][0] = Dip::Value( "Off", 0x00 ); context.dips[2][1] = Dip::Value( "On", 0x10 ); context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[3][0] = Dip::Value( "Off", 0x00 ); context.dips[3][1] = Dip::Value( "On", 0x20 ); context.dips[4] = Dip::Value( "Timer", 2, 0 ); context.dips[4][0] = Dip::Value( "Normal", 0x00 ); context.dips[4][1] = Dip::Value( "Fast", 0x40 ); context.dips[5] = Dip::Value( "Demo Sounds", 2, 1 ); context.dips[5][0] = Dip::Value( "Off", 0x00 ); context.dips[5][1] = Dip::Value( "On", 0x80 ); context.ppuModel = PPU_RP2C04_0003; context.inputMapper = InputMapper::TYPE_1; break; case 0xFF5135A3: // Hogan's Alley context.SetDips(4); context.dips[0] = Dip::Value( "Coinage", 8, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); context.dips[0][3] = Dip::Value( "2 Coins / 1 Credit", 0x06 ); context.dips[0][4] = Dip::Value( "3 Coins / 1 Credit", 0x01 ); context.dips[0][5] = Dip::Value( "4 Coins / 1 Credit", 0x05 ); context.dips[0][6] = Dip::Value( "5 Coins / 1 Credit", 0x03 ); context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); context.dips[1] = Dip::Value( "Difficulty", 4, 1 ); context.dips[1][0] = Dip::Value( "Easy", 0x00 ); context.dips[1][1] = Dip::Value( "Normal", 0x08 ); context.dips[1][2] = Dip::Value( "Hard", 0x10 ); context.dips[1][3] = Dip::Value( "Very Hard", 0x18 ); context.dips[2] = Dip::Value( "Misses per Game", 2, 1 ); context.dips[2][0] = Dip::Value( "3", 0x00 ); context.dips[2][1] = Dip::Value( "5", 0x20 ); context.dips[3] = Dip::Value( "Bonus Life", 4, 0 ); context.dips[3][0] = Dip::Value( "30000", 0x00 ); context.dips[3][1] = Dip::Value( "50000", 0x40 ); context.dips[3][2] = Dip::Value( "80000", 0x80 ); context.dips[3][3] = Dip::Value( "100000", 0xC0 ); context.ppuModel = PPU_RP2C04_0001; break; case 0x17AE56BE: // Freedom Force context.SetDips(6); context.dips[0] = Dip::Value( "Coinage", 8, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); context.dips[0][3] = Dip::Value( "2 Coins / 1 Credit", 0x06 ); context.dips[0][4] = Dip::Value( "3 Coins / 1 Credit", 0x01 ); context.dips[0][5] = Dip::Value( "4 Coins / 1 Credit", 0x05 ); context.dips[0][6] = Dip::Value( "5 Coins / 1 Credit", 0x03 ); context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); context.dips[1] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[1][0] = Dip::Value( "Off", 0x00 ); context.dips[1][1] = Dip::Value( "On", 0x08 ); context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[2][0] = Dip::Value( "Off", 0x00 ); context.dips[2][1] = Dip::Value( "On", 0x10 ); context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[3][0] = Dip::Value( "Off", 0x00 ); context.dips[3][1] = Dip::Value( "On", 0x20 ); context.dips[4] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[4][0] = Dip::Value( "Off", 0x00 ); context.dips[4][1] = Dip::Value( "On", 0x40 ); context.dips[5] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[5][0] = Dip::Value( "Off", 0x00 ); context.dips[5][1] = Dip::Value( "On", 0x80 ); context.ppuModel = PPU_RP2C04_0001; break; case 0xC99EC059: // Raid on Bungeling Bay context.SetDips(6); context.dips[0] = Dip::Value( "Coinage", 8, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); context.dips[0][3] = Dip::Value( "1 Coin / 4 Credits", 0x06 ); context.dips[0][4] = Dip::Value( "2 Coins / 1 Credit", 0x01 ); context.dips[0][5] = Dip::Value( "3 Coins / 1 Credit", 0x05 ); context.dips[0][6] = Dip::Value( "4 Coins / 1 Credit", 0x03 ); context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); context.dips[1] = Dip::Value( "Lives", 2, 0 ); context.dips[1][0] = Dip::Value( "2", 0x00 ); context.dips[1][1] = Dip::Value( "3", 0x08 ); context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[2][0] = Dip::Value( "Off", 0x00 ); context.dips[2][1] = Dip::Value( "On", 0x10 ); context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[3][0] = Dip::Value( "Off", 0x00 ); context.dips[3][1] = Dip::Value( "On", 0x20 ); context.dips[4] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[4][0] = Dip::Value( "Off", 0x00 ); context.dips[4][1] = Dip::Value( "On", 0x40 ); context.dips[5] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[5][0] = Dip::Value( "Off", 0x00 ); context.dips[5][1] = Dip::Value( "On", 0x80 ); context.ppuModel = PPU_RP2C04_0002; context.inputMapper = InputMapper::TYPE_4; break; case 0xF9D3B0A3: // Super Xevious case 0x66BB838F: // -||- case 0x9924980A: // -||- context.SetDips(6); context.dips[0] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[0][0] = Dip::Value( "Off", 0x00 ); context.dips[0][1] = Dip::Value( "On", 0x01 ); context.dips[1] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[1][0] = Dip::Value( "Off", 0x00 ); context.dips[1][1] = Dip::Value( "On", 0x02 ); context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[2][0] = Dip::Value( "Off", 0x00 ); context.dips[2][1] = Dip::Value( "On", 0x04 ); context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[3][0] = Dip::Value( "Off", 0x00 ); context.dips[3][1] = Dip::Value( "On", 0x08 ); context.dips[4] = Dip::Value( "Coinage", 4, 0 ); context.dips[4][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[4][1] = Dip::Value( "1 Coin / 2 Credits", 0x10 ); context.dips[4][2] = Dip::Value( "2 Coins / 1 Credit", 0x20 ); context.dips[4][3] = Dip::Value( "3 Coins / 1 Credit", 0x30 ); context.dips[5] = Dip::Value( "PPU", 4, 0 ); context.dips[5][0] = Dip::Value( "RP2C04-0001", 0x00 ); context.dips[5][1] = Dip::Value( "RP2C04-0002", 0x40 ); context.dips[5][2] = Dip::Value( "RP2C04-0003", 0x80 ); context.dips[5][3] = Dip::Value( "RP2C04-0004", 0xC0 ); context.inputMapper = InputMapper::TYPE_1; context.ppuModel = PPU_RP2C04_0001; context.mode = MODE_XEV; break; case 0xCC2C4B5D: // Golf (J) case 0x86167220: // Lady Golf context.ppuModel = PPU_RP2C04_0002; case 0xA93A5AEE: // Golf context.SetDips(5); context.dips[0] = Dip::Value( "Coinage", 8, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x01 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x06 ); context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); context.dips[0][3] = Dip::Value( "1 Coin / 4 Credits", 0x04 ); context.dips[0][4] = Dip::Value( "2 Coins / 1 Credit", 0x05 ); context.dips[0][5] = Dip::Value( "3 Coins / 1 Credit", 0x03 ); context.dips[0][6] = Dip::Value( "4 Coins / 1 Credit", 0x07 ); context.dips[0][7] = Dip::Value( "Free Play", 0x00 ); context.dips[1] = Dip::Value( "Hole Size", 2, 0 ); context.dips[1][0] = Dip::Value( "Large", 0x00 ); context.dips[1][1] = Dip::Value( "Small", 0x08 ); context.dips[2] = Dip::Value( "Points per Stroke", 2, 0 ); context.dips[2][0] = Dip::Value( "Easier", 0x00 ); context.dips[2][1] = Dip::Value( "Harder", 0x10 ); context.dips[3] = Dip::Value( "Starting Points", 4, 0 ); context.dips[3][0] = Dip::Value( "10", 0x00 ); context.dips[3][1] = Dip::Value( "13", 0x40 ); context.dips[3][2] = Dip::Value( "16", 0x20 ); context.dips[3][3] = Dip::Value( "20", 0x60 ); context.dips[4] = Dip::Value( "Difficulty Vs. Computer", 2, 0 ); context.dips[4][0] = Dip::Value( "Easy", 0x00 ); context.dips[4][1] = Dip::Value( "Hard", 0x80 ); context.inputMapper = InputMapper::TYPE_2; break; case 0xCA85E56D: // Mighty Bomb Jack context.SetDips(5); context.dips[0] = Dip::Value( "Coinage", 8, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); context.dips[0][3] = Dip::Value( "1 Coin / 4 Credits", 0x06 ); context.dips[0][4] = Dip::Value( "2 Coins / 1 Credit", 0x01 ); context.dips[0][5] = Dip::Value( "3 Coins / 1 Credit", 0x05 ); context.dips[0][6] = Dip::Value( "4 Coins / 1 Credit", 0x03 ); context.dips[0][7] = Dip::Value( "5 Coins / 1 Credit", 0x07 ); context.dips[1] = Dip::Value( "Lives", 4, 0 ); context.dips[1][0] = Dip::Value( "2", 0x10 ); context.dips[1][1] = Dip::Value( "3", 0x00 ); context.dips[1][2] = Dip::Value( "4", 0x08 ); context.dips[1][3] = Dip::Value( "5", 0x18 ); context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[2][0] = Dip::Value( "Off", 0x00 ); context.dips[2][1] = Dip::Value( "On", 0x20 ); context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[3][0] = Dip::Value( "Off", 0x00 ); context.dips[3][1] = Dip::Value( "On", 0x40 ); context.dips[4] = Dip::Value( "Unknown/Unused", 2, 0 ); context.dips[4][0] = Dip::Value( "Off", 0x00 ); context.dips[4][1] = Dip::Value( "On", 0x80 ); context.ppuModel = PPU_RC2C05_02; context.inputMapper = InputMapper::TYPE_1; break; case 0xFE446787: // Gumshoe context.SetDips(5); context.dips[0] = Dip::Value( "Coinage", 8, 0 ); context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); context.dips[0][3] = Dip::Value( "2 Coins / 1 Credit", 0x06 ); context.dips[0][4] = Dip::Value( "3 Coins / 1 Credit", 0x01 ); context.dips[0][5] = Dip::Value( "4 Coins / 1 Credit", 0x05 ); context.dips[0][6] = Dip::Value( "5 Coins / 1 Credit", 0x03 ); context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); context.dips[1] = Dip::Value( "Difficulty", 4, 1 ); context.dips[1][0] = Dip::Value( "Easy", 0x00 ); context.dips[1][1] = Dip::Value( "Normal", 0x08 ); context.dips[1][2] = Dip::Value( "Hard", 0x10 ); context.dips[1][3] = Dip::Value( "Very Hard", 0x18 ); context.dips[2] = Dip::Value( "Lives", 2, 1 ); context.dips[2][0] = Dip::Value( "3", 0x10 ); context.dips[2][1] = Dip::Value( "5", 0x00 ); context.dips[3] = Dip::Value( "Bullets per Balloon", 2, 1 ); context.dips[3][0] = Dip::Value( "2", 0x40 ); context.dips[3][1] = Dip::Value( "3", 0x00 ); context.dips[4] = Dip::Value( "Bonus Life", 2, 0 ); context.dips[4][0] = Dip::Value( "80000", 0x00 ); context.dips[4][1] = Dip::Value( "100000", 0x80 ); context.ppuModel = PPU_RC2C05_03; break; default: context.SetDips(8); for (uint i=0; i < 8; ++i) { context.dips[i] = Dip::Value( "Unknown", 2, 0 ); context.dips[i][0] = Dip::Value( "Off", 0x00 ); context.dips[i][1] = Dip::Value( "On", 1U << i ); } if (ppuModel != PPU_RP2C02) context.ppuModel = ppuModel; break; } switch (context.mode) { case MODE_RBI: return new RbiBaseball ( context ); case MODE_TKO: return new TkoBoxing ( context ); case MODE_XEV: return new SuperXevious ( context ); default: return new VsSystem ( context ); } } catch (...) { delete [] context.dips; throw; } } void Cartridge::VsSystem::Destroy(Cartridge::VsSystem* vsSystem) { delete vsSystem; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif struct Cartridge::VsSystem::InputMapper::Type1 : InputMapper { void Fix(Pad (&pads)[4],const uint (&ports)[2]) const { const uint p[2] = { ports[0] < 4 ? pads[ports[0]].buttons : 0, ports[1] < 4 ? pads[ports[1]].buttons : 0 }; for (uint i=2; i--; ) { if (ports[i] < 4) pads[ports[i]].buttons = (p[i] & ~uint(Pad::SELECT|Pad::START)) | ((p[i] & Pad::SELECT) << 1) | ((p[i] & Pad::START) >> 1); } } }; struct Cartridge::VsSystem::InputMapper::Type2 : InputMapper { void Fix(Pad (&pads)[4],const uint (&ports)[2]) const { const uint p[2] = { ports[0] < 4 ? pads[ports[0]].buttons : 0, ports[1] < 4 ? pads[ports[1]].buttons : 0 }; for (uint i=2; i--; ) { if (ports[i] < 4) pads[ports[i]].buttons = (p[i^1] & ~uint(Pad::SELECT|Pad::START)) | ((p[i^0] & Pad::SELECT) << 1) | ((p[i^0] & Pad::START) >> 1); } } }; struct Cartridge::VsSystem::InputMapper::Type3 : InputMapper { void Fix(Pad (&pads)[4],const uint (&ports)[2]) const { const uint p[2] = { ports[0] < 4 ? pads[ports[0]].buttons : 0, ports[1] < 4 ? pads[ports[1]].buttons : 0 }; if (ports[1] < 4) pads[ports[1]].buttons = p[0] & ~uint(Pad::SELECT|Pad::START); if (ports[0] < 4) pads[ports[0]].buttons = (p[1] & ~uint(Pad::SELECT|Pad::START)) | ((p[0] & Pad::START) >> 1) | (p[1] & Pad::START); } }; struct Cartridge::VsSystem::InputMapper::Type4 : InputMapper { void Fix(Pad (&pads)[4],const uint (&ports)[2]) const { const uint p[2] = { ports[0] < 4 ? pads[ports[0]].buttons : 0, ports[1] < 4 ? pads[ports[1]].buttons : 0 }; for (uint i=2; i--; ) { if (ports[i] < 4) pads[ports[i]].buttons = (p[i^1] & ~uint(Pad::SELECT|Pad::START)) | (((p[i^0] & Pad::SELECT) ^ Pad::SELECT) << 1) | ((p[i^0] & Pad::START) >> 1); } } }; struct Cartridge::VsSystem::InputMapper::Type5 : InputMapper { void Fix(Pad (&pads)[4],const uint (&ports)[2]) const { const uint p[2] = { ports[0] < 4 ? pads[ports[0]].buttons : 0, ports[1] < 4 ? pads[ports[1]].buttons : 0 }; if (ports[1] < 4) pads[ports[1]].buttons = (p[1] & ~uint(Pad::A|Pad::SELECT|Pad::START)) | ((p[0] & Pad::B) >> 1) | ((p[1] & Pad::SELECT) << 1) | ((p[1] & Pad::START) >> 1); if (ports[0] < 4) pads[ports[0]].buttons = (p[0] & ~uint(Pad::B|Pad::SELECT|Pad::START)) | ((p[1] & Pad::A) << 1) | ((p[0] & Pad::SELECT) << 1) | ((p[0] & Pad::START) >> 1); } }; void Cartridge::VsSystem::InputMapper::Begin(const Api::Input input,Input::Controllers* const controllers) { Input::Controllers::Pad::callback.Get( userCallback, userData ); if (controllers) { uint ports[2]; for (uint i=0; i < 2; ++i) { ports[i] = input.GetConnectedController(i) - Api::Input::PAD1; if (ports[i] < 4) Input::Controllers::Pad::callback( controllers->pad[ports[i]], ports[i] ); } Input::Controllers::Pad::callback.Set( NULL, NULL ); Fix( controllers->pad, ports ); } } void Cartridge::VsSystem::InputMapper::End() const { Input::Controllers::Pad::callback.Set( userCallback, userData ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Cartridge::VsSystem::InputMapper* Cartridge::VsSystem::InputMapper::Create(Type type) { switch (type) { case TYPE_1: return new Type1; case TYPE_2: return new Type2; case TYPE_3: return new Type3; case TYPE_4: return new Type4; case TYPE_5: return new Type5; case TYPE_NONE: default: break; } return NULL; } Cartridge::VsSystem::VsSystem(Context& context) : cpu (context.cpu), ppu (context.ppu), inputMapper (InputMapper::Create( context.inputMapper )), dips (context.dips,context.numDips), ppuModel (context.ppuModel) { } Cartridge::VsSystem::~VsSystem() { delete inputMapper; } void Cartridge::VsSystem::Reset(bool) { dips.Reset(); coin = 0; p4016 = cpu.Map( 0x4016 ); p4017 = cpu.Map( 0x4017 ); cpu.Map( 0x4016 ).Set( this, &VsSystem::Peek_4016, &VsSystem::Poke_4016 ); cpu.Map( 0x4017 ).Set( this, &VsSystem::Peek_4017, &VsSystem::Poke_4017 ); cpu.Map( 0x4020 ).Set( this, &VsSystem::Peek_4020, &VsSystem::Poke_4020 ); cpu.Map( 0x5000, 0x5FFF ).Set( this, &VsSystem::Peek_Nop, &VsSystem::Poke_Nop ); Reset(); } void Cartridge::VsSystem::SaveState(State::Saver& state,const dword baseChunk) const { state.Begin( baseChunk ); state.Write8( coin ); SubSave( state ); state.End(); } void Cartridge::VsSystem::LoadState(State::Loader& state) { coin = state.Read8(); while (const dword chunk = state.Begin()) { SubLoad( state, chunk ); state.End(); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(Cartridge::VsSystem,Nop) { return address >> 8; } NES_POKE(Cartridge::VsSystem,Nop) { } NES_PEEK_A(Cartridge::VsSystem,4016) { return dips.Reg(0) | (p4016.Peek( address ) & (STATUS_4016_MASK^0xFFU)); } NES_POKE_AD(Cartridge::VsSystem,4016) { p4016.Poke( address, data ); } NES_PEEK_A(Cartridge::VsSystem,4017) { return dips.Reg(1) | (p4017.Peek( address ) & (STATUS_4017_MASK^0xFFU)); } NES_POKE_AD(Cartridge::VsSystem,4017) { p4017.Poke( address, data ); } NES_PEEK(Cartridge::VsSystem,4020) { return coin; } NES_POKE_D(Cartridge::VsSystem,4020) { coin = data; } } } nestopia-1.51.1/source/core/vssystem/NstVsSystem.hpp000066400000000000000000000105351411157722000225450ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_VSSYSTEM_H #define NST_VSSYSTEM_H #include "../api/NstApiInput.hpp" #include "../NstDipSwitches.hpp" #include "../NstCartridge.hpp" #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class Cartridge::VsSystem { public: enum Mode { MODE_STD, MODE_RBI, MODE_TKO, MODE_XEV }; static VsSystem* Create(Cpu&,Ppu&,PpuModel,dword); static void Destroy(VsSystem*); void Reset(bool); void SaveState(State::Saver&,dword) const; void LoadState(State::Loader&); protected: struct Context; explicit VsSystem(Context&); virtual ~VsSystem(); private: class RbiBaseball; class SuperXevious; class TkoBoxing; virtual void Reset() {} virtual void SubSave(State::Saver&) const {} virtual void SubLoad(State::Loader&,dword) {} class Dip; class VsDipSwitches : public DipSwitches { public: VsDipSwitches(Dip*&,uint); ~VsDipSwitches(); inline uint Reg(uint) const; inline void Reset(); void BeginFrame(Input::Controllers*); private: uint NumDips() const; uint NumValues(uint) const; cstring GetDipName(uint) const; cstring GetValueName(uint,uint) const; uint GetValue(uint) const; void SetValue(uint,uint); uint coinTimer; Dip* const table; const uint size; uint regs[2]; }; enum { DIPSWITCH_4016_MASK = 0x03, DIPSWITCH_4016_SHIFT = 3, DIPSWITCH_4017_MASK = 0xFC, DIPSWITCH_4017_SHIFT = 0, COIN_1 = Input::Controllers::VsSystem::COIN_1, COIN_2 = Input::Controllers::VsSystem::COIN_2, COIN = COIN_1|COIN_2, STATUS_4016_MASK = uint(DIPSWITCH_4016_MASK) << DIPSWITCH_4016_SHIFT | COIN, STATUS_4017_MASK = uint(DIPSWITCH_4017_MASK) << DIPSWITCH_4017_SHIFT }; NES_DECL_PEEK( Nop ); NES_DECL_POKE( Nop ); NES_DECL_PEEK( 4016 ); NES_DECL_POKE( 4016 ); NES_DECL_PEEK( 4017 ); NES_DECL_POKE( 4017 ); NES_DECL_PEEK( 4020 ); NES_DECL_POKE( 4020 ); protected: Cpu& cpu; Ppu& ppu; private: class InputMapper { typedef Input::Controllers::Pad Pad; virtual void Fix(Pad (&)[4],const uint (&)[2]) const = 0; void* userData; Pad::PollCallback userCallback; struct Type1; struct Type2; struct Type3; struct Type4; struct Type5; public: enum Type { TYPE_NONE, TYPE_1, TYPE_2, TYPE_3, TYPE_4, TYPE_5 }; static InputMapper* Create(Type); virtual ~InputMapper() {} void Begin(const Api::Input,Input::Controllers*); void End() const; }; InputMapper* const inputMapper; Io::Port p4016; Io::Port p4017; VsDipSwitches dips; uint coin; const PpuModel ppuModel; public: void BeginFrame(const Api::Input& input,Input::Controllers* controllers) { dips.BeginFrame( controllers ); if (inputMapper) inputMapper->Begin( input, controllers ); } void VSync() const { if (inputMapper) inputMapper->End(); } PpuModel GetPpuModel() const { return ppuModel; } DipSwitches& GetDipSwiches() { return dips; } }; } } #endif nestopia-1.51.1/source/core/vssystem/NstVsTkoBoxing.cpp000066400000000000000000000044561411157722000231650ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "../NstCpu.hpp" #include "../NstState.hpp" #include "../vssystem/NstVsSystem.hpp" #include "../vssystem/NstVsTkoBoxing.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif void Cartridge::VsSystem::TkoBoxing::Reset() { cpu.Map( 0x5E00 ).Set( &TkoBoxing::Peek_5E00 ); cpu.Map( 0x5E01 ).Set( &TkoBoxing::Peek_5E01 ); counter = 0; } void Cartridge::VsSystem::TkoBoxing::SubSave(State::Saver& state) const { state.Begin( AsciiId<'T','K','O'>::V ).Write8( counter & 0x1F ).End(); } void Cartridge::VsSystem::TkoBoxing::SubLoad(State::Loader& state,const dword chunk) { if (chunk == AsciiId<'T','K','O'>::V) counter = state.Read8() & 0x1F; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK(Cartridge::VsSystem::TkoBoxing,5E00) { counter = 0; return 0; } NES_PEEK(Cartridge::VsSystem::TkoBoxing,5E01) { static const byte securityData[32] = { 0xFF, 0xBF, 0xB7, 0x97, 0x97, 0x17, 0x57, 0x4F, 0x6F, 0x6B, 0xEB, 0xA9, 0xB1, 0x90, 0x94, 0x14, 0x56, 0x4E, 0x6F, 0x6B, 0xEB, 0xA9, 0xB1, 0x90, 0xD4, 0x5C, 0x3E, 0x26, 0x87, 0x83, 0x13, 0x00 }; return securityData[counter++ & 0x1F]; } } } nestopia-1.51.1/source/core/vssystem/NstVsTkoBoxing.hpp000066400000000000000000000030351411157722000231620ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_VS_TKOBOXING_H #define NST_VS_TKOBOXING_H #ifdef NST_PRAGMA_ONCE #pragma once #endif namespace Nes { namespace Core { class Cartridge::VsSystem::TkoBoxing : public Cartridge::VsSystem { public: explicit TkoBoxing(Context& c) : VsSystem(c) {} private: ~TkoBoxing() {} void Reset(); void SubSave(State::Saver&) const; void SubLoad(State::Loader&,dword); NES_DECL_PEEK( 5E00 ); NES_DECL_PEEK( 5E01 ); uint counter; }; } } #endif nestopia-1.51.1/source/fltkui/000077500000000000000000000000001411157722000162175ustar00rootroot00000000000000nestopia-1.51.1/source/fltkui/audio.cpp000066400000000000000000000117761411157722000200400ustar00rootroot00000000000000/* * Nestopia UE * * Copyright (C) 2012-2021 R. Danbrook * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include #include #include "nstcommon.h" #include "config.h" #include "audio.h" #define BUFSIZE 16000 extern Emulator emulator; static SDL_AudioSpec spec, obtained; static SDL_AudioDeviceID dev; static SDL_AudioCVT cvt; static int16_t intbuf[BUFSIZE]; static int16_t extbuf[BUFSIZE]; static uint16_t bufstart = 0; static uint16_t bufend = 0; static uint16_t bufsamples = 0; static uint16_t framerate, channels, bufsize; static bool paused = false; void audio_set_speed(int speed) { bufsize = (channels * (conf.audio_sample_rate / framerate)) / speed; } void audio_queue() { while ((bufsamples + bufsize) >= BUFSIZE) { SDL_Delay(1); } SDL_LockAudioDevice(dev); int numsamples = bufsize; if (bufsamples < bufsize * 3) { SDL_ConvertAudio(&cvt); numsamples += channels * 2; } for (int i = 0; i < numsamples; i++) { extbuf[bufend] = intbuf[i]; bufend = (bufend + 1) % BUFSIZE; bufsamples++; if (bufsamples >= BUFSIZE - 1) { break; } } SDL_UnlockAudioDevice(dev); } static inline float audio_dequeue() { if (bufsamples == 0) { return 0; } int16_t sample = extbuf[bufstart]; bufstart = (bufstart + 1) % BUFSIZE; bufsamples--; return sample; } void audio_cb(void *data, uint8_t *stream, int len) { int16_t *out = (int16_t*)stream; for (int i = 0; i < len / sizeof(int16_t); i++) { out[i] = audio_dequeue(); } } void audio_deinit() { if (dev) { SDL_CloseAudioDevice(dev); } } void audio_init_sdl() { int e = 1; // Check Endianness SDL_AudioFormat fmt = ((int)*((unsigned char *)&e) == 1) ? AUDIO_S16LSB : AUDIO_S16MSB; spec.freq = conf.audio_sample_rate; spec.format = fmt; spec.channels = channels; spec.silence = 0; spec.samples = 512; spec.userdata = 0; spec.callback = audio_cb; bufsize = channels * (conf.audio_sample_rate / framerate); bufend = bufstart = bufsamples = 0; dev = SDL_OpenAudioDevice(NULL, 0, &spec, &obtained, SDL_AUDIO_ALLOW_ANY_CHANGE); if (!dev) { fprintf(stderr, "Error opening audio device.\n"); } else { fprintf(stderr, "Audio: SDL - %dHz, %d channel(s)\n", spec.freq, spec.channels); } SDL_BuildAudioCVT(&cvt, fmt, channels, conf.audio_sample_rate, fmt, channels, conf.audio_sample_rate + ((nst_pal() ? 50 : 60) * channels * 2)); SDL_assert(cvt.needed); cvt.len = (bufsize + channels * 2) * sizeof(int16_t); cvt.buf = (Uint8*)intbuf; SDL_PauseAudioDevice(dev, 1); // Setting to 0 unpauses } void audio_init() { // Initialize audio device // Set the framerate based on the region. For PAL: (60 / 6) * 5 = 50 framerate = nst_pal() ? (conf.timing_speed / 6) * 5 : conf.timing_speed; channels = conf.audio_stereo ? 2 : 1; memset(intbuf, 0, sizeof(int16_t) * BUFSIZE); audio_init_sdl(); paused = false; } void audio_pause() { // Pause the SDL audio device SDL_PauseAudioDevice(dev, 1); paused = true; } void audio_unpause() { // Unpause the SDL audio device SDL_PauseAudioDevice(dev, 0); paused = false; } void audio_set_params(Sound::Output *soundoutput) { // Set audio parameters Sound sound(emulator); sound.SetSampleBits(16); sound.SetSampleRate(conf.audio_sample_rate); sound.SetSpeaker(conf.audio_stereo ? Sound::SPEAKER_STEREO : Sound::SPEAKER_MONO); sound.SetSpeed(Sound::DEFAULT_SPEED); audio_adj_volume(); soundoutput->samples[0] = intbuf; soundoutput->length[0] = conf.audio_sample_rate / framerate; soundoutput->samples[1] = NULL; soundoutput->length[1] = 0; } void audio_adj_volume() { // Adjust the audio volume to the current settings Sound sound(emulator); sound.SetVolume(Sound::ALL_CHANNELS, conf.audio_volume); sound.SetVolume(Sound::CHANNEL_SQUARE1, conf.audio_vol_sq1); sound.SetVolume(Sound::CHANNEL_SQUARE2, conf.audio_vol_sq2); sound.SetVolume(Sound::CHANNEL_TRIANGLE, conf.audio_vol_tri); sound.SetVolume(Sound::CHANNEL_NOISE, conf.audio_vol_noise); sound.SetVolume(Sound::CHANNEL_DPCM, conf.audio_vol_dpcm); sound.SetVolume(Sound::CHANNEL_FDS, conf.audio_vol_fds); sound.SetVolume(Sound::CHANNEL_MMC5, conf.audio_vol_mmc5); sound.SetVolume(Sound::CHANNEL_VRC6, conf.audio_vol_vrc6); sound.SetVolume(Sound::CHANNEL_VRC7, conf.audio_vol_vrc7); sound.SetVolume(Sound::CHANNEL_N163, conf.audio_vol_n163); sound.SetVolume(Sound::CHANNEL_S5B, conf.audio_vol_s5b); if (conf.audio_volume == 0) { memset(intbuf, 0, sizeof(int16_t) * BUFSIZE); } } nestopia-1.51.1/source/fltkui/audio.h000066400000000000000000000006201411157722000174670ustar00rootroot00000000000000#ifndef _AUDIO_H_ #define _AUDIO_H_ #include #include "core/api/NstApiEmulator.hpp" #include "core/api/NstApiSound.hpp" using namespace Nes::Api; void audio_set_funcs(); void audio_init(); void audio_deinit(); void audio_queue(); void audio_pause(); void audio_unpause(); void audio_set_params(Sound::Output *soundoutput); void audio_set_speed(int speed); void audio_adj_volume(); #endif nestopia-1.51.1/source/fltkui/cheats.cpp000066400000000000000000000146051411157722000202000ustar00rootroot00000000000000/* * Nestopia UE * * Copyright (C) 2012-2018 R. Danbrook * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include #include #include #include "cheats.h" static Xml savexml; static Xml::Node saveroot; std::vector chtlist; extern Emulator emulator; void nst_cheats_init(const char *cheatpath) { // Initialize cheat engine Cheats cheats(emulator); Xml xml; cheats.ClearCodes(); std::ifstream cheatfile(cheatpath, std::ifstream::in|std::ifstream::binary); if (cheatfile.is_open()) { xml.Read(cheatfile); if (xml.GetRoot().IsType(L"cheats")) { Xml::Node root(xml.GetRoot()); Xml::Node node(root.GetFirstChild()); for (int i = 0; i < root.NumChildren(L"cheat"); i++) { if (node.GetAttribute(L"enabled").IsValue(L"1")) { if (node.GetChild(L"genie")) { // Game Genie nst_cheats_code_gg_add(node.GetChild(L"genie").GetValue()); } else if (node.GetChild(L"rocky")) { // Pro Action Rocky nst_cheats_code_par_add(node.GetChild(L"rocky").GetValue()); } else if (node.GetChild(L"address")) { // Raw Cheats::Code code; code.useCompare = false; code.address = node.GetChild(L"address").GetUnsignedValue(); if (node.GetChild(L"value")) { code.value = node.GetChild(L"value").GetUnsignedValue(); } if (node.GetChild(L"compare")) { code.compare = node.GetChild(L"compare").GetUnsignedValue(); code.useCompare = true; } cheats.SetCode(code); } //fprintf(stderr, "Cheat: %ls\n", node.GetChild(L"description").GetValue()); } NstCheat cht = { node.GetAttribute(L"enabled").IsValue(L"1"), node.GetChild(L"genie").GetValue(), node.GetChild(L"rocky").GetValue(), node.GetChild(L"address").GetUnsignedValue(), node.GetChild(L"value").GetUnsignedValue(), node.GetChild(L"compare").GetUnsignedValue(), node.GetChild(L"description").GetValue() }; chtlist.push_back(cht); node = node.GetNextSibling(); } } cheatfile.close(); } } void nst_cheats_save(const char *cheatpath) { // Save the cheat list std::ofstream cheatfile(cheatpath, std::ifstream::out|std::ifstream::binary); if (cheatfile.is_open()) { saveroot = (savexml.GetRoot()); saveroot = savexml.Create( L"cheats" ); saveroot.AddAttribute( L"version", L"1.0" ); char buf[9]; wchar_t wbuf[9]; for (int i = 0; i < chtlist.size(); i++) { Xml::Node node(saveroot.AddChild(L"cheat")); node.AddAttribute(L"enabled", chtlist[i].enabled ? L"1" : L"0"); if (chtlist[i].gg.size() > 0) { node.AddChild(L"genie", chtlist[i].gg.c_str()); } if (chtlist[i].par.size() > 0) { node.AddChild(L"rocky", chtlist[i].par.c_str()); } if (chtlist[i].address != 0) { snprintf(buf, sizeof(buf), "0x%04X", chtlist[i].address); mbstowcs(wbuf, buf, 9); node.AddChild(L"address", wbuf); snprintf(buf, sizeof(buf), "0x%02x", chtlist[i].value); mbstowcs(wbuf, buf, 9); node.AddChild(L"value", wbuf); snprintf(buf, sizeof(buf), "0x%02x", chtlist[i].compare); mbstowcs(wbuf, buf, 9); node.AddChild(L"compare", wbuf); } if (chtlist[i].description.size() > 0) { node.AddChild(L"description", chtlist[i].description.c_str()); } } savexml.Write(saveroot, cheatfile); cheatfile.close(); } } void nst_cheats_code_gg_add(const std::wstring data) { // Add a Game Genie code Cheats cheats(emulator); Cheats::Code code; char gg[9]; snprintf(gg, sizeof(gg), "%ls", data.c_str()); cheats.GameGenieDecode(gg, code); cheats.SetCode(code); } void nst_cheats_code_par_add(const std::wstring data) { // Add a Pro Action Rocky code Cheats cheats(emulator); Cheats::Code code; char par[9]; snprintf(par, sizeof(par), "%ls", data.c_str()); cheats.ProActionRockyDecode(par, code); cheats.SetCode(code); } void nst_cheats_refresh() { Cheats cheats(emulator); cheats.ClearCodes(); for (int i = 0; i < chtlist.size(); i++) { if (chtlist[i].enabled) { if (chtlist[i].gg.size()) { nst_cheats_code_gg_add(chtlist[i].gg); } else if (chtlist[i].par.size()) { nst_cheats_code_par_add(chtlist[i].par); } else if (chtlist[i].address) { Cheats::Code code; code.useCompare = false; code.address = chtlist[i].address; code.value = chtlist[i].value; code.compare = chtlist[i].compare; code.useCompare = code.compare != 0; cheats.SetCode(code); } } } } // DIP Switches void nst_dip_handle(const char *dippath) { // Handle the DIP switch file DipSwitches dipswitches(emulator); Xml xml; std::ifstream dipfile(dippath, std::ifstream::in|std::ifstream::binary); if (dipfile.is_open()) { xml.Read(dipfile); if (xml.GetRoot().IsType(L"dipswitches")) { Xml::Node root(xml.GetRoot()); Xml::Node node(root.GetFirstChild()); for (int i = 0; i < root.NumChildren(L"dip"); i++) { if (node.GetChild(L"value")) { dipswitches.SetValue(i, node.GetChild(L"value").GetUnsignedValue()); } node = node.GetNextSibling(); } } dipfile.close(); } else { Xml::Node root(xml.GetRoot()); root = xml.Create(L"dipswitches"); root.AddAttribute(L"version", L"1.0"); wchar_t wbuf[32]; char buf[32]; int numdips = dipswitches.NumDips(); if (numdips > 0) { for (int i = 0; i < numdips; i++) { Xml::Node node(root.AddChild(L"dip")); snprintf(buf, sizeof(buf), "%s", dipswitches.GetDipName(i)); mbstowcs(wbuf, buf, sizeof(buf)); node.AddChild(L"description", wbuf); snprintf(buf, sizeof(buf), "%d", dipswitches.GetValue(i)); mbstowcs(wbuf, buf, sizeof(buf)); node.AddChild(L"value", wbuf); } } std::ofstream dipout(dippath, std::ifstream::out|std::ifstream::binary); if (dipout.is_open()) { xml.Write(root, dipout); } dipout.close(); } } nestopia-1.51.1/source/fltkui/cheats.h000066400000000000000000000014531411157722000176420ustar00rootroot00000000000000#ifndef _CHEATS_H_ #define _CHEATS_H_ #include #include #include "core/api/NstApiEmulator.hpp" #include "core/api/NstApiCheats.hpp" #include "core/api/NstApiDipSwitches.hpp" #include "core/NstStream.hpp" #include "core/NstXml.hpp" using namespace Nes::Api; typedef Nes::Core::Xml Xml; typedef struct NstCheat { bool enabled; std::wstring gg; std::wstring par; unsigned short address; unsigned char value; unsigned char compare; std::wstring description; } NstCheat; void nst_cheats_init(const char *cheatpath); void nst_cheats_save(const char *cheatpath); void nst_cheats_refresh(); void nst_cheats_code_gg_add(const std::wstring data); void nst_cheats_code_par_add(const std::wstring data); // DIP Switches void nst_dip_handle(const char *dippath); #endif nestopia-1.51.1/source/fltkui/cli.cpp000066400000000000000000000104251411157722000174740ustar00rootroot00000000000000/* * Nestopia UE * * Copyright (C) 2012-2016 R. Danbrook * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include #include #include #include "cli.h" #include "config.h" void cli_error(const char *message) { cli_show_usage(); fprintf(stderr, "%s\n", message); exit(1); } void cli_show_usage() { printf("Usage: nestopia [options] [FILE]\n"); printf("\nOptions:\n"); printf(" -f, --fullscreen Fullscreen mode\n"); printf(" -w, --window Window mode\n\n"); printf(" -l, --filter Video Filter\n"); printf(" (0=None, 1=NTSC, 2=xBR, 3=HqX, 4=2xSaI, 5=ScaleX)\n\n"); printf(" -m, --maskoverscan Mask overscan areas\n"); printf(" -n, --no-maskoverscan Disable overscan masking\n\n"); printf(" -o, --stretchfs Stretch to native resolution in fullscreen mode\n"); printf(" -p, --preserveaspect Preserve aspect ratio in fullscreen mode\n\n"); printf(" -s, --scalefactor Video scale factor (1-4)\n\n"); printf(" -t, --tvaspect TV aspect ratio\n"); printf(" -r, --no-tvaspect Regular aspect ratio\n\n"); printf(" -u, --unlimitedsprites Remove sprite limit\n"); printf(" -q, --spritelimit Enable sprite limit\n\n"); printf(" -v, --version Show version information\n\n"); printf("More options can be set in the configuration file.\n"); printf("Options are saved, and do not need to be set on future invocations.\n\n"); } void cli_show_version() { printf("Nestopia UE 1.51.1\n"); } void cli_handle_command(int argc, char *argv[]) { int c; int optint; while (1) { static struct option long_options[] = { {"disablegui", no_argument, 0, 'd'}, {"enablegui", no_argument, 0, 'e'}, {"fullscreen", no_argument, 0, 'f'}, {"window", no_argument, 0, 'w'}, {"help", no_argument, 0, 'h'}, {"filter", required_argument, 0, 'l'}, {"maskoverscan", no_argument, 0, 'm'}, {"no-maskoverscan", no_argument, 0, 'n'}, {"stretchfs", no_argument, 0, 'o'}, {"preserveaspect", no_argument, 0, 'p'}, {"scalefactor", required_argument, 0, 's'}, {"tvaspect", no_argument, 0, 't'}, {"no-tvaspect", no_argument, 0, 'r'}, {"unlimitedsprites", no_argument, 0, 'u'}, {"spritelimit", no_argument, 0, 'q'}, {"version", no_argument, 0, 'v'}, {0, 0, 0, 0} }; int option_index = 0; c = getopt_long(argc, argv, "defhl:mnopqrs:tuvw", long_options, &option_index); if (c == -1) { break; } switch(c) { case 'f': conf.video_fullscreen = true; break; case 'w': conf.video_fullscreen = false; break; case 'h': cli_show_usage(); exit(0); break; case 'l': optint = atoi(optarg); if (optint < 6) { conf.video_filter = optint; } else { cli_error("Error: Invalid filter"); } break; case 'm': conf.video_unmask_overscan = false; break; case 'n': conf.video_unmask_overscan = true; break; case 'o': conf.video_stretch_aspect = true; break; case 'p': conf.video_stretch_aspect = false; break; case 's': optint = atoi(optarg); if (optint < 5 && optint != 0) { conf.video_scale_factor = optint; } else { cli_error("Error: Invalid scale factor"); } break; case 't': conf.video_tv_aspect = true; break; case 'r': conf.video_tv_aspect = false; break; case 'u': conf.video_unlimited_sprites = true; break; case 'q': conf.video_unlimited_sprites = false; break; case 'v': cli_show_version(); exit(0); break; default: cli_error("Error: Invalid option"); break; } } } nestopia-1.51.1/source/fltkui/cli.h000066400000000000000000000002061411157722000171350ustar00rootroot00000000000000void cli_error(const char *message); void cli_show_usage(); void cli_show_version(); void cli_handle_command(int argc, char *argv[]); nestopia-1.51.1/source/fltkui/config.cpp000066400000000000000000000275521411157722000202030ustar00rootroot00000000000000/* * Nestopia UE * * Copyright (C) 2012-2016 R. Danbrook * Copyright (C) 2018-2018 Phil Smith * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include #include #include #include "config.h" #include "ini.h" settings_t conf; static int fs = 0; void config_file_read(const char *nstdir) { // Read the config file char confpath[256]; snprintf(confpath, sizeof(confpath), "%snestopia.conf", nstdir); if (ini_parse(confpath, config_match, &conf) < 0) { fprintf(stderr, "Failed to read config file %s: Using defaults.\n", confpath); } fs = conf.video_fullscreen; } void config_file_write(const char *nstdir) { // Write the config file char confpath[256]; snprintf(confpath, sizeof(confpath), "%snestopia.conf", nstdir); FILE *fp = fopen(confpath, "w"); if (fp != NULL) { // Video fprintf(fp, "; Nestopia UE Configuration File\n\n"); fprintf(fp, "[video]\n"); fprintf(fp, "; 0=None, 1=NTSC, 2=xBR, 3=HqX, 4=2xSaI, 5=ScaleX\n"); fprintf(fp, "filter=%d\n\n", conf.video_filter); fprintf(fp, "; Valid values are 1 to 8.\n"); fprintf(fp, "scale_factor=%d\n\n", conf.video_scale_factor); fprintf(fp, "; 0=YUV, 1=RGB, 2=Custom\n"); fprintf(fp, "palette_mode=%d\n\n", conf.video_palette_mode); fprintf(fp, "; 0=Consumer, 1=Canonical, 2=Alternative\n"); fprintf(fp, "decoder=%d\n\n", conf.video_decoder); fprintf(fp, "; Valid values are -100 to 100.\n"); fprintf(fp, "brightness=%d\n", conf.video_brightness); fprintf(fp, "saturation=%d\n", conf.video_saturation); fprintf(fp, "contrast=%d\n\n", conf.video_contrast); fprintf(fp, "; Valid values are -45 to 45.\n"); fprintf(fp, "hue=%d\n\n", conf.video_hue); fprintf(fp, "; 0=Composite, 1=S-Video, 2=RGB, 3=Monochrome, 4=Custom\n"); fprintf(fp, "ntsc_mode=%d\n\n", conf.video_ntsc_mode); fprintf(fp, "; Valid values are -100 to 100.\n"); fprintf(fp, "ntsc_sharpness=%d\n", conf.video_ntsc_sharpness); fprintf(fp, "ntsc_resolution=%d\n", conf.video_ntsc_resolution); fprintf(fp, "ntsc_bleed=%d\n", conf.video_ntsc_bleed); fprintf(fp, "ntsc_artifacts=%d\n", conf.video_ntsc_artifacts); fprintf(fp, "ntsc_fringing=%d\n\n", conf.video_ntsc_fringing); fprintf(fp, "; 0=None, 1=Some, 2=All\n"); fprintf(fp, "xbr_corner_rounding=%d\n\n", conf.video_xbr_corner_rounding); fprintf(fp, "; Valid values are 1 and 0.\n"); fprintf(fp, "linear_filter=%d\n", conf.video_linear_filter); fprintf(fp, "tv_aspect=%d\n", conf.video_tv_aspect); fprintf(fp, "unmask_overscan=%d\n", conf.video_unmask_overscan); fprintf(fp, "fullscreen=%d\n", fs); fprintf(fp, "stretch_aspect=%d\n", conf.video_stretch_aspect); fprintf(fp, "unlimited_sprites=%d\n", conf.video_unlimited_sprites); fprintf(fp, "xbr_pixel_blending=%d\n", conf.video_xbr_pixel_blending); fprintf(fp, "\n"); // End of Section // Audio fprintf(fp, "[audio]\n"); fprintf(fp, "; Valid values are 1 and 0.\n"); fprintf(fp, "stereo=%d\n\n", conf.audio_stereo); fprintf(fp, "; Valid values are 11025, 22050, 44100, 48000, and 96000.\n"); fprintf(fp, "sample_rate=%d\n\n", conf.audio_sample_rate); fprintf(fp, "; Valid values are 0 to 100.\n"); fprintf(fp, "volume=%d\n", conf.audio_volume); fprintf(fp, "vol_sq1=%d\n", conf.audio_vol_sq1); fprintf(fp, "vol_sq2=%d\n", conf.audio_vol_sq2); fprintf(fp, "vol_tri=%d\n", conf.audio_vol_tri); fprintf(fp, "vol_noise=%d\n", conf.audio_vol_noise); fprintf(fp, "vol_dpcm=%d\n", conf.audio_vol_dpcm); fprintf(fp, "vol_fds=%d\n", conf.audio_vol_fds); fprintf(fp, "vol_mmc5=%d\n", conf.audio_vol_mmc5); fprintf(fp, "vol_vrc6=%d\n", conf.audio_vol_vrc6); fprintf(fp, "vol_vrc7=%d\n", conf.audio_vol_vrc7); fprintf(fp, "vol_n163=%d\n", conf.audio_vol_n163); fprintf(fp, "vol_s5b=%d\n", conf.audio_vol_s5b); fprintf(fp, "\n"); // End of Section // Timing fprintf(fp, "[timing]\n"); fprintf(fp, "; Base speed for NTSC in Frames per Second.\n"); fprintf(fp, "speed=%d\n\n", conf.timing_speed); fprintf(fp, "; Fast-Forward Speed\n"); fprintf(fp, "ffspeed=%d\n\n", conf.timing_ffspeed); fprintf(fp, "; Pulse turbo buttons every n frames. Minimum value is 2.\n"); fprintf(fp, "turbopulse=%d\n", conf.timing_turbopulse); fprintf(fp, "\n"); // End of Section // Misc fprintf(fp, "[misc]\n"); fprintf(fp, "; 0=Auto, 1=NTSC, 2=PAL, 3=Famicom, 4=Dendy\n"); fprintf(fp, "default_system=%d\n\n", conf.misc_default_system); fprintf(fp, "; Valid values are 1 and 0.\n"); fprintf(fp, "soft_patching=%d\n", conf.misc_soft_patching); fprintf(fp, "genie_distortion=%d\n", conf.misc_genie_distortion); fprintf(fp, "disable_cursor=%d\n", conf.misc_disable_cursor); fprintf(fp, "disable_cursor_special=%d\n", conf.misc_disable_cursor_special); fprintf(fp, "config_pause=%d\n\n", conf.misc_config_pause); fprintf(fp, "; 0=0x00, 1=0xFF, 2=Random\n"); fprintf(fp, "power_state=%d\n\n", conf.misc_power_state); fprintf(fp, "; Valid values are -1 (disabled) or 0 to 65535.\n"); fprintf(fp, "homebrew_exit=%d\n", conf.misc_homebrew_exit); fprintf(fp, "homebrew_stdout=%d\n", conf.misc_homebrew_stdout); fprintf(fp, "homebrew_stderr=%d\n", conf.misc_homebrew_stderr); fclose(fp); } else { fprintf(stderr, "Failed to write config file %s.\n", confpath); } } void config_set_default() { // Video conf.video_filter = 0; conf.video_scale_factor = 2; conf.video_palette_mode = 0; conf.video_decoder = 0; conf.video_brightness = 0; // -100 to 100 conf.video_saturation = 0; // -100 to 100 conf.video_contrast = 0; // -100 to 100 conf.video_hue = 0; // -45 to 45 conf.video_ntsc_mode = 0; conf.video_ntsc_sharpness = 0; // -100 to 100 conf.video_ntsc_resolution = 0; // -100 to 100 conf.video_ntsc_bleed = 0; // -100 to 100 conf.video_ntsc_artifacts = 0; // -100 to 100 conf.video_ntsc_fringing = 0; // -100 to 100 conf.video_xbr_corner_rounding = 0; conf.video_linear_filter = false; conf.video_tv_aspect = false; conf.video_unmask_overscan = false; conf.video_fullscreen = false; conf.video_stretch_aspect = false; conf.video_unlimited_sprites = false; conf.video_xbr_pixel_blending = false; // Audio conf.audio_stereo = false; conf.audio_sample_rate = 48000; conf.audio_volume = 85; conf.audio_vol_sq1 = 85; conf.audio_vol_sq2 = 85; conf.audio_vol_tri = 85; conf.audio_vol_noise = 85; conf.audio_vol_dpcm = 85; conf.audio_vol_fds = 85; conf.audio_vol_mmc5 = 85; conf.audio_vol_vrc6 = 85; conf.audio_vol_vrc7 = 85; conf.audio_vol_n163 = 85; conf.audio_vol_s5b = 85; // Timing conf.timing_speed = 60; conf.timing_ffspeed = 3; conf.timing_turbopulse = 3; // Misc conf.misc_default_system = 0; conf.misc_soft_patching = true; conf.misc_genie_distortion = false; conf.misc_disable_cursor = false; conf.misc_disable_cursor_special = false; conf.misc_config_pause = false; conf.misc_power_state = 0; conf.misc_homebrew_exit = -1; conf.misc_homebrew_stdout = -1; conf.misc_homebrew_stderr = -1; } static int config_match(void* user, const char* section, const char* name, const char* value) { // Match values from config file and populate live config settings_t* pconfig = (settings_t*)user; // Video if (MATCH("video", "filter")) { pconfig->video_filter = atoi(value); } else if (MATCH("video", "scale_factor")) { pconfig->video_scale_factor = atoi(value); } else if (MATCH("video", "palette_mode")) { pconfig->video_palette_mode = atoi(value); } else if (MATCH("video", "decoder")) { pconfig->video_decoder = atoi(value); } else if (MATCH("video", "brightness")) { pconfig->video_brightness = atoi(value); } else if (MATCH("video", "saturation")) { pconfig->video_saturation = atoi(value); } else if (MATCH("video", "contrast")) { pconfig->video_contrast = atoi(value); } else if (MATCH("video", "hue")) { pconfig->video_hue = atoi(value); } else if (MATCH("video", "ntsc_mode")) { pconfig->video_ntsc_mode = atoi(value); } else if (MATCH("video", "ntsc_sharpness")) { pconfig->video_ntsc_sharpness = atoi(value); } else if (MATCH("video", "ntsc_resolution")) { pconfig->video_ntsc_resolution = atoi(value); } else if (MATCH("video", "ntsc_bleed")) { pconfig->video_ntsc_bleed = atoi(value); } else if (MATCH("video", "ntsc_artifacts")) { pconfig->video_ntsc_artifacts = atoi(value); } else if (MATCH("video", "ntsc_fringing")) { pconfig->video_ntsc_fringing = atoi(value); } else if (MATCH("video", "xbr_corner_rounding")) { pconfig->video_xbr_corner_rounding = atoi(value); } else if (MATCH("video", "linear_filter")) { pconfig->video_linear_filter = atoi(value); } else if (MATCH("video", "tv_aspect")) { pconfig->video_tv_aspect = atoi(value); } else if (MATCH("video", "unmask_overscan")) { pconfig->video_unmask_overscan = atoi(value); } else if (MATCH("video", "fullscreen")) { pconfig->video_fullscreen = atoi(value); } else if (MATCH("video", "stretch_aspect")) { pconfig->video_stretch_aspect = atoi(value); } else if (MATCH("video", "unlimited_sprites")) { pconfig->video_unlimited_sprites = atoi(value); } else if (MATCH("video", "xbr_pixel_blending")) { pconfig->video_xbr_pixel_blending = atoi(value); } // Audio else if (MATCH("audio", "stereo")) { pconfig->audio_stereo = atoi(value); } else if (MATCH("audio", "sample_rate")) { pconfig->audio_sample_rate = atoi(value); } else if (MATCH("audio", "volume")) { pconfig->audio_volume = atoi(value); } else if (MATCH("audio", "vol_sq1")) { pconfig->audio_vol_sq1 = atoi(value); } else if (MATCH("audio", "vol_sq2")) { pconfig->audio_vol_sq2 = atoi(value); } else if (MATCH("audio", "vol_tri")) { pconfig->audio_vol_tri = atoi(value); } else if (MATCH("audio", "vol_noise")) { pconfig->audio_vol_noise = atoi(value); } else if (MATCH("audio", "vol_dpcm")) { pconfig->audio_vol_dpcm = atoi(value); } else if (MATCH("audio", "vol_fds")) { pconfig->audio_vol_fds = atoi(value); } else if (MATCH("audio", "vol_mmc5")) { pconfig->audio_vol_mmc5 = atoi(value); } else if (MATCH("audio", "vol_vrc6")) { pconfig->audio_vol_vrc6 = atoi(value); } else if (MATCH("audio", "vol_vrc7")) { pconfig->audio_vol_vrc7 = atoi(value); } else if (MATCH("audio", "vol_n163")) { pconfig->audio_vol_n163 = atoi(value); } else if (MATCH("audio", "vol_s5b")) { pconfig->audio_vol_s5b = atoi(value); } // Timing else if (MATCH("timing", "speed")) { pconfig->timing_speed = atoi(value); } else if (MATCH("timing", "ffspeed")) { pconfig->timing_ffspeed = atoi(value); } else if (MATCH("timing", "turbopulse")) { pconfig->timing_turbopulse = atoi(value); } // Misc else if (MATCH("misc", "default_system")) { pconfig->misc_default_system = atoi(value); } else if (MATCH("misc", "soft_patching")) { pconfig->misc_soft_patching = atoi(value); } else if (MATCH("misc", "genie_distortion")) { pconfig->misc_genie_distortion = atoi(value); } else if (MATCH("misc", "config_pause")) { pconfig->misc_config_pause = atoi(value); } else if (MATCH("misc", "disable_cursor")) { pconfig->misc_disable_cursor = atoi(value); } else if (MATCH("misc", "disable_cursor_special")) { pconfig->misc_disable_cursor_special = atoi(value); } else if (MATCH("misc", "power_state")) { pconfig->misc_power_state = atoi(value); } else if (MATCH("misc", "homebrew_exit")) { pconfig->misc_homebrew_exit = atoi(value); } else if (MATCH("misc", "homebrew_stdout")) { pconfig->misc_homebrew_stdout = atoi(value); } else if (MATCH("misc", "homebrew_stderr")) { pconfig->misc_homebrew_stderr = atoi(value); } else { return 0; } return 1; } nestopia-1.51.1/source/fltkui/config.h000066400000000000000000000027731411157722000176460ustar00rootroot00000000000000#ifndef _CONFIG_H_ #define _CONFIG_H_ typedef struct { // Video int video_filter; int video_scale_factor; int video_palette_mode; int video_decoder; int video_brightness; int video_saturation; int video_contrast; int video_hue; int video_ntsc_mode; int video_ntsc_sharpness; int video_ntsc_resolution; int video_ntsc_bleed; int video_ntsc_artifacts; int video_ntsc_fringing; int video_xbr_corner_rounding; bool video_linear_filter; bool video_tv_aspect; bool video_unmask_overscan; bool video_fullscreen; bool video_stretch_aspect; bool video_unlimited_sprites; bool video_xbr_pixel_blending; // Audio bool audio_stereo; int audio_sample_rate; int audio_volume; int audio_vol_sq1; int audio_vol_sq2; int audio_vol_tri; int audio_vol_noise; int audio_vol_dpcm; int audio_vol_fds; int audio_vol_mmc5; int audio_vol_vrc6; int audio_vol_vrc7; int audio_vol_n163; int audio_vol_s5b; // Timing int timing_speed; int timing_ffspeed; int timing_turbopulse; // Misc int misc_default_system; bool misc_soft_patching; bool misc_genie_distortion; bool misc_disable_cursor; bool misc_disable_cursor_special; bool misc_config_pause; int misc_power_state; int misc_homebrew_exit; int misc_homebrew_stdout; int misc_homebrew_stderr; } settings_t; void config_file_read(const char *nstdir); void config_file_write(const char *nstdir); void config_set_default(); static int config_match(void* user, const char* section, const char* name, const char* value); extern settings_t conf; #endif nestopia-1.51.1/source/fltkui/fltkui.cpp000066400000000000000000000347371411157722000202370ustar00rootroot00000000000000/* * Nestopia UE * * Copyright (C) 2012-2021 R. Danbrook * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include "nstcommon.h" #include "cli.h" #include "config.h" #include "audio.h" #include "video.h" #include "input.h" #include "cheats.h" #include "fltkui.h" #include "fltkui_archive.h" #include "fltkui_cheats.h" #include "fltkui_config.h" #define MBARHEIGHT 24 static NstWindow *nstwin; static Fl_Menu_Bar *menubar; static NstGlArea *glarea; static NstChtWindow *chtwin; static NstConfWindow *confwin; extern int loaded; Fl_Color NstGreen = 0x255f6500; Fl_Color NstPurple = 0x5f578700; Fl_Color NstRed = 0xb51e2c00; Fl_Color NstBlueGrey = 0x383c4a00; Fl_Color NstLightGrey = 0xd3dae300; extern Input::Controllers *cNstPads; extern nstpaths_t nstpaths; extern bool (*nst_archive_select)(const char*, char*, size_t); static void fltkui_cheats(Fl_Widget* w, void* userdata) { if (!loaded) { return; } chtwin->refresh(); chtwin->show(); } static void fltkui_config(Fl_Widget* w, void* userdata) { confwin->show(); } static void fltkui_rom_open(Fl_Widget* w, void* userdata) { // Create native chooser Fl_Native_File_Chooser fc; fc.title("Select a ROM"); fc.type(Fl_Native_File_Chooser::BROWSE_FILE); fc.filter("NES Games\t*.{nes,unf,fds,zip,7z,gz,bz2,xz}"); // Show file chooser switch (fc.show()) { case -1: fprintf(stderr, "Error: %s\n", fc.errmsg()); break; case 1: break; // Cancel default: if (fc.filename()) { loaded = nst_load(fc.filename()); nstwin->label(nstpaths.gamename); if (loaded) { nst_play(); } } break; } } static void fltkui_movie_load(Fl_Widget* w, void* userdata) { // Create native chooser if (!loaded) { return; } Fl_Native_File_Chooser fc; fc.title("Select a Movie"); fc.type(Fl_Native_File_Chooser::BROWSE_FILE); fc.directory((const char*)nstpaths.nstdir); fc.filter("Nestopia Movies\t*.nsv"); // Show file chooser switch (fc.show()) { case -1: fprintf(stderr, "Error: %s\n", fc.errmsg()); break; case 1: break; // Cancel default: if (fc.filename()) { nst_movie_load(fc.filename()); } break; } } static void fltkui_movie_save(Fl_Widget* w, void* userdata) { // Create native chooser if (!loaded) { return; } Fl_Native_File_Chooser fc; fc.title("Save Movie"); fc.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); fc.directory((const char*)nstpaths.nstdir); fc.filter("Nestopia Moviess\t*.nsv"); fc.options(Fl_Native_File_Chooser::SAVEAS_CONFIRM | Fl_Native_File_Chooser::USE_FILTER_EXT); // Show file chooser if (fc.show()) { return; } nst_movie_save(fc.filename()); } static void fltkui_movie_stop(Fl_Widget* w, void* userdata) { nst_movie_stop(); } static void fltkui_state_load(Fl_Widget* w, void* userdata) { // Create native chooser if (!loaded) { return; } Fl_Native_File_Chooser fc; fc.title("Load State"); fc.type(Fl_Native_File_Chooser::BROWSE_FILE); fc.directory((const char*)nstpaths.statepath); fc.filter("Nestopia States\t*.nst"); // Show file chooser switch (fc.show()) { case -1: fprintf(stderr, "Error: %s\n", fc.errmsg()); break; case 1: break; // Cancel default: if (fc.filename()) { nst_state_load(fc.filename()); } break; } } static void fltkui_state_save(Fl_Widget* w, void* userdata) { // Create native chooser if (!loaded) { return; } Fl_Native_File_Chooser fc; fc.title("Save State"); fc.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); fc.directory((const char*)nstpaths.statepath); fc.filter("Nestopia States\t*.nst"); fc.options(Fl_Native_File_Chooser::SAVEAS_CONFIRM | Fl_Native_File_Chooser::USE_FILTER_EXT); // Show file chooser if (fc.show()) { return; } nst_state_save(fc.filename()); } static void fltkui_screenshot(Fl_Widget* w, void* userdata) { // Create native chooser if (!loaded) { return; } Fl_Native_File_Chooser fc; fc.title("Save Screenshot"); fc.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); fc.directory((const char*)nstpaths.nstdir); fc.filter("PNG Screenshots\t*.png"); fc.options(Fl_Native_File_Chooser::SAVEAS_CONFIRM | Fl_Native_File_Chooser::USE_FILTER_EXT); // Show file chooser if (fc.show()) { return; } video_screenshot(fc.filename()); } static void fltkui_palette_open(Fl_Widget* w, void* userdata) { // Create native chooser Fl_Native_File_Chooser fc; fc.title("Select a Palette"); fc.type(Fl_Native_File_Chooser::BROWSE_FILE); fc.filter("NES Palettes\t*.pal"); // Show file chooser switch (fc.show()) { case -1: fprintf(stderr, "Error: %s\n", fc.errmsg()); break; case 1: break; // Cancel default: if (fc.filename()) { nst_palette_load(fc.filename()); nst_palette_save(); conf.video_palette_mode = 2; video_init(); } break; } } static void fltkui_state_qload(Fl_Widget* w, void* userdata) { nst_state_quickload(atoi((const char*)userdata)); } static void fltkui_state_qsave(Fl_Widget* w, void* userdata) { nst_state_quicksave(atoi((const char*)userdata)); } static void fltkui_pause(Fl_Widget* w, void* userdata) { if (nst_playing()) { nst_pause(); } else { nst_play(); } } static void fltkui_reset(Fl_Widget* w, void* userdata) { nst_reset(atoi((const char*)userdata)); } void fltkui_resize() { video_set_dimensions(); dimensions_t rendersize = nst_video_get_dimensions_render(); nstwin->size(rendersize.w, rendersize.h + MBARHEIGHT); menubar->resize(0, 0, nstwin->w(), MBARHEIGHT); glarea->resize(0, 24, rendersize.w, rendersize.h); nst_video_set_dimensions_screen(rendersize); video_init(); } void fltkui_fullscreen(Fl_Widget* w, void* userdata) { if (!nst_playing()) { return; } conf.video_fullscreen ^= 1; if (conf.video_fullscreen) { int x, y, w, h; Fl::screen_xywh(x, y, w, h); menubar->hide(); nstwin->fullscreen(); dimensions_t scrdim = {w, h}; nstwin->resize(0, 0, scrdim.w, scrdim.h); glarea->resize(0, 0, scrdim.w, scrdim.h); nst_video_set_dimensions_screen(scrdim); video_init(); } else { video_set_dimensions(); dimensions_t rendersize = nst_video_get_dimensions_render(); nstwin->fullscreen_off(); nstwin->size(rendersize.w, rendersize.h + MBARHEIGHT); menubar->show(); menubar->resize(0, 0, nstwin->w(), MBARHEIGHT); glarea->resize(0, 24, rendersize.w, rendersize.h); nst_video_set_dimensions_screen(rendersize); video_init(); } } static void fltkui_fds_flip(Fl_Widget* w, void* userdata) { nst_fds_flip(); } static void fltkui_fds_switch(Fl_Widget* w, void* userdata) { nst_fds_switch(); } static void fltkui_about_close(Fl_Widget* w, void* userdata) { Fl_Window *about = (Fl_Window*)userdata; about->hide(); } static void fltkui_about(Fl_Widget* w, void* userdata) { Fl_Window about(460, 440); Fl_Box iconbox(166, 16, 128, 128); Fl_Box text0(0, 144, 460, 24, "Nestopia UE"); text0.labelfont(FL_BOLD); Fl_Box text1(0, 166, 460, 24, "1.51.1"); Fl_Box text2(0, 208, 460, 24, "Cycle-Accurate Nintendo Entertainment System Emulator"); Fl_Box text3(0, 256, 460, 24, "FLTK Frontend\n(c) 2012-2021, R. Danbrook\n(c) 2007-2008, R. Belmont"); text3.labelsize(10); Fl_Box text4(0, 320, 460, 24, "Nestopia Emulator\n(c) 2020-2021, Rupert Carmichael\n(c) 2012-2020, Nestopia UE Contributors\n(c) 2003-2008, Martin Freij"); text4.labelsize(10); Fl_Box text5(0, 360, 460, 24, "Icon based on drawing by Trollekop"); text5.labelsize(10); // Set up the icon char iconpath[512]; snprintf(iconpath, sizeof(iconpath), "%s/icons/hicolor/128x128/apps/nestopia.png", DATAROOTDIR); // Load the SVG from local source dir if make install hasn't been done struct stat svgstat; if (stat(iconpath, &svgstat) == -1) { snprintf(iconpath, sizeof(iconpath), "icons/128/nestopia.png"); } Fl_PNG_Image nsticon(iconpath); iconbox.image(nsticon); Fl_Button close(360, 400, 80, 24, "&Close"); close.callback(fltkui_about_close, (void*)&about); about.set_modal(); about.show(); while (about.shown()) { Fl::wait(); } } static void quit_cb(Fl_Widget* w, void* userdata) { nstwin->hide(); } // this is used to stop Esc from exiting the program: int handle(int e) { return (e == FL_SHORTCUT); // eat all keystrokes } int NstWindow::handle(int e) { switch (e) { case FL_KEYDOWN: case FL_KEYUP: fltkui_input_process_key(e); break; } return Fl_Double_Window::handle(e); } int NstGlArea::handle(int e) { if (nst_input_zapper_present()) { switch (e) { case FL_ENTER: cursor(conf.misc_disable_cursor_special ? FL_CURSOR_NONE : FL_CURSOR_CROSS); break; case FL_LEAVE: cursor(FL_CURSOR_DEFAULT); break; case FL_PUSH: nst_input_inject_mouse(cNstPads, Fl::event_button(), 1, Fl::event_x(), Fl::event_y()); break; case FL_RELEASE: nst_input_inject_mouse(cNstPads, Fl::event_button(), 0, Fl::event_x(), Fl::event_y()); break; } } else if (e == FL_ENTER && conf.misc_disable_cursor) { cursor(FL_CURSOR_NONE); } else if (e == FL_LEAVE) { cursor(FL_CURSOR_DEFAULT); } return Fl_Gl_Window::handle(e); } static Fl_Menu_Item menutable[] = { {"&File", 0, 0, 0, FL_SUBMENU}, {"&Open", FL_ALT + 'o', fltkui_rom_open, 0, FL_MENU_DIVIDER}, {"Load State...", 0, fltkui_state_load, 0, 0}, {"Save State...", 0, fltkui_state_save, 0, FL_MENU_DIVIDER}, {"Quick Load", 0, 0, 0, FL_SUBMENU}, {"Slot 0", 0, fltkui_state_qload, (void*)"0", 0}, {"Slot 1", 0, fltkui_state_qload, (void*)"1", 0}, {"Slot 2", 0, fltkui_state_qload, (void*)"2", 0}, {"Slot 3", 0, fltkui_state_qload, (void*)"3", 0}, {"Slot 4", 0, fltkui_state_qload, (void*)"4", 0}, {0}, {"Quick Save", 0, 0, 0, FL_SUBMENU|FL_MENU_DIVIDER}, {"Slot 0", 0, fltkui_state_qsave, (void*)"0", 0}, {"Slot 1", 0, fltkui_state_qsave, (void*)"1", 0}, {"Slot 2", 0, fltkui_state_qsave, (void*)"2", 0}, {"Slot 3", 0, fltkui_state_qsave, (void*)"3", 0}, {"Slot 4", 0, fltkui_state_qsave, (void*)"4", 0}, {0}, {"Open Palette...", 0, fltkui_palette_open, 0, FL_MENU_DIVIDER}, {"Screenshot...", 0, fltkui_screenshot, 0, FL_MENU_DIVIDER}, {"Load Movie...", 0, fltkui_movie_load, 0, 0}, {"Record Movie...", 0, fltkui_movie_save, 0, 0}, {"Stop Movie", 0, fltkui_movie_stop, 0, FL_MENU_DIVIDER}, {"&Quit", FL_ALT + 'q', quit_cb}, {0}, // End File {"&Emulator", 0, 0, 0, FL_SUBMENU}, {"Pause/Play", 0, fltkui_pause, 0, FL_MENU_DIVIDER}, {"Reset (Soft)", 0, fltkui_reset, (void*)"0", 0}, {"Reset (Hard)", 0, fltkui_reset, (void*)"1", FL_MENU_DIVIDER}, {"Fullscreen", 0, fltkui_fullscreen, 0, FL_MENU_DIVIDER}, {"Flip Disk", 0, fltkui_fds_flip, 0, 0}, {"Switch Disk", 0, fltkui_fds_switch, 0, FL_MENU_DIVIDER}, {"Cheats...", 0, fltkui_cheats, 0, FL_MENU_DIVIDER}, {"Configuration...", 0, fltkui_config, 0}, {0}, // End Emulator {"&Help", 0, 0, 0, FL_SUBMENU}, {"About", 0, fltkui_about, 0, 0}, {0}, // End Help {0} // End Menu }; void makenstwin(const char *name) { video_set_dimensions(); dimensions_t rendersize = nst_video_get_dimensions_render(); Fl::add_handler(handle); // Cheats Window chtwin = new NstChtWindow(660, 500, "Cheat Manager"); chtwin->populate(); // Configuration Window confwin = new NstConfWindow(400, 400, "Configuration"); confwin->populate(); // Main Window nstwin = new NstWindow(rendersize.w, rendersize.h + MBARHEIGHT, name); nstwin->color(FL_BLACK); nstwin->xclass("nestopia"); // Menu Bar menubar = new Fl_Menu_Bar(0, 0, nstwin->w(), MBARHEIGHT); menubar->box(FL_FLAT_BOX); menubar->menu(menutable); glarea = new NstGlArea(0, MBARHEIGHT, nstwin->w(), nstwin->h() - MBARHEIGHT); glarea->color(FL_BLACK); nstwin->end(); } int main(int argc, char *argv[]) { // Set up directories nst_set_dirs(); // Set default config options config_set_default(); // Read the config file and override defaults config_file_read(nstpaths.nstconfdir); // Handle command line arguments cli_handle_command(argc, argv); // Set the video dimensions video_set_dimensions(); // Set up callbacks nst_set_callbacks(); // Initialize SDL Audio and Joystick if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) { fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError()); return 1; } // Set archive handler function pointer nst_archive_select = &fltkui_archive_select; // Detect and set up Joysticks nstsdl_input_joysticks_detect(); nstsdl_input_conf_defaults(); nstsdl_input_conf_read(); // Initialize and load FDS BIOS and NstDatabase.xml nst_fds_bios_load(); nst_db_load(); makenstwin(argv[0]); nstwin->label("Nestopia UE"); nstwin->show(); menubar->show(); glarea->make_current(); glarea->show(); Fl::check(); // Load a rom from the command line if (argc > 1 && argv[argc - 1][0] != '-') { int loaded = nst_load(argv[argc - 1]); if (loaded) { nst_play(); } else { exit(1); } nstwin->label(nstpaths.gamename); } else if (conf.video_fullscreen) { conf.video_fullscreen = 0; } if (conf.video_fullscreen) { conf.video_fullscreen = 0; fltkui_fullscreen(NULL, NULL); } video_init(); while (true) { Fl::check(); if (!nstwin->shown()) { break; } else if (!nstwin->shown() && (confwin->shown() || chtwin->shown())) { break; } SDL_Event event; while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_JOYHATMOTION: case SDL_JOYAXISMOTION: case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP: nstsdl_input_process(cNstPads, event); break; default: break; } } nst_emuloop(); glarea->redraw(); } // Remove the cartridge and shut down the NES nst_unload(); // Unload the FDS BIOS, NstDatabase.xml, and the custom palette nst_db_unload(); nst_fds_bios_unload(); nst_palette_unload(); // Deinitialize audio audio_deinit(); // Deinitialize joysticks nstsdl_input_joysticks_close(); // Write the input config file nstsdl_input_conf_write(); // Write the config file config_file_write(nstpaths.nstconfdir); return 0; } nestopia-1.51.1/source/fltkui/fltkui.h000066400000000000000000000012401411157722000176630ustar00rootroot00000000000000#ifndef MAIN_H #define MAIN_H class NstWindow : public Fl_Double_Window { private: int handle(int e); public: NstWindow(int w, int h, const char* t = 0) : Fl_Double_Window(w, h, t) { } virtual ~NstWindow() { } }; class NstGlArea : public Fl_Gl_Window { private: void draw() { nst_ogl_render(); } int handle(int e); public: NstGlArea(int x, int y, int w, int h, const char *l = 0) : Fl_Gl_Window(x, y, w, h, l) { box(FL_DOWN_FRAME); } }; extern Fl_Color NstGreen; extern Fl_Color NstPurple; extern Fl_Color NstRed; extern Fl_Color NstBlueGrey; extern Fl_Color NstLightGrey; void fltkui_resize(); void fltkui_fullscreen(Fl_Widget* w, void* userdata); #endif nestopia-1.51.1/source/fltkui/fltkui_archive.cpp000066400000000000000000000065621411157722000217330ustar00rootroot00000000000000/* * Nestopia UE * * Copyright (C) 2012-2021 R. Danbrook * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include #include #include #include #include #include #include #include #include "nstcommon.h" #include "config.h" #include "fltkui_archive.h" static Fl_Double_Window *window; static Fl_Select_Browser *browser; static char *romfile = NULL; static void fltkui_archive_ok(Fl_Widget *w, long) { window->hide(); } static void fltkui_archive_cancel(Fl_Widget *w, long) { snprintf(romfile, 256, "%s", ""); window->hide(); } static void fltkui_archive_setfile(Fl_Widget *w, long) { int r = ((Fl_Browser*)w)->value(); if (r) { snprintf(romfile, 256, "%s", ((Fl_Browser*)w)->text(r)); if (Fl::event_clicks()) { window->hide(); } } else { snprintf(romfile, 256, "%s", ""); } } bool fltkui_archive_select(const char *filename, char *reqfile, size_t reqsize) { // Select a filename to pull out of the archive struct archive *a; struct archive_entry *entry; int r, numarchives = 0; a = archive_read_new(); archive_read_support_filter_all(a); archive_read_support_format_all(a); r = archive_read_open_filename(a, filename, 10240); // Test if it's actually an archive if (r != ARCHIVE_OK) { r = archive_read_free(a); return false; } // If it is an archive, handle it else { if (window) { delete window; } window = new Fl_Double_Window(420, 260, "Load from Archive"); browser = new Fl_Select_Browser(0, 0, window->w(), 200, 0); browser->type(FL_HOLD_BROWSER); browser->callback(fltkui_archive_setfile, 0); Fl_Button btncancel(260, 220, 80, 24, "&Cancel"); btncancel.callback(fltkui_archive_cancel, 0); Fl_Button btnok(350, 220, 40, 24, "&OK"); btnok.callback(fltkui_archive_ok, 0); romfile = reqfile; // Fill the treestore with the filenames while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { const char *currentfile = archive_entry_pathname(entry); if (nst_archive_checkext(currentfile)) { browser->add(currentfile); numarchives++; snprintf(reqfile, reqsize, "%s", currentfile); } archive_read_data_skip(a); } // Free the archive r = archive_read_free(a); // If there are no valid files in the archive, return if (numarchives == 0) { return false; } // If there's only one file, don't bring up the selector else if (numarchives == 1) { return true; } browser->select(1); snprintf(romfile, 256, "%s", browser->text(1)); window->resizable(browser); window->show(); window->set_modal(); window->show(); while (window->shown()) { Fl::wait(); } if (strlen(romfile)) { return true; } } return false; } nestopia-1.51.1/source/fltkui/fltkui_archive.h000066400000000000000000000002201411157722000213610ustar00rootroot00000000000000#ifndef _FLTKUI_ARCHIVE_H_ #define _FLTKUI_ARCHIVE_H_ bool fltkui_archive_select(const char *filename, char *reqfile, size_t reqsize); #endif nestopia-1.51.1/source/fltkui/fltkui_cheats.cpp000066400000000000000000000155601411157722000215570ustar00rootroot00000000000000/* * Nestopia UE * * Copyright (C) 2012-2021 R. Danbrook * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include #include #include #include #include #include #include #include #include "cheats.h" #include "nstcommon.h" #include "fltkui_cheats.h" static Fl_Input *input_desc; static Fl_Input *input_gg; static Fl_Input *input_par; static int rsel = 0; extern Emulator emulator; extern std::vector chtlist; extern nstpaths_t nstpaths; class ChtTable : public Fl_Table_Row { protected: void draw_cell(TableContext context, int R=0, int C=0, int X=0, int Y=0, int W=0, int H=0); public: ChtTable(int x, int y, int w, int h, const char *l=0) : Fl_Table_Row(x,y,w,h,l) { end(); } ~ChtTable() { } }; static ChtTable *ctable; static void cb_ok(Fl_Widget *w, long) { w->parent()->hide(); } void cb_table(Fl_Widget* w, long rn) { Fl_Table *table = (Fl_Table*)w; if (!table->rows()) { return; } rn = table->callback_row(); rsel = rn; if (Fl::event_clicks() > 0) { chtlist[rn].enabled = !chtlist[rn].enabled; nst_cheats_refresh(); } ctable->redraw(); } void cb_toggle(Fl_Widget* w, long) { if (!chtlist.size()) { return; } chtlist[rsel].enabled = !chtlist[rsel].enabled; nst_cheats_refresh(); ctable->redraw(); } void cb_add(Fl_Widget* w, long) { NstCheat cht; bool addgg = false; bool addpar = false; cht.enabled = true; wchar_t wtmp[256]; mbstowcs(wtmp, input_desc->value(), 256); cht.description = std::wstring(wtmp); if (strlen(input_gg->value())) { mbstowcs(wtmp, input_gg->value(), 256); cht.gg = std::wstring(wtmp); addgg = true; } if (strlen(input_par->value())) { mbstowcs(wtmp, input_par->value(), 256); cht.par = std::wstring(wtmp); addpar = true; } cht.address = cht.value = cht.compare = 0; if (addgg || addpar) { chtlist.push_back(cht); nst_cheats_refresh(); ctable->rows(chtlist.size()); input_desc->value(""); input_gg->value(""); input_par->value(""); return; } } void cb_del(Fl_Widget* w, long) { if (chtlist.size()) { chtlist.erase(chtlist.begin() + rsel); nst_cheats_refresh(); ctable->rows(chtlist.size()); } } void cb_clr(Fl_Widget* w, long) { chtlist.clear(); nst_cheats_refresh(); ctable->rows(chtlist.size()); } void cb_load(Fl_Widget* w, long) { Fl_Native_File_Chooser fc; fc.title("Select a Cheat List"); fc.type(Fl_Native_File_Chooser::BROWSE_FILE); fc.directory((const char*)nstpaths.cheatpath); fc.filter("Nestopia Cheats\t*.xml"); // Show file chooser switch (fc.show()) { case -1: fprintf(stderr, "Error: %s\n", fc.errmsg()); break; case 1: break; // Cancel default: if (fc.filename()) { chtlist.clear(); nst_cheats_init(fc.filename()); ctable->rows(chtlist.size()); } break; } } void cb_save(Fl_Widget* w, long) { Fl_Native_File_Chooser fc; fc.title("Save Cheat List"); fc.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); fc.directory((const char*)nstpaths.cheatpath); std::string preset = std::string(nstpaths.cheatpath) + "/" + std::string(nstpaths.gamename) + ".xml"; fc.preset_file(preset.c_str()); fc.filter("Nestopia Cheats\t*.xml"); fc.options(Fl_Native_File_Chooser::SAVEAS_CONFIRM | Fl_Native_File_Chooser::USE_FILTER_EXT); // Show file chooser if (fc.show()) { return; } nst_cheats_save(fc.filename()); } // Handle drawing all cells in table void ChtTable::draw_cell(TableContext context, int r, int c, int X, int Y, int W, int H) { static char s[128]; switch (context) { case CONTEXT_COL_HEADER: switch (c) { case 0: snprintf(s, sizeof(s), ""); break; case 1: snprintf(s, sizeof(s), "Game Genie"); break; case 2: snprintf(s, sizeof(s), "PAR"); break; case 3: snprintf(s, sizeof(s), "Raw"); break; case 4: snprintf(s, sizeof(s), "Description"); break; } fl_push_clip(X, Y, W, H); fl_draw_box(FL_THIN_UP_BOX, X, Y, W, H, color()); fl_color(FL_BLACK); fl_draw(s, X, Y, W, H, FL_ALIGN_CENTER); fl_pop_clip(); return; case CONTEXT_CELL: fl_push_clip(X, Y, W, H); switch (c) { case 0: snprintf(s, sizeof(s), "%s", chtlist[r].enabled ? "On" : "Off"); break; case 1: snprintf(s, sizeof(s), "%ls", chtlist[r].gg.c_str()); break; case 2: snprintf(s, sizeof(s), "%ls", chtlist[r].par.c_str()); break; case 3: if (chtlist[r].address) { snprintf(s, sizeof(s), "%04X %02X %02X", chtlist[r].address, chtlist[r].value, chtlist[r].compare); } else { snprintf(s, sizeof(s), ""); } break; case 4: snprintf(s, sizeof(s), "%ls", chtlist[r].description.c_str()); break; default: break; } // Background fl_color( row_selected(r) ? selection_color() : FL_WHITE); fl_rectf(X, Y, W, H); // Text fl_color(FL_BLACK); fl_draw(s, X, Y, W, H, c ? FL_ALIGN_LEFT : FL_ALIGN_CENTER); fl_pop_clip(); return; default: return; } } void NstChtWindow::refresh() { ctable->rows(chtlist.size()); ctable->row_header(0); } void NstChtWindow::populate() { ctable = new ChtTable(19, 20, 642, 270); ctable->selection_color(FL_YELLOW); ctable->cols(5); ctable->col_header(1); // enable col header ctable->col_width(0, 80); ctable->col_width(1, 100); ctable->col_width(2, 90); ctable->col_width(3, 90); ctable->col_width(4, 260); ctable->callback(cb_table, 0); ctable->when(FL_WHEN_CHANGED); ctable->end(); input_desc = new Fl_Input(380, 310, 260, 25, "Description:"); input_gg = new Fl_Input(380, 340, 260, 25, "Game Genie:"); input_par = new Fl_Input(380, 370, 260, 25, "Pro Action Rocky:"); Fl_Button *btnadd = new Fl_Button(380, 400, 80, 25, "Add"); btnadd->callback(cb_add, 0); Fl_Button *btntog = new Fl_Button(20, 300, 80, 25, "Toggle"); btntog->callback(cb_toggle, 0); Fl_Button *btndel = new Fl_Button(110, 300, 80, 25, "Delete"); btndel->callback(cb_del, 0); Fl_Button *btnclr = new Fl_Button(200, 300, 80, 25, "Clear"); btnclr->callback(cb_clr, 0); Fl_Button *btnload = new Fl_Button(20, 350, 80, 25, "Load..."); btnload->callback(cb_load, 0); Fl_Button *btnsave = new Fl_Button(20, 380, 80, 25, "Save..."); btnsave->callback(cb_save, 0); Fl_Button *btnok = new Fl_Button(560, 460, 80, 25, "&OK"); btnok->callback(cb_ok, 0); this->end(); } nestopia-1.51.1/source/fltkui/fltkui_cheats.h000066400000000000000000000004451411157722000212200ustar00rootroot00000000000000#ifndef _FLTKUI_CHEATS_H_ #define _FLTKUI_CHEATS_H_ class NstChtWindow : public Fl_Double_Window { //private: // bool icfg_running; public: NstChtWindow(int w, int h, const char* t) : Fl_Double_Window(w, h, t) { } virtual ~NstChtWindow() { } void refresh(); void populate(); }; #endif nestopia-1.51.1/source/fltkui/fltkui_config.cpp000066400000000000000000000511441411157722000215530ustar00rootroot00000000000000/* * Nestopia UE * * Copyright (C) 2012-2021 R. Danbrook * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nstcommon.h" #include "config.h" #include "audio.h" #include "video.h" #include "input.h" #include "fltkui.h" #include "fltkui_config.h" static const char *icfg_labels[10] = { "Press Key For: Up", "Press Key For: Down", "Press Key For: Left", "Press Key For: Right", "Press Key For: Select", "Press Key For: Start", "Press Key For: A", "Press Key For: B", "Press Key For: Turbo A", "Press Key For: Turbo B" }; NstInputConfWindow *icfg; static Fl_Dial *dial_vall, *dial_vsq1, *dial_vsq2, *dial_vtri, *dial_vnoise, *dial_vdpcm, *dial_vfds, *dial_vmmc5, *dial_vvrc6, *dial_vvrc7, *dial_vn163, *dial_vs5b; extern inputsettings_t inputconf; static void cb_filter(Fl_Widget *w, long) { conf.video_filter = ((Fl_Choice*)w)->value(); fltkui_resize(); } static void cb_scale(Fl_Widget *w, long) { conf.video_scale_factor = ((Fl_Choice*)w)->value() + 1; fltkui_resize(); } static void cb_ntscmode(Fl_Widget *w, long) { conf.video_ntsc_mode = ((Fl_Choice*)w)->value(); fltkui_resize(); } static void cb_xbrrounding(Fl_Widget *w, long) { conf.video_xbr_corner_rounding = ((Fl_Choice*)w)->value(); video_init(); video_toggle_filterupdate(); } static void cb_palettemode(Fl_Widget *w, long) { conf.video_palette_mode = ((Fl_Choice*)w)->value(); video_init(); } static void cb_decoder(Fl_Widget *w, long) { conf.video_decoder = ((Fl_Choice*)w)->value(); video_init(); } static void cb_brightness(Fl_Widget *w, long) { conf.video_brightness = ((Fl_Valuator*)w)->value(); video_init(); } static void cb_saturation(Fl_Widget *w, long) { conf.video_saturation = ((Fl_Valuator*)w)->value(); video_init(); } static void cb_contrast(Fl_Widget *w, long) { conf.video_contrast = ((Fl_Valuator*)w)->value(); video_init(); } static void cb_hue(Fl_Widget *w, long) { conf.video_hue = ((Fl_Valuator*)w)->value(); video_init(); } static void cb_xbrpixblend(Fl_Widget *w, long) { conf.video_xbr_pixel_blending = ((Fl_Check_Button*)w)->value(); video_init(); video_toggle_filterupdate(); } static void cb_linearfilter(Fl_Widget *w, long) { conf.video_linear_filter = ((Fl_Check_Button*)w)->value(); video_init(); } static void cb_tvaspect(Fl_Widget *w, long) { conf.video_tv_aspect = ((Fl_Check_Button*)w)->value(); fltkui_resize(); } static void cb_unmask_overscan(Fl_Widget *w, long) { conf.video_unmask_overscan = ((Fl_Check_Button*)w)->value(); fltkui_resize(); } static void cb_unlimited_sprites(Fl_Widget *w, long) { conf.video_unlimited_sprites = ((Fl_Check_Button*)w)->value(); } static void cb_samplerate(Fl_Widget *w, long) { switch (((Fl_Choice*)w)->value()) { case 0: conf.audio_sample_rate = 11025; break; case 1: conf.audio_sample_rate = 22050; break; case 2: conf.audio_sample_rate = 44100; break; case 3: conf.audio_sample_rate = 48000; break; case 4: conf.audio_sample_rate = 96000; break; default: conf.audio_sample_rate = 48000; break; } if (nst_playing()) { nst_pause(); nst_play(); } } static void cb_dials() { dial_vall->value(conf.audio_volume); dial_vsq1->value(conf.audio_vol_sq1); dial_vsq2->value(conf.audio_vol_sq2); dial_vtri->value(conf.audio_vol_tri); dial_vnoise->value(conf.audio_vol_noise); dial_vdpcm->value(conf.audio_vol_dpcm); dial_vfds->value(conf.audio_vol_fds); dial_vmmc5->value(conf.audio_vol_mmc5); dial_vvrc6->value(conf.audio_vol_vrc6); dial_vvrc7->value(conf.audio_vol_vrc7); dial_vn163->value(conf.audio_vol_n163); dial_vs5b->value(conf.audio_vol_s5b); } static void cb_volume(Fl_Widget *w, long adj) { Fl_Dial *dial = (Fl_Dial*)w; switch (adj) { case 0: conf.audio_volume = (int)dial->value(); conf.audio_vol_sq1 = conf.audio_vol_sq2 = conf.audio_vol_tri = conf.audio_vol_noise = conf.audio_vol_dpcm = conf.audio_vol_fds = conf.audio_vol_mmc5 = conf.audio_vol_vrc6 = conf.audio_vol_vrc7 = conf.audio_vol_n163 = conf.audio_vol_s5b = conf.audio_volume; break; case 1: conf.audio_vol_sq1 = (int)dial->value(); break; case 2: conf.audio_vol_sq2 = (int)dial->value(); break; case 3: conf.audio_vol_tri = (int)dial->value(); break; case 4: conf.audio_vol_noise = (int)dial->value(); break; case 5: conf.audio_vol_dpcm = (int)dial->value(); break; case 6: conf.audio_vol_fds = (int)dial->value(); break; case 7: conf.audio_vol_mmc5 = (int)dial->value(); break; case 8: conf.audio_vol_vrc6 = (int)dial->value(); break; case 9: conf.audio_vol_vrc7 = (int)dial->value(); break; case 10: conf.audio_vol_n163 = (int)dial->value(); break; case 11: conf.audio_vol_s5b = (int)dial->value(); break; } audio_adj_volume(); cb_dials(); } static void cb_stereo(Fl_Widget *w, long) { conf.audio_stereo = ((Fl_Check_Button*)w)->value(); if (nst_playing()) { nst_pause(); nst_play(); } } int NstInputConfWindow::handle(int e) { switch (e) { case FL_KEYUP: fltkui_input_conf_set(Fl::event_key(), player, btn); this->hide(); this->set_non_modal(); break; } return Fl_Double_Window::handle(e); } static void cb_icfg(Fl_Widget *w, long btn) { icfg->set_modal(); icfg->btn = btn; icfg->text->label(icfg_labels[btn]); icfg->show(); if (icfg->device == 1) { nstsdl_input_conf_button(icfg->player, btn); icfg->hide(); icfg->set_non_modal(); } } static void cb_player(Fl_Widget *w, long) { icfg->player = ((Fl_Choice*)w)->value(); } static void cb_idevice(Fl_Widget *w, long) { icfg->device = ((Fl_Choice*)w)->value(); } static void cb_turbopulse(Fl_Widget *w, long) { conf.timing_turbopulse = ((Fl_Valuator*)w)->value(); } static void cb_default_system(Fl_Widget *w, long) { conf.misc_default_system = ((Fl_Choice*)w)->value(); } static void cb_power_state(Fl_Widget *w, long) { conf.misc_power_state = ((Fl_Choice*)w)->value(); } static void cb_ffspeed(Fl_Widget *w, long) { conf.timing_ffspeed = ((Fl_Valuator*)w)->value(); } static void cb_soft_patching(Fl_Widget *w, long) { conf.misc_soft_patching = ((Fl_Check_Button*)w)->value(); } static void cb_genie_distortion(Fl_Widget *w, long) { conf.misc_genie_distortion = ((Fl_Check_Button*)w)->value(); } static void cb_disable_cursor(Fl_Widget *w, long) { conf.misc_disable_cursor = ((Fl_Check_Button*)w)->value(); } static void cb_disable_cursor_special(Fl_Widget *w, long) { conf.misc_disable_cursor_special = ((Fl_Check_Button*)w)->value(); } static void cb_ok(Fl_Widget *w, long) { w->parent()->hide(); } void NstConfWindow::populate() { Fl_Tabs *tabs = new Fl_Tabs(10, 5, 380, 360); Fl_Group *vtab = new Fl_Group(10, 30, 380, 360, "&Video"); Fl_Choice *ch_filter = new Fl_Choice(20, 55, 160, 25, "Filter"); ch_filter->align(FL_ALIGN_TOP_LEFT); ch_filter->add("None"); ch_filter->add("NTSC"); ch_filter->add("xBR"); ch_filter->add("HqX"); ch_filter->add("2XSaI"); ch_filter->add("ScaleX"); ch_filter->value(conf.video_filter); ch_filter->callback(cb_filter); Fl_Choice *ch_scale = new Fl_Choice(200, 55, 160, 25, "Scale Factor"); ch_scale->align(FL_ALIGN_TOP_LEFT); ch_scale->add("1x"); ch_scale->add("2x"); ch_scale->add("3x"); ch_scale->add("4x"); ch_scale->add("5x"); ch_scale->add("6x"); ch_scale->add("7x"); ch_scale->add("8x"); ch_scale->value(conf.video_scale_factor - 1); ch_scale->callback(cb_scale); Fl_Choice *ch_ntscmode = new Fl_Choice(20, 105, 160, 25, "NTSC Mode"); ch_ntscmode->align(FL_ALIGN_TOP_LEFT); ch_ntscmode->add("Composite"); ch_ntscmode->add("S-Video"); ch_ntscmode->add("RGB"); ch_ntscmode->add("Monochrome"); ch_ntscmode->add("Custom"); ch_ntscmode->value(conf.video_ntsc_mode); ch_ntscmode->callback(cb_ntscmode); Fl_Choice *ch_xbrrounding = new Fl_Choice(200, 105, 160, 25, "xBR Corner Rounding"); ch_xbrrounding->align(FL_ALIGN_TOP_LEFT); ch_xbrrounding->add("None"); ch_xbrrounding->add("Some"); ch_xbrrounding->add("All"); ch_xbrrounding->value(conf.video_xbr_corner_rounding); ch_xbrrounding->callback(cb_xbrrounding); Fl_Choice *ch_palettemode = new Fl_Choice(20, 155, 160, 25, "Palette Mode"); ch_palettemode->align(FL_ALIGN_TOP_LEFT); ch_palettemode->add("YUV"); ch_palettemode->add("RGB"); ch_palettemode->add("Custom"); ch_palettemode->value(conf.video_palette_mode); ch_palettemode->callback(cb_palettemode); Fl_Choice *ch_decoder = new Fl_Choice(200, 155, 160, 25, "YUV Decoder"); ch_decoder->align(FL_ALIGN_TOP_LEFT); ch_decoder->add("Consumer"); ch_decoder->add("Canonical"); ch_decoder->add("Alternative"); ch_decoder->value(conf.video_decoder); ch_decoder->callback(cb_decoder); Fl_Hor_Value_Slider *sld_brightness = new Fl_Hor_Value_Slider(20, 210, 160, 25, "Brightness"); sld_brightness->align(FL_ALIGN_TOP_LEFT); sld_brightness->bounds(-100, 100); sld_brightness->box(FL_FLAT_BOX); sld_brightness->callback(cb_brightness); sld_brightness->step(1); sld_brightness->selection_color(NstGreen); sld_brightness->type(FL_HOR_NICE_SLIDER); sld_brightness->value(conf.video_brightness); Fl_Hor_Value_Slider *sld_saturation = new Fl_Hor_Value_Slider(20, 250, 160, 25, "Saturation"); sld_saturation->align(FL_ALIGN_TOP_LEFT); sld_saturation->bounds(-100, 100); sld_saturation->box(FL_FLAT_BOX); sld_saturation->callback(cb_saturation); sld_saturation->step(1); sld_saturation->selection_color(NstGreen); sld_saturation->type(FL_HOR_NICE_SLIDER); sld_saturation->value(conf.video_saturation); Fl_Hor_Value_Slider *sld_contrast = new Fl_Hor_Value_Slider(20, 290, 160, 25, "Contrast"); sld_contrast->align(FL_ALIGN_TOP_LEFT); sld_contrast->bounds(-100, 100); sld_contrast->box(FL_FLAT_BOX); sld_contrast->callback(cb_contrast); sld_contrast->step(1); sld_contrast->selection_color(NstGreen); sld_contrast->type(FL_HOR_NICE_SLIDER); sld_contrast->value(conf.video_contrast); Fl_Hor_Value_Slider *sld_hue = new Fl_Hor_Value_Slider(20, 330, 160, 25, "Hue"); sld_hue->align(FL_ALIGN_TOP_LEFT); sld_hue->bounds(-45, 45); sld_hue->box(FL_FLAT_BOX); sld_hue->callback(cb_hue); sld_hue->step(1); sld_hue->selection_color(NstGreen); sld_hue->type(FL_HOR_NICE_SLIDER); sld_hue->value(conf.video_hue); Fl_Check_Button *chk_xbrpixblend = new Fl_Check_Button(200, 210, 160, 25, "xBR Pixel Blending"); chk_xbrpixblend->value(conf.video_xbr_pixel_blending); chk_xbrpixblend->callback(cb_xbrpixblend); Fl_Check_Button *chk_linearfilter = new Fl_Check_Button(200, 235, 160, 25, "Linear Filter"); chk_linearfilter->value(conf.video_linear_filter); chk_linearfilter->callback(cb_linearfilter); Fl_Check_Button *chk_tvaspect = new Fl_Check_Button(200, 260, 160, 25, "TV Aspect Ratio"); chk_tvaspect->value(conf.video_tv_aspect); chk_tvaspect->callback(cb_tvaspect); Fl_Check_Button *chk_unmask_overscan = new Fl_Check_Button(200, 285, 160, 25, "Unmask Overscan"); chk_unmask_overscan->value(conf.video_unmask_overscan); chk_unmask_overscan->callback(cb_unmask_overscan); Fl_Check_Button *chk_unlimited_sprites = new Fl_Check_Button(200, 310, 160, 25, "Unlimited Sprites"); chk_unlimited_sprites->value(conf.video_unlimited_sprites); chk_unlimited_sprites->callback(cb_unlimited_sprites); vtab->end(); Fl_Group *atab = new Fl_Group(10, 30, 380, 360, "&Audio"); Fl_Choice *ch_samplerate = new Fl_Choice(20, 55, 160, 25, "Sample Rate"); ch_samplerate->align(FL_ALIGN_TOP_LEFT); ch_samplerate->add("11025Hz"); ch_samplerate->add("22050Hz"); ch_samplerate->add("44100Hz"); ch_samplerate->add("48000Hz"); ch_samplerate->add("96000Hz"); switch (conf.audio_sample_rate) { case 11025: ch_samplerate->value(0); break; case 22050: ch_samplerate->value(1); break; case 44100: ch_samplerate->value(2); break; case 48000: ch_samplerate->value(3); break; case 96000: ch_samplerate->value(4); break; default: ch_samplerate->value(3); break; } ch_samplerate->callback(cb_samplerate); Fl_Check_Button *chk_stereo = new Fl_Check_Button(200, 55, 160, 25, "Stereo"); chk_stereo->value(conf.audio_stereo); chk_stereo->callback(cb_stereo); dial_vall = new Fl_Dial(20, 100, 100, 100, "All"); dial_vall->bounds(0, 100); dial_vall->step(1); dial_vall->color(NstPurple); dial_vall->selection_color(NstGreen); dial_vall->callback(cb_volume, 0); dial_vall->value(conf.audio_volume); dial_vsq1 = new Fl_Dial(130, 115, 40, 40, "SQ1"); dial_vsq1->bounds(0, 100); dial_vsq1->step(1); dial_vsq1->color(NstGreen); dial_vsq1->selection_color(NstPurple); dial_vsq1->callback(cb_volume, 1); dial_vsq1->value(conf.audio_vol_sq1); dial_vsq2 = new Fl_Dial(180, 115, 40, 40, "SQ2"); dial_vsq2->bounds(0, 100); dial_vsq2->step(1); dial_vsq2->color(NstGreen); dial_vsq2->selection_color(NstPurple); dial_vsq2->callback(cb_volume, 2); dial_vsq2->value(conf.audio_vol_sq2); dial_vtri = new Fl_Dial(230, 115, 40, 40, "TRI"); dial_vtri->bounds(0, 100); dial_vtri->step(1); dial_vtri->color(NstGreen); dial_vtri->selection_color(NstPurple); dial_vtri->callback(cb_volume, 3); dial_vtri->value(conf.audio_vol_tri); dial_vnoise = new Fl_Dial(280, 115, 40, 40, "NOISE"); dial_vnoise->bounds(0, 100); dial_vnoise->step(1); dial_vnoise->color(NstGreen); dial_vnoise->selection_color(NstPurple); dial_vnoise->callback(cb_volume, 4); dial_vnoise->value(conf.audio_vol_noise); dial_vdpcm = new Fl_Dial(330, 115, 40, 40, "DPCM"); dial_vdpcm->bounds(0, 100); dial_vdpcm->step(1); dial_vdpcm->color(NstGreen); dial_vdpcm->selection_color(NstPurple); dial_vdpcm->callback(cb_volume, 5); dial_vdpcm->value(conf.audio_vol_dpcm); dial_vfds = new Fl_Dial(80, 225, 40, 40, "FDS"); dial_vfds->bounds(0, 100); dial_vfds->step(1); dial_vfds->color(NstGreen); dial_vfds->selection_color(NstPurple); dial_vfds->callback(cb_volume, 6); dial_vfds->value(conf.audio_vol_fds); dial_vmmc5 = new Fl_Dial(130, 225, 40, 40, "MMC5"); dial_vmmc5->bounds(0, 100); dial_vmmc5->step(1); dial_vmmc5->color(NstGreen); dial_vmmc5->selection_color(NstPurple); dial_vmmc5->callback(cb_volume, 7); dial_vmmc5->value(conf.audio_vol_mmc5); dial_vvrc6 = new Fl_Dial(180, 225, 40, 40, "VRC6"); dial_vvrc6->bounds(0, 100); dial_vvrc6->step(1); dial_vvrc6->color(NstGreen); dial_vvrc6->selection_color(NstPurple); dial_vvrc6->callback(cb_volume, 8); dial_vvrc6->value(conf.audio_vol_vrc6); dial_vvrc7 = new Fl_Dial(230, 225, 40, 40, "VRC7"); dial_vvrc7->bounds(0, 100); dial_vvrc7->step(1); dial_vvrc7->color(NstGreen); dial_vvrc7->selection_color(NstPurple); dial_vvrc7->callback(cb_volume, 9); dial_vvrc7->value(conf.audio_vol_vrc7); dial_vn163 = new Fl_Dial(280, 225, 40, 40, "N163"); dial_vn163->bounds(0, 100); dial_vn163->step(1); dial_vn163->color(NstGreen); dial_vn163->selection_color(NstPurple); dial_vn163->callback(cb_volume, 10); dial_vn163->value(conf.audio_vol_n163); dial_vs5b = new Fl_Dial(330, 225, 40, 40, "S5B"); dial_vs5b->bounds(0, 100); dial_vs5b->step(1); dial_vs5b->color(NstGreen); dial_vs5b->selection_color(NstPurple); dial_vs5b->callback(cb_volume, 11); dial_vs5b->value(conf.audio_vol_s5b); atab->end(); Fl_Group *itab = new Fl_Group(10, 30, 380, 360, "&Input"); Fl_Button *btn_icfg_u = new Fl_Button(70, 55, 30, 24, "U"); btn_icfg_u->callback(cb_icfg, 0); btn_icfg_u->color(NstBlueGrey); btn_icfg_u->labelcolor(NstLightGrey); Fl_Button *btn_icfg_d = new Fl_Button(70, 115, 30, 24, "D"); btn_icfg_d->callback(cb_icfg, 1); btn_icfg_d->color(NstBlueGrey); btn_icfg_d->labelcolor(NstLightGrey); Fl_Button *btn_icfg_l = new Fl_Button(30, 85, 30, 24, "L"); btn_icfg_l->callback(cb_icfg, 2); btn_icfg_l->color(NstBlueGrey); btn_icfg_l->labelcolor(NstLightGrey); Fl_Button *btn_icfg_r = new Fl_Button(110, 85, 30, 24, "R"); btn_icfg_r->callback(cb_icfg, 3); btn_icfg_r->color(NstBlueGrey); btn_icfg_r->labelcolor(NstLightGrey); Fl_Button *btn_icfg_slct = new Fl_Button(150, 85, 60, 24, "Select"); btn_icfg_slct->callback(cb_icfg, 4); btn_icfg_slct->color(NstGreen); btn_icfg_slct->labelcolor(NstLightGrey); Fl_Button *btn_icfg_strt = new Fl_Button(220, 85, 60, 24, "Start"); btn_icfg_strt->callback(cb_icfg, 5); btn_icfg_strt->color(NstGreen); btn_icfg_strt->labelcolor(NstLightGrey); Fl_Button *btn_icfg_a = new Fl_Button(330, 100, 30, 24, "A"); btn_icfg_a->callback(cb_icfg, 6); btn_icfg_a->color(NstRed); btn_icfg_a->labelcolor(NstLightGrey); Fl_Button *btn_icfg_b = new Fl_Button(290, 100, 30, 24, "B"); btn_icfg_b->callback(cb_icfg, 7); btn_icfg_b->color(NstRed); btn_icfg_b->labelcolor(NstLightGrey); Fl_Button *btn_icfg_ta = new Fl_Button(330, 65, 30, 24, "TA"); btn_icfg_ta->callback(cb_icfg, 8); btn_icfg_ta->color(NstRed); btn_icfg_ta->labelcolor(NstLightGrey); Fl_Button *btn_icfg_tb = new Fl_Button(290, 65, 30, 24, "TB"); btn_icfg_tb->callback(cb_icfg, 9); btn_icfg_tb->color(NstRed); btn_icfg_tb->labelcolor(NstLightGrey); icfg = new NstInputConfWindow(110, 55, 170, 24, "Input Config"); icfg->color(NstPurple); icfg->hide(); icfg->text = new Fl_Box(0, 0, 0, 24); icfg->text->align(FL_ALIGN_RIGHT); icfg->text->labelcolor(NstLightGrey); icfg->player = icfg->btn = icfg->device = 0; icfg->end(); Fl_Choice *ch_player = new Fl_Choice(20, 180, 160, 25, "Player"); ch_player->align(FL_ALIGN_TOP_LEFT); ch_player->add("Player 1"); ch_player->add("Player 2"); ch_player->value(0); ch_player->callback(cb_player); Fl_Choice *ch_idevice = new Fl_Choice(20, 230, 160, 25, "Input Device"); ch_idevice->align(FL_ALIGN_TOP_LEFT); ch_idevice->add("Keyboard"); ch_idevice->add("Joystick"); ch_idevice->value(0); ch_idevice->callback(cb_idevice); Fl_Hor_Value_Slider *sld_turbopulse = new Fl_Hor_Value_Slider(200, 180, 160, 25, "Turbo Pulse"); sld_turbopulse->align(FL_ALIGN_TOP_LEFT); sld_turbopulse->bounds(2, 9); sld_turbopulse->box(FL_FLAT_BOX); sld_turbopulse->callback(cb_turbopulse); sld_turbopulse->step(1); sld_turbopulse->selection_color(NstGreen); sld_turbopulse->type(FL_HOR_NICE_SLIDER); sld_turbopulse->value(conf.timing_turbopulse); itab->end(); Fl_Group *mtab = new Fl_Group(10, 30, 380, 360, "&Misc"); Fl_Choice *ch_default_system = new Fl_Choice(20, 55, 160, 25, "Default System"); ch_default_system->align(FL_ALIGN_TOP_LEFT); ch_default_system->add("Auto"); ch_default_system->add("NTSC"); ch_default_system->add("PAL"); ch_default_system->add("Famicom"); ch_default_system->add("Dendy"); ch_default_system->value(conf.misc_default_system); ch_default_system->callback(cb_default_system); Fl_Choice *ch_power_state = new Fl_Choice(20, 105, 160, 25, "RAM Power-on State"); ch_power_state->align(FL_ALIGN_TOP_LEFT); ch_power_state->add("0x00"); ch_power_state->add("0xFF"); ch_power_state->add("Random"); ch_power_state->value(conf.misc_power_state); ch_power_state->callback(cb_power_state); Fl_Hor_Value_Slider *sld_ffspeed = new Fl_Hor_Value_Slider(20, 160, 160, 25, "Fast-Forward Speed"); sld_ffspeed->align(FL_ALIGN_TOP_LEFT); sld_ffspeed->bounds(1, 8); sld_ffspeed->box(FL_FLAT_BOX); sld_ffspeed->callback(cb_ffspeed); sld_ffspeed->step(1); sld_ffspeed->selection_color(NstGreen); sld_ffspeed->type(FL_HOR_NICE_SLIDER); sld_ffspeed->value(conf.timing_ffspeed); Fl_Check_Button *chk_soft_patching = new Fl_Check_Button(200, 55, 185, 25, "Auto Soft Patching"); chk_soft_patching->value(conf.misc_soft_patching); chk_soft_patching->callback(cb_soft_patching); Fl_Check_Button *chk_genie_distortion = new Fl_Check_Button(200, 80, 185, 25, "Genie Sound Distortion"); chk_genie_distortion->value(conf.misc_genie_distortion); chk_genie_distortion->callback(cb_genie_distortion); Fl_Check_Button *chk_disable_cursor = new Fl_Check_Button(200, 105, 185, 25, "Disable Cursor"); chk_disable_cursor->value(conf.misc_disable_cursor); chk_disable_cursor->callback(cb_disable_cursor); Fl_Check_Button *chk_disable_cursor_special = new Fl_Check_Button(200, 130, 185, 25, "Disable Special Cursor"); chk_disable_cursor_special->value(conf.misc_disable_cursor_special); chk_disable_cursor_special->callback(cb_disable_cursor_special); mtab->end(); tabs->end(); Fl_Button *btn_ok = new Fl_Button(350, 370, 40, 24, "&OK"); btn_ok->callback(cb_ok, 0); this->end(); } nestopia-1.51.1/source/fltkui/fltkui_config.h000066400000000000000000000011331411157722000212110ustar00rootroot00000000000000#ifndef _FLTKUI_CONFIG_H_ #define _FLTKUI_CONFIG_H_ class NstConfWindow : public Fl_Double_Window { private: bool icfg_running; public: NstConfWindow(int w, int h, const char* t) : Fl_Double_Window(w, h, t) { } virtual ~NstConfWindow() { } void populate(); }; class NstInputConfWindow : public Fl_Double_Window { private: int handle(int e); public: NstInputConfWindow(int x, int y, int w, int h, const char* t) : Fl_Double_Window(x, y, w, h, t) { box(FL_DOWN_BOX); } virtual ~NstInputConfWindow() { } Fl_Box *text; int btn; int player; int device; // Keyboard or Joystick }; #endif nestopia-1.51.1/source/fltkui/font.h000066400000000000000000000307741411157722000173510ustar00rootroot00000000000000const char *nesfont[] = { " .. . . . . . ", // 0 " ..+ .+ .+ . . . . . + . . +", " ..+ .+ .+ ...... . +. + . .+ . + ", " ..+ ++ ++ .++.++ +. + . .+. ..... ..... . + ", " ..+ .+ .+ . +. +.+ + +.+++ +++++ . + ", " ++ ...... . +. . . .+. .+ .. .. . + ", " .. .++.++ . + . + +.+ + + ..+ ..+ . + ", " ++ + + + + + .++ ++ + ", " ..... .. ..... ..... ... ....... ..... ....... ..... ..... .... ", // 8 "..+++.. ...+ ..+++.. ..+++.. ....+ ..++++++..+++.. ..+++..+..+++.. ..+++.. .. .. .. .. ..++.. ", "..+ ..+ ..+ ..+ ..+ ++ ..+ ..+..+ ...... ..+ ++ ++ ..++..+ ..+..+ ..+ ..+ ..+ ..++ ..... .. ++ ..+ ", "..+ ..+ ..+ ++ ..++ ....++..++..+ ..+++.. ...... ..++ .....++ ......+ ++ ++ .++ +++++ .+ ..++ ", "..+ ..+ ..+ .. ++ ++.. ..+ ..+ ++ ..+..+++.. ..+ ..+++.. +++..+ .+ .+ ..++ ", "..+ ..+ ..+ ..++ .. ..+....... .. ..+..+ ..+ ..++ ..+ ..+.. ..+ .. ..+ .. ..... ..+ ++ ", " .....++ .... ....... .....++ +++..++ .....++ .....++ ..+ .....++ .....++ ..+ ..+ .. +++++ ..++ .. ", " +++++ ++++ +++++++ +++++ ++ +++++ +++++ ++ +++++ +++++ ++ .++ ++ ++ ++ ", " ... ...... .... ..... ....... ....... ..... .. .. .... ..... .. .. .. . . . .. ..... ", // 16 " ..+.. ..+++.. ..++.. ..++.. ..++++++..++++++..+++.. ..+ ..+ ..++ +..++..+ ..++..+ .. ..+.. ..+..+++.. ", " .++ .+ ..+ ..+..++ ++..+ .. ..+ ..+ ..+ ++..+ ..+ ..+ ..+ ..+..++ ..+ ... ...+... ..+..+ ..+", " ..+ .. ......++..+ ..+ ..+...... ...... ..+.... .......+ ..+ ..+ ....++ ..+ .......+.... ..+..+ ..+", " .......+..+++.. ..+ ..+ ..+..+++++ ..+++++ ..+ +..+..+++..+ ..+ ..+ ..+.. ..+ ..+.+..+..+....+..+ ..+", " ..+++..+..+ ..+ .. .. ..+ ..++..+ ..+ ..+ ..+..+ ..+ ..+ .. ..+ ..+ .. ..+ ..+ +..+..+ ...+..+ ..+", " ..+ ..+......++ ....++.....++ ....... ..+ .....++..+ ..+ .... ....++ ..+ .. ....... ..+ ..+..+ ..+ .....++", " ++ ++ ++++++ ++++ +++++ +++++++ ++ +++++ ++ ++ ++++ ++++ ++ ++ +++++++ ++ ++ ++ ++ +++++ ", "...... ..... ...... ..... ...... .. .. .. .. .. .. .. .. .. .. ...... ", // 24 "..+++.. ..+++.. ..+++.. ..+++.. +..+++ ..+ ..+..+ ..+..+ ..+..+ ..+..+ ..+ +++..+ .. .. ", "..+ ..+..+ ..+..+ ..+..+ ++ ..+ ..+ ..+..+ ..+..+. ..+ .. ..++..+ ..+ ..++ ..++ .. ", "..+ ..+..+ ..+..+ ...+ ..... ..+ ..+ ..+..+ ..+..+.+..+ ...++ ....++ ..++ .++ .+ ", "......++..+.. .+.....+++ +++.. ..+ ..+ ..+ .. ..++.......+ ..+.. ..++ ..++ .+ .+ ", "..+++++ ..+ .. +..+... .. ..+ ..+ ..+ ..+ ..+..+ ...+...+..++ .. ..+ ..++ .. ..+ ", "..+ ... .. ..+ ... .....++ ..+ .....++ ...++ .++ .++..+ ..+ ..+ ...... .. ..++ ....... ", " ++ +++ ++ ++ +++ +++++ ++ +++++ +++ + + ++ ++ ++ ++++++ ++ ++ +++++++", " .. .. .. ... .. .. ... ", // 32 " ..+ ..+ ..+ ..+++ ..+ .. .. ..+ ..+ ", " .++ .... ..... ..... .....+ .... ..+ ..... ..+ ++ ++ ..+ .. ..+ ... .. ..... .... ", " + ..++.. ..++.. ..+++++ ..++..+ ..++.. ...... ..++..+ ..... .. .. ..+..++ ..+ ..+. .. ..++.. ..++.. ", " ..+ ..+ ..+ ..+ ..+ ..+ ..+ ......+ +..+++ ..+ ..+ ..++.. ..+ ..+ ....++ ..+ ..+.+..+..+ ..+ ..+ ..+ ", " ..+ ..+ ..+ ..+ ..+ ..+ ..+ ..+++++ ..+ .....+ ..+ ..+ ..+ ..+ ..+.. ..+ ..+.+..+..+ ..+ ..+ ..+ ", " ... .. .....++ ..... .....+ ..... ..+ ++..+ ..+ ..+ ..+ .. ..+ ..+ .. ..+ ..+.+..+..+ ..+ ....++ ", " +++ ++ +++++ +++++ +++++ +++++ ++ ....++ ++ ++ ++ ....++ ++ ++ ++ ++ + ++ ++ ++ ++++ ", " .. ", // 40 " ..+ .. .. ", "..... ..... .. ... .... ...... .. .. .. .. .. .. .. .. .. .. ...... ..++ .. ", "..++.. ..++..+ ... +++ ..++++ +..+++ ..+ ..+ ..+ ..+ ..+. ..+ .. ..++..+ ..+ ++..++ .++ .+ .. . ", "..+ ..+ ..+ ..+ ..++ .... ..+ ..+ ..+ ..+ ..+ ..+.+..+ ...++ ....++ ..++ .+ .+ . +.. + ", ".....++ .....+ ..+ ++.. ..+ ..+ ..+ ....++ ..+.+..+ ..+.. ..++ ..++ .. ..+ + ++ ", "..++++ ++..+ ..+ .....++ ... ....++ ..++ .. ..++..++ .. ..++ ...... .. ..++ ", "..+ ... ++ +++++ +++ ++++ ++ ++ ++ ++ ++..++ ++++++ ++ ++ "}; const char *nesfont2[] = { " .. .. .. .. .. .. ... .. .. .. .. ", // 0 " .... .. .. .. .. ..... .. .. .. .. .. .. .. .. .. .. .. ", " .... .. .. ....... .. .. .. ... .. .. .. .... .. .. ", " .... .. .. .... .. ... .. .. .. .............. ...... .. ", " .. ....... .. .. .. ... .. .. .... .. .. ", " .. .. .. ..... .. .. .. .. .. .. .. .. .. .. .. .. ", " .. .. .. .. .. ... .. .. .. .. .. . ", " .. .. ", " ... .. ..... ...... ... ...... .... ....... ..... ..... .. .. .... ", // 8 " . .. ... .. .. .. .... .. .. .. .. .. .. .. .. .. .. .. .. .. .. ", ".. .. .. ... .. .. .. ...... .. .. .. .. .. .. .. .. .. ...... .. .. ", ".. .. .. .... .... .. .. .. ...... .. ..... ...... .. .. .. ", ".. .. .. .... .. ....... .. .. .. .. .. .. .. .. .. .. ", " .. . .. ... .. .. .. .. .. .. .. .. .. .. .. .. .. .. ...... .. ", " ... ...... ....... ..... .. ..... ..... .. ..... .... .. .. .. .. .. ", " .. ", " ..... ... ...... .... ..... ....... ....... ..... .. .. ...... .... .. .. .. .. .. .. .. ..... ", // 16 ".. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ... ... ... .. .. .. ", ".. .... .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ....... .... .. .. .. ", ".. .... .. .. ...... .. .. .. ...... ...... .. ... ....... .. .. .... .. ....... ....... .. .. ", ".. .... ....... .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..... .. .. . .. .. .... .. .. ", ".. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ... .. .. .. .. ... .. .. ", " .... .. .. ...... .... ..... ....... .. ..... .. .. ...... ..... .. ... ...... .. .. .. .. ..... ", " ", "...... ..... ...... .... ...... .. .. .. .. .. .. .. .. .. .. ....... .... .. .... . ", // 24 ".. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ... ... .. .. ... .. .. .. ... ", ".. .. .. .. .. .. .. .. .. .. .. .. .. . .. ..... .. .. ... .. .. .. .. .. ", ".. .. .. .. .. ... ..... .. .. .. ... ... ....... ... .... ... .. .. .. .. .. ", "...... .. .... ..... .. .. .. .. ..... ....... ..... .. ... .. .. .. ", ".. .. .. .. ... .. .. .. .. .. ... ... ... ... ... .. ... .. .. .. ", ".. .... . .. ... ..... .. ..... . .. .. .. .. .. ....... .... . .... ", " ........", " .. .. .. ... .. .. .. ", // 32 " .. .. .. .. .. .. .. .. .. ", " .. .... ..... ..... ..... .... .. ..... .. .. . .. ... .. ..... .... ", " .. .. .. .. .. .. .. .. .. ...... .. .. ..... .. .. .. . .. .. . .. .. .. .. .. ", " .. .. .. .. .. .. .. ...... .. .. .. .. .. .. .. .. . .. .. . .. .. .. .. .. ", " .. .. .. .. .. .. .. .. .. ..... .. .. .. .. ..... .. .. . .. .. .. .. .. ", " ... .. ..... ..... ..... ..... .. .. .. .. .. .. .. .. .. .. .. . .. .. .. .... ", " .... .... ", " .. ... .. ... ... .. ", // 40 " .. .. .. .. .. ... . ", " ..... ..... .. ... .... ...... .. .. .. .. .. .. .. .. .. .. ...... .. .. .. ... ", " .. .. .. .. ... . .. .. .. .. .. .. . .. .. .. .. .. .. ... ... .. .. ", " .. .. .. .. .. .... .. .. .. .. .. .. . .. ... . .. .. .. .. .. .. .. ", " ..... ..... .. .. .. .. .. . . .. . .. .. .. .. .. .. .. .. .. .. ", " .. .. .. ..... ... .... .. .. .. .. .. .. ...... ... .. ... ....... ", " .. .. .. "}; nestopia-1.51.1/source/fltkui/homebrew.cpp000066400000000000000000000023201411157722000205300ustar00rootroot00000000000000/* * Nestopia UE * * Copyright (C) 2018-2018 Phil Smith * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "config.h" #include "homebrew.h" extern Emulator emulator; void nst_homebrew_init() { Homebrew homebrew(emulator); homebrew.ClearPorts(); if (conf.misc_homebrew_exit != -1) { homebrew.SetExitPort(conf.misc_homebrew_exit); } if (conf.misc_homebrew_stdout != -1) { homebrew.SetStdOutPort(conf.misc_homebrew_stdout); } if (conf.misc_homebrew_stderr != -1) { homebrew.SetStdErrPort(conf.misc_homebrew_stderr); } } nestopia-1.51.1/source/fltkui/homebrew.h000066400000000000000000000017161411157722000202050ustar00rootroot00000000000000/* * Nestopia UE * * Copyright (C) 2018-2018 Phil Smith * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef _HOMEBREW_H_ #define _HOMEBREW_H_ #include "core/api/NstApiEmulator.hpp" #include "core/api/NstApiHomebrew.hpp" using namespace Nes::Api; void nst_homebrew_init(); #endif nestopia-1.51.1/source/fltkui/ini.cpp000066400000000000000000000143221411157722000175040ustar00rootroot00000000000000/* inih -- simple .INI file parser Copyright (c) 2009, Brush Technology All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Brush Technology nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "ini.h" #if !INI_USE_STACK #include #endif #define MAX_SECTION 50 #define MAX_NAME 50 /* Strip whitespace chars off end of given string, in place. Return s. */ static char* rstrip(char* s) { char* p = s + strlen(s); while (p > s && isspace((unsigned char)(*--p))) *p = '\0'; return s; } /* Return pointer to first non-whitespace char in given string. */ static char* lskip(const char* s) { while (*s && isspace((unsigned char)(*s))) s++; return (char*)s; } /* Return pointer to first char c or ';' comment in given string, or pointer to null at end of string if neither found. ';' must be prefixed by a whitespace character to register as a comment. */ static char* find_char_or_comment(const char* s, char c) { int was_whitespace = 0; while (*s && *s != c && !(was_whitespace && *s == ';')) { was_whitespace = isspace((unsigned char)(*s)); s++; } return (char*)s; } /* Version of strncpy that ensures dest (size bytes) is null-terminated. */ static char* strncpy0(char* dest, const char* src, size_t size) { strncpy(dest, src, size); dest[size - 1] = '\0'; return dest; } /* See documentation in header file. */ int ini_parse_file(FILE* file, int (*handler)(void*, const char*, const char*, const char*), void* user) { /* Uses a fair bit of stack (use heap instead if you need to) */ #if INI_USE_STACK char line[INI_MAX_LINE]; #else char* line; #endif char section[MAX_SECTION] = ""; char prev_name[MAX_NAME] = ""; char* start; char* end; char* name; char* value; int lineno = 0; int error = 0; #if !INI_USE_STACK line = (char*)malloc(INI_MAX_LINE); if (!line) { return -2; } #endif /* Scan through file line by line */ while (fgets(line, INI_MAX_LINE, file) != NULL) { lineno++; start = line; #if INI_ALLOW_BOM if (lineno == 1 && (unsigned char)start[0] == 0xEF && (unsigned char)start[1] == 0xBB && (unsigned char)start[2] == 0xBF) { start += 3; } #endif start = lskip(rstrip(start)); if (*start == ';' || *start == '#') { /* Per Python ConfigParser, allow '#' comments at start of line */ } #if INI_ALLOW_MULTILINE else if (*prev_name && *start && start > line) { /* Non-black line with leading whitespace, treat as continuation of previous name's value (as per Python ConfigParser). */ if (!handler(user, section, prev_name, start) && !error) error = lineno; } #endif else if (*start == '[') { /* A "[section]" line */ end = find_char_or_comment(start + 1, ']'); if (*end == ']') { *end = '\0'; strncpy0(section, start + 1, sizeof(section)); *prev_name = '\0'; } else if (!error) { /* No ']' found on section line */ error = lineno; } } else if (*start && *start != ';') { /* Not a comment, must be a name[=:]value pair */ end = find_char_or_comment(start, '='); if (*end != '=') { end = find_char_or_comment(start, ':'); } if (*end == '=' || *end == ':') { *end = '\0'; name = rstrip(start); value = lskip(end + 1); end = find_char_or_comment(value, '\0'); if (*end == ';') *end = '\0'; rstrip(value); /* Valid name[=:]value pair found, call handler */ strncpy0(prev_name, name, sizeof(prev_name)); if (!handler(user, section, name, value) && !error) error = lineno; } else if (!error) { /* No '=' or ':' found on name[=:]value line */ error = lineno; } } } #if !INI_USE_STACK free(line); #endif return error; } /* See documentation in header file. */ int ini_parse(const char* filename, int (*handler)(void*, const char*, const char*, const char*), void* user) { FILE* file; int error; file = fopen(filename, "r"); if (!file) return -1; error = ini_parse_file(file, handler, user); fclose(file); return error; } nestopia-1.51.1/source/fltkui/ini.h000066400000000000000000000074111411157722000171520ustar00rootroot00000000000000/* inih -- simple .INI file parser Copyright (c) 2009, Brush Technology All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Brush Technology nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __INI_H__ #define __INI_H__ /* Make this header file easier to include in C++ code */ #ifdef __cplusplus extern "C" { #endif #include /* Parse given INI-style file. May have [section]s, name=value pairs (whitespace stripped), and comments starting with ';' (semicolon). Section is "" if name=value pair parsed before any section heading. name:value pairs are also supported as a concession to Python's ConfigParser. For each name=value pair parsed, call handler function with given user pointer as well as section, name, and value (data only valid for duration of handler call). Handler should return nonzero on success, zero on error. Returns 0 on success, line number of first error on parse error (doesn't stop on first error), -1 on file open error, or -2 on memory allocation error (only when INI_USE_STACK is zero). */ int ini_parse(const char* filename, int (*handler)(void* user, const char* section, const char* name, const char* value), void* user); /* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't close the file when it's finished -- the caller must do that. */ int ini_parse_file(FILE* file, int (*handler)(void* user, const char* section, const char* name, const char* value), void* user); /* Nonzero to allow multi-line value parsing, in the style of Python's ConfigParser. If allowed, ini_parse() will call the handler with the same name for each subsequent line parsed. */ #ifndef INI_ALLOW_MULTILINE #define INI_ALLOW_MULTILINE 1 #endif /* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of the file. See http://code.google.com/p/inih/issues/detail?id=21 */ #ifndef INI_ALLOW_BOM #define INI_ALLOW_BOM 1 #endif /* Nonzero to use stack, zero to use heap (malloc/free). */ #ifndef INI_USE_STACK #define INI_USE_STACK 1 #endif /* Maximum line length for any line in INI file. */ #ifndef INI_MAX_LINE #define INI_MAX_LINE 200 #endif #ifndef MATCH #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0 #endif #ifdef __cplusplus } #endif #endif /* __INI_H__ */ nestopia-1.51.1/source/fltkui/input.cpp000066400000000000000000001075051411157722000200720ustar00rootroot00000000000000/* * Nestopia UE * * Copyright (C) 2012-2016 R. Danbrook * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include #include #include #include #include #include "nstcommon.h" #include "config.h" #include "input.h" #include "video.h" #include "ini.h" #include "fltkui.h" static SDL_Joystick *joystick; gamepad_t player[NUMGAMEPADS]; inputsettings_t inputconf; static char inputconfpath[256]; static turbo_t turbostate; static turbo_t turbotoggle; extern Emulator emulator; extern nstpaths_t nstpaths; extern Emulator emulator; extern Input::Controllers *cNstPads; extern int drawtext; static unsigned char nescodes[TOTALBUTTONS] = { Input::Controllers::Pad::UP, Input::Controllers::Pad::DOWN, Input::Controllers::Pad::LEFT, Input::Controllers::Pad::RIGHT, Input::Controllers::Pad::SELECT, Input::Controllers::Pad::START, Input::Controllers::Pad::A, Input::Controllers::Pad::B, Input::Controllers::Pad::A, Input::Controllers::Pad::B, Input::Controllers::Pad::UP, Input::Controllers::Pad::DOWN, Input::Controllers::Pad::LEFT, Input::Controllers::Pad::RIGHT, Input::Controllers::Pad::SELECT, Input::Controllers::Pad::START, Input::Controllers::Pad::A, Input::Controllers::Pad::B, Input::Controllers::Pad::A, Input::Controllers::Pad::B }; void nst_input_init() { // Initialize input char controller[32]; for (int i = 0; i < NUMGAMEPADS; i++) { Input(emulator).AutoSelectController(i); switch(Input(emulator).GetConnectedController(i)) { case Input::UNCONNECTED: snprintf(controller, sizeof(controller), "%s", "Unconnected"); break; case Input::PAD1: case Input::PAD2: case Input::PAD3: case Input::PAD4: snprintf(controller, sizeof(controller), "%s", "Standard Pad"); break; case Input::ZAPPER: snprintf(controller, sizeof(controller), "%s", "Zapper"); break; case Input::PADDLE: snprintf(controller, sizeof(controller), "%s", "Arkanoid Paddle"); break; case Input::POWERPAD: snprintf(controller, sizeof(controller), "%s", "Power Pad"); break; case Input::POWERGLOVE: snprintf(controller, sizeof(controller), "%s", "Power Glove"); break; case Input::MOUSE: snprintf(controller, sizeof(controller), "%s", "Mouse"); break; case Input::ROB: snprintf(controller, sizeof(controller), "%s", "R.O.B."); break; case Input::FAMILYTRAINER: snprintf(controller, sizeof(controller), "%s", "Family Trainer"); break; case Input::FAMILYKEYBOARD: snprintf(controller, sizeof(controller), "%s", "Family Keyboard"); break; case Input::SUBORKEYBOARD: snprintf(controller, sizeof(controller), "%s", "Subor Keyboard"); break; case Input::DOREMIKKOKEYBOARD: snprintf(controller, sizeof(controller), "%s", "Doremikko Keyboard"); break; case Input::HORITRACK: snprintf(controller, sizeof(controller), "%s", "Hori Track"); break; case Input::PACHINKO: snprintf(controller, sizeof(controller), "%s", "Pachinko"); break; case Input::OEKAKIDSTABLET: snprintf(controller, sizeof(controller), "%s", "Oeka Kids Tablet"); break; case Input::KONAMIHYPERSHOT: snprintf(controller, sizeof(controller), "%s", "Konami Hypershot"); break; case Input::BANDAIHYPERSHOT: snprintf(controller, sizeof(controller), "%s", "Bandai Hypershot"); break; case Input::CRAZYCLIMBER: snprintf(controller, sizeof(controller), "%s", "Crazy Climber"); break; case Input::MAHJONG: snprintf(controller, sizeof(controller), "%s", "Mahjong"); break; case Input::EXCITINGBOXING: snprintf(controller, sizeof(controller), "%s", "Exciting Boxing"); break; case Input::TOPRIDER: snprintf(controller, sizeof(controller), "%s", "Top Rider"); break; case Input::POKKUNMOGURAA: snprintf(controller, sizeof(controller), "%s", "Pokkun Moguraa"); break; case Input::PARTYTAP: snprintf(controller, sizeof(controller), "%s", "PartyTap"); break; case Input::TURBOFILE: snprintf(controller, sizeof(controller), "%s", "Turbo File"); break; case Input::BARCODEWORLD: snprintf(controller, sizeof(controller), "%s", "Barcode World"); break; default: snprintf(controller, sizeof(controller), "%s", "Unknown"); break; } fprintf(stderr, "Port %d: %s\n", i + 1, controller); } } void nst_input_inject(Input::Controllers *controllers, nesinput_t input) { // Insert the input signal into the NES if (controllers == NULL) { return; } if (input.pressed) { controllers->pad[input.player].buttons |= input.nescode; if (input.turboa) { input.player == 0 ? turbostate.p1a = true : turbostate.p2a = true; } if (input.turbob) { input.player == 0 ? turbostate.p1b = true : turbostate.p2b = true; } } else { controllers->pad[input.player].buttons &= ~input.nescode; if (input.turboa) { input.player == 0 ? turbostate.p1a = false : turbostate.p2a = false; } if (input.turbob) { input.player == 0 ? turbostate.p1b = false : turbostate.p2b = false; } } } void nst_input_inject_mouse(Input::Controllers *controllers, int b, int s, int x, int y) { // Insert input signal for Zappers if(controllers == NULL) { return; } double xaspect; double yaspect; if (s) { // Get X coords if (conf.video_filter == 1) { // NTSC xaspect = (double)(Video::Output::WIDTH) / (double)(Video::Output::NTSC_WIDTH / 2); } else if (conf.video_tv_aspect) { xaspect = (double)(Video::Output::WIDTH) / (double)(TV_WIDTH); } else { xaspect = 1.0; } dimensions_t rendersize = nst_video_get_dimensions_render(); dimensions_t screensize = nst_video_get_dimensions_screen(); // Calculate fullscreen X coords if (conf.video_fullscreen) { if (conf.video_stretch_aspect) { xaspect = (double)(conf.video_scale_factor * Video::Output::WIDTH) / (double)(screensize.w); } else { // Remove the same amount of pixels as the black area to the left of the screen x -= screensize.w / 2.0f - rendersize.w / 2.0f; xaspect = (double)(conf.video_scale_factor * Video::Output::WIDTH) / (double)(rendersize.w); } } controllers->zapper.x = (int)(x * xaspect) / conf.video_scale_factor; // Get Y coords if (conf.video_unmask_overscan) { controllers->zapper.y = y / conf.video_scale_factor; } else { controllers->zapper.y = (y + OVERSCAN_TOP * conf.video_scale_factor) / conf.video_scale_factor; } // Calculate fullscreen Y coords if (conf.video_fullscreen) { yaspect = (double)(conf.video_scale_factor * Video::Output::HEIGHT) / (double)(screensize.h); controllers->zapper.y = (y * yaspect) / conf.video_scale_factor; } // Offscreen if (b != 1) { controllers->zapper.x = ~1U; } controllers->zapper.fire = true; } else { controllers->zapper.fire = false; } } void nst_input_turbo_init() { // Initialize the turbo button states turbostate.p1a = turbotoggle.p1a = 0; turbostate.p1b = turbotoggle.p1b = 0; turbostate.p2a = turbotoggle.p2a = 0; turbostate.p2b = turbotoggle.p2b = 0; } void nst_input_turbo_pulse(Input::Controllers *controllers) { // Pulse the turbo buttons if they're pressed if (turbostate.p1a) { turbotoggle.p1a++; if (turbotoggle.p1a >= conf.timing_turbopulse) { turbotoggle.p1a = 0; controllers->pad[0].buttons &= ~Input::Controllers::Pad::A; } else { controllers->pad[0].buttons |= Input::Controllers::Pad::A; } } if (turbostate.p1b) { turbotoggle.p1b++; if (turbotoggle.p1b >= conf.timing_turbopulse) { turbotoggle.p1b = 0; controllers->pad[0].buttons &= ~Input::Controllers::Pad::B; } else { controllers->pad[0].buttons |= Input::Controllers::Pad::B; } } if (turbostate.p2a) { turbotoggle.p2a++; if (turbotoggle.p2a >= conf.timing_turbopulse) { turbotoggle.p2a = 0; controllers->pad[1].buttons &= ~Input::Controllers::Pad::A; } else { controllers->pad[1].buttons |= Input::Controllers::Pad::A; } } if (turbostate.p2b) { turbotoggle.p2b++; if (turbotoggle.p2b >= conf.timing_turbopulse) { turbotoggle.p2b = 0; controllers->pad[1].buttons &= ~Input::Controllers::Pad::B; } else { controllers->pad[1].buttons |= Input::Controllers::Pad::B; } } } int nst_input_zapper_present() { // Check if a Zapper is presently connected if (Input(emulator).GetConnectedController(0) == Input::ZAPPER || Input(emulator).GetConnectedController(1) == Input::ZAPPER) { return 1; } else { return 0; } } void nstsdl_input_joysticks_detect() { // Initialize any joysticks fprintf(stderr, "%i joystick(s) found:\n", SDL_NumJoysticks()); for (int i = 0; i < SDL_NumJoysticks(); i++) { joystick = SDL_JoystickOpen(i); printf("%s\n", SDL_JoystickName(joystick)); } SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); nst_input_turbo_init(); } void nstsdl_input_joysticks_close() { // Deinitialize any joysticks SDL_JoystickClose(joystick); } int nstsdl_input_checksign(int axisvalue) { if (axisvalue <= 0) { return 0; } else { return 1; } } void nstsdl_input_match_joystick(Input::Controllers *controllers, SDL_Event event) { // Match NES buttons to joystick input int j; nesinput_t input, reverseinput; input.nescode = 0x00; input.player = 0; input.pressed = 0; input.turboa = 0; input.turbob = 0; // This is for releasing opposing directions reverseinput.nescode = 0x00; reverseinput.player = 0; reverseinput.pressed = 0; SDL_Event buttons[TOTALBUTTONS] = { player[0].ju, player[0].jd, player[0].jl, player[0].jr, player[0].jselect, player[0].jstart, player[0].ja, player[0].jb, player[0].jta, player[0].jtb, player[1].ju, player[1].jd, player[1].jl, player[1].jr, player[1].jselect, player[1].jstart, player[1].ja, player[1].jb, player[1].jta, player[1].jtb }; SDL_Event rw[2] = { player[0].rwstart, player[0].rwstop }; SDL_Event reset[2] = { player[0].softreset, player[0].hardreset }; switch(event.type) { // Handle button input case SDL_JOYBUTTONUP: case SDL_JOYBUTTONDOWN: // Gamepad input for (j = 0; j < TOTALBUTTONS; j++) { if (buttons[j].jbutton.button == event.jbutton.button && buttons[j].jbutton.which == event.jbutton.which) { input.nescode = nescodes[j]; if (j >= NUMBUTTONS) { input.player = 1; } // This is really dirty if (j == 8 || j == 18) { input.turboa = 1; } if (j == 9 || j == 19) { input.turbob = 1; } } } input.pressed = event.jbutton.state; // Rewind if (event.jbutton.button == rw[0].jbutton.button && event.jbutton.which == rw[0].jbutton.which) { nst_set_rewind(0); } if (event.jbutton.button == rw[1].jbutton.button && event.jbutton.which == rw[1].jbutton.which) { nst_set_rewind(1); } if (event.jbutton.button == reset[0].jbutton.button && event.jbutton.which == reset[0].jbutton.which) { nst_reset(0); } if (event.jbutton.button == reset[1].jbutton.button && event.jbutton.which == reset[1].jbutton.which) { nst_reset(1); } break; // Handling hat input can be a lot of fun if you like pain case SDL_JOYHATMOTION: unsigned char hu, hd, hl, hr; hu = hd = hl = hr = 0; // Start a loop to check if input matches for (j = 0; j < TOTALBUTTONS; j++) { // Read value of each hat direction on current hat if (buttons[j].type == event.type && buttons[j].jhat.which == event.jhat.which && buttons[j].jhat.hat == event.jhat.hat) { if (j >= NUMBUTTONS) { input.player = reverseinput.player = 1; } // Find the values at each hat position on the current hat if (buttons[j].jhat.value == SDL_HAT_UP) { hu = nescodes[j]; } else if (buttons[j].jhat.value == SDL_HAT_DOWN) { hd = nescodes[j]; } else if (buttons[j].jhat.value == SDL_HAT_LEFT) { hl = nescodes[j]; } else if (buttons[j].jhat.value == SDL_HAT_RIGHT) { hr = nescodes[j]; } input.pressed = 1; // Make sure opposing hat positions are turned off switch(event.jhat.value) { case SDL_HAT_UP: input.nescode |= hu; reverseinput.nescode |= hd |= hl |= hr; break; case SDL_HAT_LEFTUP: input.nescode |= hu |= hl; reverseinput.nescode |= hd |= hr; break; case SDL_HAT_RIGHTUP: input.nescode |= hu |= hr; reverseinput.nescode |= hd |= hl; break; case SDL_HAT_DOWN: input.nescode |= hd; reverseinput.nescode |= hu |= hl |= hr; break; case SDL_HAT_LEFTDOWN: input.nescode |= hd |= hl; reverseinput.nescode |= hu |= hr; break; case SDL_HAT_RIGHTDOWN: input.nescode |= hd |= hr; reverseinput.nescode |= hu |= hl; break; case SDL_HAT_LEFT: input.nescode |= hl; reverseinput.nescode |= hr |= hu |= hd; break; case SDL_HAT_RIGHT: input.nescode |= hr; reverseinput.nescode |= hl |= hu |= hd; break; default: input.nescode |= hu |= hd |= hl |= hr; break; } } } break; // Handle axis input case SDL_JOYAXISMOTION: for (j = 0; j < TOTALBUTTONS; j++) { int nvalue = nstsdl_input_checksign(event.jaxis.value); if (buttons[j].jaxis.axis == event.jaxis.axis && buttons[j].jaxis.which == event.jaxis.which && buttons[j].jaxis.type == event.jaxis.type && buttons[j].jaxis.value == nvalue) { if (j >= NUMBUTTONS) { input.player = reverseinput.player = 1; } input.nescode = nescodes[j]; } if (buttons[j].jaxis.axis == event.jaxis.axis && buttons[j].jaxis.which == event.jaxis.which && buttons[j].jaxis.type == event.jaxis.type && buttons[j].jaxis.value == !nvalue) { reverseinput.nescode = nescodes[j]; } if (abs(event.jaxis.value) > DEADZONE) { input.pressed = 1; } } break; default: break; } nst_input_inject(controllers, reverseinput); nst_input_inject(controllers, input); } void nstsdl_input_conf_defaults() { // Set default input config inputconf.qsave1 = FL_F + 5; inputconf.qsave2 = FL_F + 6; inputconf.qload1 = FL_F + 7; inputconf.qload2 = FL_F + 8; inputconf.screenshot = FL_F + 9; inputconf.fdsflip = FL_F + 3; inputconf.fdsswitch = FL_F + 4; inputconf.insertcoin1 = FL_F + 1; inputconf.insertcoin2 = FL_F + 2; inputconf.reset = FL_F + 12; inputconf.ffspeed = '`'; inputconf.rwstart = FL_BackSpace; inputconf.rwstop = '\\'; inputconf.fullscreen = 'f'; player[0].u = FL_Up; player[0].d = FL_Down; player[0].l = FL_Left; player[0].r = FL_Right; player[0].select = FL_Shift_R; player[0].start = FL_Enter; player[0].a = 'z'; player[0].b = 'a'; player[0].ta = 'x'; player[0].tb = 's'; player[0].ju = nstsdl_input_translate_string("j0h01"); player[0].jd = nstsdl_input_translate_string("j0h04"); player[0].jl = nstsdl_input_translate_string("j0h08"); player[0].jr = nstsdl_input_translate_string("j0h02"); player[0].jselect = nstsdl_input_translate_string("j0b8"); player[0].jstart = nstsdl_input_translate_string("j0b9"); player[0].ja = nstsdl_input_translate_string("j0b1"); player[0].jb = nstsdl_input_translate_string("j0b0"); player[0].jta = nstsdl_input_translate_string("j0b2"); player[0].jtb = nstsdl_input_translate_string("j0b3"); player[0].rwstart = nstsdl_input_translate_string("j0b4"); player[0].rwstop = nstsdl_input_translate_string("j0b5"); player[0].softreset = nstsdl_input_translate_string("j0b99"); player[0].hardreset = nstsdl_input_translate_string("j0b99"); player[1].u = 'i'; player[1].d = 'j'; player[1].l = 'k'; player[1].r = 'l'; player[1].select = FL_Shift_L; player[1].start = FL_Control_L; player[1].a = 'm'; player[1].b = 'n'; player[1].ta = 'b'; player[1].tb = 'v'; player[1].ju = nstsdl_input_translate_string("j1h01"); player[1].jd = nstsdl_input_translate_string("j1h04"); player[1].jl = nstsdl_input_translate_string("j1h08"); player[1].jr = nstsdl_input_translate_string("j1h02"); player[1].jselect = nstsdl_input_translate_string("j1b8"); player[1].jstart = nstsdl_input_translate_string("j1b9"); player[1].ja = nstsdl_input_translate_string("j1b1"); player[1].jb = nstsdl_input_translate_string("j1b0"); player[1].jta = nstsdl_input_translate_string("j1b2"); player[1].jtb = nstsdl_input_translate_string("j1b3"); } void fltkui_input_conf_set(int kval, int pnum, int bnum) { // Set an input item to what was requested by configuration process switch (bnum) { case 0: player[pnum].u = kval; break; case 1: player[pnum].d = kval; break; case 2: player[pnum].l = kval; break; case 3: player[pnum].r = kval; break; case 4: player[pnum].select = kval; break; case 5: player[pnum].start = kval; break; case 6: player[pnum].a = kval; break; case 7: player[pnum].b = kval; break; case 8: player[pnum].ta = kval; break; case 9: player[pnum].tb = kval; break; default: break; } } void nstsdl_input_conf_set(SDL_Event event, int pnum, int bnum) { // Set an input item to what was requested by configuration process switch (bnum) { case 0: player[pnum].ju = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; case 1: player[pnum].jd = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; case 2: player[pnum].jl = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; case 3: player[pnum].jr = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; case 4: player[pnum].jselect = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; case 5: player[pnum].jstart = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; case 6: player[pnum].ja = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; case 7: player[pnum].jb = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; case 8: player[pnum].jta = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; case 9: player[pnum].jtb = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; default: break; } } static int nstsdl_input_config_match(void* user, const char* section, const char* name, const char* value) { // Match values from input config file and populate live config inputsettings_t* pconfig = (inputsettings_t*)user; // User Interface if (MATCH("ui", "qsave1")) { pconfig->qsave1 = atoi(value); } else if (MATCH("ui", "qsave2")) { pconfig->qsave2 = atoi(value); } else if (MATCH("ui", "qload1")) { pconfig->qload1 = atoi(value); } else if (MATCH("ui", "qload2")) { pconfig->qload2 = atoi(value); } else if (MATCH("ui", "screenshot")) { pconfig->screenshot = atoi(value); } else if (MATCH("ui", "fdsflip")) { pconfig->fdsflip = atoi(value); } else if (MATCH("ui", "fdsswitch")) { pconfig->fdsswitch = atoi(value); } else if (MATCH("ui", "insertcoin1")) { pconfig->insertcoin1 = atoi(value); } else if (MATCH("ui", "insertcoin2")) { pconfig->insertcoin2 = atoi(value); } else if (MATCH("ui", "reset")) { pconfig->reset = atoi(value); } else if (MATCH("ui", "ffspeed")) { pconfig->ffspeed = atoi(value); } else if (MATCH("ui", "rwstart")) { pconfig->rwstart = atoi(value); } else if (MATCH("ui", "rwstop")) { pconfig->rwstop = atoi(value); } else if (MATCH("ui", "fullscreen")) { pconfig->fullscreen = atoi(value); } // Player 1 else if (MATCH("gamepad1", "kb_u")) { pconfig->kb_p1u = atoi(value); } else if (MATCH("gamepad1", "kb_d")) { pconfig->kb_p1d = atoi(value); } else if (MATCH("gamepad1", "kb_l")) { pconfig->kb_p1l = atoi(value); } else if (MATCH("gamepad1", "kb_r")) { pconfig->kb_p1r = atoi(value); } else if (MATCH("gamepad1", "kb_select")) { pconfig->kb_p1select = atoi(value); } else if (MATCH("gamepad1", "kb_start")) { pconfig->kb_p1start = atoi(value); } else if (MATCH("gamepad1", "kb_a")) { pconfig->kb_p1a = atoi(value); } else if (MATCH("gamepad1", "kb_b")) { pconfig->kb_p1b = atoi(value); } else if (MATCH("gamepad1", "kb_ta")) { pconfig->kb_p1ta = atoi(value); } else if (MATCH("gamepad1", "kb_tb")) { pconfig->kb_p1tb = atoi(value); } else if (MATCH("gamepad1", "js_u")) { pconfig->js_p1u = strdup(value); } else if (MATCH("gamepad1", "js_d")) { pconfig->js_p1d = strdup(value); } else if (MATCH("gamepad1", "js_l")) { pconfig->js_p1l = strdup(value); } else if (MATCH("gamepad1", "js_r")) { pconfig->js_p1r = strdup(value); } else if (MATCH("gamepad1", "js_select")) { pconfig->js_p1select = strdup(value); } else if (MATCH("gamepad1", "js_start")) { pconfig->js_p1start = strdup(value); } else if (MATCH("gamepad1", "js_a")) { pconfig->js_p1a = strdup(value); } else if (MATCH("gamepad1", "js_b")) { pconfig->js_p1b = strdup(value); } else if (MATCH("gamepad1", "js_ta")) { pconfig->js_p1ta = strdup(value); } else if (MATCH("gamepad1", "js_tb")) { pconfig->js_p1tb = strdup(value); } else if (MATCH("gamepad1", "js_rwstart")) { pconfig->js_rwstart = strdup(value); } else if (MATCH("gamepad1", "js_rwstop")) { pconfig->js_rwstop = strdup(value); } else if (MATCH("gamepad1", "js_softreset")) { pconfig->js_softreset = strdup(value); } else if (MATCH("gamepad1", "js_hardreset")) { pconfig->js_hardreset = strdup(value); } // Player 2 else if (MATCH("gamepad2", "kb_u")) { pconfig->kb_p2u = atoi(value); } else if (MATCH("gamepad2", "kb_d")) { pconfig->kb_p2d = atoi(value); } else if (MATCH("gamepad2", "kb_l")) { pconfig->kb_p2l = atoi(value); } else if (MATCH("gamepad2", "kb_r")) { pconfig->kb_p2r = atoi(value); } else if (MATCH("gamepad2", "kb_select")) { pconfig->kb_p2select = atoi(value); } else if (MATCH("gamepad2", "kb_start")) { pconfig->kb_p2start = atoi(value); } else if (MATCH("gamepad2", "kb_a")) { pconfig->kb_p2a = atoi(value); } else if (MATCH("gamepad2", "kb_b")) { pconfig->kb_p2b = atoi(value); } else if (MATCH("gamepad2", "kb_ta")) { pconfig->kb_p2ta = atoi(value); } else if (MATCH("gamepad2", "kb_tb")) { pconfig->kb_p2tb = atoi(value); } else if (MATCH("gamepad2", "js_u")) { pconfig->js_p2u = strdup(value); } else if (MATCH("gamepad2", "js_d")) { pconfig->js_p2d = strdup(value); } else if (MATCH("gamepad2", "js_l")) { pconfig->js_p2l = strdup(value); } else if (MATCH("gamepad2", "js_r")) { pconfig->js_p2r = strdup(value); } else if (MATCH("gamepad2", "js_select")) { pconfig->js_p2select = strdup(value); } else if (MATCH("gamepad2", "js_start")) { pconfig->js_p2start = strdup(value); } else if (MATCH("gamepad2", "js_a")) { pconfig->js_p2a = strdup(value); } else if (MATCH("gamepad2", "js_b")) { pconfig->js_p2b = strdup(value); } else if (MATCH("gamepad2", "js_ta")) { pconfig->js_p2ta = strdup(value); } else if (MATCH("gamepad2", "js_tb")) { pconfig->js_p2tb = strdup(value); } else { return 0; } return 1; } void nstsdl_input_conf_read() { // Read the input config file snprintf(inputconfpath, sizeof(inputconfpath), "%sinput.conf", nstpaths.nstconfdir); if (ini_parse(inputconfpath, nstsdl_input_config_match, &inputconf) < 0) { fprintf(stderr, "Failed to load input config file %s: Using defaults.\n", inputconfpath); } else { // Map the input settings from the config file player[0].u = inputconf.kb_p1u; player[0].d = inputconf.kb_p1d; player[0].l = inputconf.kb_p1l; player[0].r = inputconf.kb_p1r; player[0].select = inputconf.kb_p1select; player[0].start = inputconf.kb_p1start; player[0].a = inputconf.kb_p1a; player[0].b = inputconf.kb_p1b; player[0].ta = inputconf.kb_p1ta; player[0].tb = inputconf.kb_p1tb; player[0].ju = nstsdl_input_translate_string(inputconf.js_p1u); player[0].jd = nstsdl_input_translate_string(inputconf.js_p1d); player[0].jl = nstsdl_input_translate_string(inputconf.js_p1l); player[0].jr = nstsdl_input_translate_string(inputconf.js_p1r); player[0].jselect = nstsdl_input_translate_string(inputconf.js_p1select); player[0].jstart = nstsdl_input_translate_string(inputconf.js_p1start); player[0].ja = nstsdl_input_translate_string(inputconf.js_p1a); player[0].jb = nstsdl_input_translate_string(inputconf.js_p1b); player[0].jta = nstsdl_input_translate_string(inputconf.js_p1ta); player[0].jtb = nstsdl_input_translate_string(inputconf.js_p1tb); if (inputconf.js_rwstart) { player[0].rwstart = nstsdl_input_translate_string(inputconf.js_rwstart); } if (inputconf.js_rwstop) { player[0].rwstop = nstsdl_input_translate_string(inputconf.js_rwstop); } if (inputconf.js_softreset) { player[0].softreset = nstsdl_input_translate_string(inputconf.js_softreset); } if (inputconf.js_hardreset) { player[0].hardreset = nstsdl_input_translate_string(inputconf.js_hardreset); } // Player 2 player[1].u = inputconf.kb_p2u; player[1].d = inputconf.kb_p2d; player[1].l = inputconf.kb_p2l; player[1].r = inputconf.kb_p2r; player[1].select = inputconf.kb_p2select; player[1].start = inputconf.kb_p2start; player[1].a = inputconf.kb_p2a; player[1].b = inputconf.kb_p2b; player[1].ta = inputconf.kb_p2ta; player[1].tb = inputconf.kb_p2tb; player[1].ju = nstsdl_input_translate_string(inputconf.js_p2u); player[1].jd = nstsdl_input_translate_string(inputconf.js_p2d); player[1].jl = nstsdl_input_translate_string(inputconf.js_p2l); player[1].jr = nstsdl_input_translate_string(inputconf.js_p2r); player[1].jselect = nstsdl_input_translate_string(inputconf.js_p2select); player[1].jstart = nstsdl_input_translate_string(inputconf.js_p2start); player[1].ja = nstsdl_input_translate_string(inputconf.js_p2a); player[1].jb = nstsdl_input_translate_string(inputconf.js_p2b); player[1].jta = nstsdl_input_translate_string(inputconf.js_p2ta); player[1].jtb = nstsdl_input_translate_string(inputconf.js_p2tb); } } void nstsdl_input_conf_write() { // Write out the input configuration file FILE *fp = fopen(inputconfpath, "w"); if (fp != NULL) { fprintf(fp, "; Nestopia UE Input Configuration File\n\n"); fprintf(fp, "; Possible values for joystick input:\n; j[joystick number][a|b|h][button/hat/axis number][1/0 = +/- (axes only)]\n"); fprintf(fp, "; Example: j0b3 = joystick 0, button 3. j1a11 = joystick 1, axis 1 +\n\n"); fprintf(fp, "[ui]\n"); fprintf(fp, "qsave1=%d\n", inputconf.qsave1); fprintf(fp, "qsave2=%d\n", inputconf.qsave2); fprintf(fp, "qload1=%d\n", inputconf.qload1); fprintf(fp, "qload2=%d\n", inputconf.qload2); fprintf(fp, "screenshot=%d\n", inputconf.screenshot); fprintf(fp, "fdsflip=%d\n", inputconf.fdsflip); fprintf(fp, "fdsswitch=%d\n", inputconf.fdsswitch); fprintf(fp, "insertcoin1=%d\n", inputconf.insertcoin1); fprintf(fp, "insertcoin2=%d\n", inputconf.insertcoin2); fprintf(fp, "reset=%d\n", inputconf.reset); fprintf(fp, "ffspeed=%d\n", inputconf.ffspeed); fprintf(fp, "rwstart=%d\n", inputconf.rwstart); fprintf(fp, "rwstop=%d\n", inputconf.rwstop); fprintf(fp, "fullscreen=%d\n", inputconf.fullscreen); fprintf(fp, "\n"); // End of Section fprintf(fp, "[gamepad1]\n"); fprintf(fp, "kb_u=%d\n", player[0].u); fprintf(fp, "kb_d=%d\n", player[0].d); fprintf(fp, "kb_l=%d\n", player[0].l); fprintf(fp, "kb_r=%d\n", player[0].r); fprintf(fp, "kb_select=%d\n", player[0].select); fprintf(fp, "kb_start=%d\n", player[0].start); fprintf(fp, "kb_a=%d\n", player[0].a); fprintf(fp, "kb_b=%d\n", player[0].b); fprintf(fp, "kb_ta=%d\n", player[0].ta); fprintf(fp, "kb_tb=%d\n", player[0].tb); fprintf(fp, "js_u=%s\n", nstsdl_input_translate_event(player[0].ju)); fprintf(fp, "js_d=%s\n", nstsdl_input_translate_event(player[0].jd)); fprintf(fp, "js_l=%s\n", nstsdl_input_translate_event(player[0].jl)); fprintf(fp, "js_r=%s\n", nstsdl_input_translate_event(player[0].jr)); fprintf(fp, "js_select=%s\n", nstsdl_input_translate_event(player[0].jselect)); fprintf(fp, "js_start=%s\n", nstsdl_input_translate_event(player[0].jstart)); fprintf(fp, "js_a=%s\n", nstsdl_input_translate_event(player[0].ja)); fprintf(fp, "js_b=%s\n", nstsdl_input_translate_event(player[0].jb)); fprintf(fp, "js_ta=%s\n", nstsdl_input_translate_event(player[0].jta)); fprintf(fp, "js_tb=%s\n", nstsdl_input_translate_event(player[0].jtb)); fprintf(fp, "js_rwstart=%s\n", nstsdl_input_translate_event(player[0].rwstart)); fprintf(fp, "js_rwstop=%s\n", nstsdl_input_translate_event(player[0].rwstop)); fprintf(fp, "js_softreset=%s\n", nstsdl_input_translate_event(player[0].softreset)); fprintf(fp, "js_hardreset=%s\n", nstsdl_input_translate_event(player[0].hardreset)); fprintf(fp, "\n"); // End of Section fprintf(fp, "[gamepad2]\n"); fprintf(fp, "kb_u=%d\n", player[1].u); fprintf(fp, "kb_d=%d\n", player[1].d); fprintf(fp, "kb_l=%d\n", player[1].l); fprintf(fp, "kb_r=%d\n", player[1].r); fprintf(fp, "kb_select=%d\n", player[1].select); fprintf(fp, "kb_start=%d\n", player[1].start); fprintf(fp, "kb_a=%d\n", player[1].a); fprintf(fp, "kb_b=%d\n", player[1].b); fprintf(fp, "kb_ta=%d\n", player[1].ta); fprintf(fp, "kb_tb=%d\n", player[1].tb); fprintf(fp, "js_u=%s\n", nstsdl_input_translate_event(player[1].ju)); fprintf(fp, "js_d=%s\n", nstsdl_input_translate_event(player[1].jd)); fprintf(fp, "js_l=%s\n", nstsdl_input_translate_event(player[1].jl)); fprintf(fp, "js_r=%s\n", nstsdl_input_translate_event(player[1].jr)); fprintf(fp, "js_select=%s\n", nstsdl_input_translate_event(player[1].jselect)); fprintf(fp, "js_start=%s\n", nstsdl_input_translate_event(player[1].jstart)); fprintf(fp, "js_a=%s\n", nstsdl_input_translate_event(player[1].ja)); fprintf(fp, "js_b=%s\n", nstsdl_input_translate_event(player[1].jb)); fprintf(fp, "js_ta=%s\n", nstsdl_input_translate_event(player[1].jta)); fprintf(fp, "js_tb=%s\n", nstsdl_input_translate_event(player[1].jtb)); fclose(fp); } } void nstsdl_input_process(Input::Controllers *controllers, SDL_Event event) { // Process input events switch(event.type) { case SDL_JOYBUTTONUP: case SDL_JOYBUTTONDOWN: case SDL_JOYAXISMOTION: case SDL_JOYHATMOTION: nstsdl_input_match_joystick(controllers, event); break; default: break; } } char* nstsdl_input_translate_event(SDL_Event event) { // Translate an SDL_Event to an inputcode static char inputcode[6]; switch(event.type) { case SDL_JOYAXISMOTION: sprintf(inputcode, "j%da%d%d", event.jaxis.which, event.jaxis.axis, nstsdl_input_checksign(event.jaxis.value)); break; case SDL_JOYHATMOTION: sprintf(inputcode, "j%dh%d%d", event.jhat.which, event.jhat.hat, event.jhat.value); break; case SDL_JOYBUTTONUP: case SDL_JOYBUTTONDOWN: sprintf(inputcode, "j%db%d", event.jbutton.which, event.jbutton.button); break; } return inputcode; } SDL_Event nstsdl_input_translate_string(const char *string) { // Translate an inputcode to an SDL_Event SDL_Event event; int type, axis, value; int which = 0, whichdigits = 0; for (int i = 1; ; i++) { if (isdigit(string[i])) { whichdigits++; } else { break; } } for (int i = 1; i <= whichdigits; i++) { which += (string[i] - '0') * (pow (10, (whichdigits - i))); } if ((unsigned char)string[whichdigits + 1] == 0x61) { // Axis axis = string[whichdigits + 2] - '0'; value = string[whichdigits + 3] - '0'; event.type = SDL_JOYAXISMOTION; event.jaxis.which = which; event.jaxis.axis = axis; event.jaxis.value = value; } else if ((unsigned char)string[whichdigits + 1] == 0x62) { // Button value = string[whichdigits + 2] - '0'; if (string[whichdigits + 3]) { value = ((string[whichdigits + 2] - '0') * 10) + (string[whichdigits + 3] - '0'); } event.type = SDL_JOYBUTTONDOWN; event.jbutton.which = which; event.jbutton.button = value; } else if ((unsigned char)string[whichdigits + 1] == 0x68) { // Hat axis = string[whichdigits + 2] - '0'; value = string[whichdigits + 3] - '0'; event.type = SDL_JOYHATMOTION; event.jhat.which = which; event.jhat.hat = axis; event.jhat.value = value; } else { fprintf(stderr, "Malformed inputcode: %s\n", string); } return event; } void nstsdl_input_conf_button(int pnum, int bnum) { // Configure Inputs for single Joystick Buttons SDL_Event event, eventbuf; int axis = 0, axisnoise = 0, iterations = 0, confrunning = 1; if (SDL_NumJoysticks() == 0) { return; } while (confrunning) { while (SDL_PollEvent(&event)) { if (event.type == SDL_JOYAXISMOTION) { if (abs(event.jaxis.value) >= DEADZONE) { eventbuf = event; axisnoise = 1; axis = event.jaxis.axis; } else if (abs(event.jaxis.value) < DEADZONE && axisnoise && event.jaxis.axis == axis) { nstsdl_input_conf_set(eventbuf, pnum, bnum); axisnoise = 0; confrunning = 0; } } else if (event.type == SDL_JOYHATMOTION) { if (event.jhat.value != SDL_HAT_CENTERED) { nstsdl_input_conf_set(event, pnum, bnum); confrunning = 0; } } else if (event.type == SDL_JOYBUTTONDOWN) { nstsdl_input_conf_set(event, pnum, bnum); confrunning = 0; } } if (++iterations > 3000) { break; } // Roughly 3 second timeout SDL_Delay(1); } } void fltkui_input_process_key(int e) { nesinput_t input; input.nescode = input.player = input.pressed = input.turboa = input.turbob = 0; if (e == FL_KEYDOWN) { input.pressed = 1; if (Fl::event_key() == '`') nst_timing_set_ffspeed(); else if (Fl::event_key() == inputconf.qsave1) nst_state_quicksave(0); else if (Fl::event_key() == inputconf.qsave2) nst_state_quicksave(1); else if (Fl::event_key() == inputconf.qload1) nst_state_quickload(0); else if (Fl::event_key() == inputconf.qload2) nst_state_quickload(1); else if (Fl::event_key() == inputconf.screenshot) { video_screenshot(NULL); } else if (Fl::event_key() == inputconf.fdsflip) { nst_fds_flip(); } else if (Fl::event_key() == inputconf.fdsswitch) { nst_fds_switch(); } else if (Fl::event_key() == inputconf.insertcoin1) { cNstPads->vsSystem.insertCoin |= Input::Controllers::VsSystem::COIN_1; } else if (Fl::event_key() == inputconf.insertcoin2) { cNstPads->vsSystem.insertCoin |= Input::Controllers::VsSystem::COIN_2; } else if (Fl::event_key() == inputconf.reset) { nst_reset(0); } else if (Fl::event_key() == inputconf.rwstart) { nst_set_rewind(0); } else if (Fl::event_key() == inputconf.rwstop) { nst_set_rewind(1); } else if (Fl::event_key() == ' ') { cNstPads->pad[1].mic = 0x04; } } else { if (Fl::event_key() == inputconf.ffspeed) nst_timing_set_default(); else if (Fl::event_key() == inputconf.fullscreen) fltkui_fullscreen(NULL, NULL); else if (Fl::event_key() == ' ') { cNstPads->pad[1].mic = 0x00; } } for (int i = 0; i < NUMGAMEPADS; i++) { if (Fl::event_key() == player[i].u) { input.player = i; input.nescode = Input::Controllers::Pad::UP; } else if (Fl::event_key() == player[i].d) { input.player = i; input.nescode = Input::Controllers::Pad::DOWN; } else if (Fl::event_key() == player[i].l) { input.player = i; input.nescode = Input::Controllers::Pad::LEFT; } else if (Fl::event_key() == player[i].r) { input.player = i; input.nescode = Input::Controllers::Pad::RIGHT; } else if (Fl::event_key() == player[i].select) { input.player = i; input.nescode = Input::Controllers::Pad::SELECT; } else if (Fl::event_key() == player[i].start) { input.player = i; input.nescode = Input::Controllers::Pad::START; } else if (Fl::event_key() == player[i].a) { input.player = i; input.nescode = Input::Controllers::Pad::A; } else if (Fl::event_key() == player[i].b) { input.player = i; input.nescode = Input::Controllers::Pad::B; } else if (Fl::event_key() == player[i].ta) { input.player = i; input.turboa = 1; input.nescode = Input::Controllers::Pad::A; } else if (Fl::event_key() == player[i].tb) { input.player = i; input.turbob = 1; input.nescode = Input::Controllers::Pad::B; } } nst_input_inject(cNstPads, input); if (nst_nsf() && input.player == 0 && input.pressed == 0) { if (input.nescode & Input::Controllers::Pad::UP) { nst_nsf_play(); } if (input.nescode & Input::Controllers::Pad::DOWN) { nst_nsf_stop(); } if (input.nescode & Input::Controllers::Pad::LEFT) { nst_nsf_prev(); } if (input.nescode & Input::Controllers::Pad::RIGHT) { nst_nsf_next(); } } } nestopia-1.51.1/source/fltkui/input.h000066400000000000000000000055431411157722000175360ustar00rootroot00000000000000#ifndef _INPUT_H_ #define _INPUT_H_ #define NUMGAMEPADS 2 #define NUMBUTTONS 10 #define TOTALBUTTONS (NUMGAMEPADS*NUMBUTTONS) #define DEADZONE (32768/3) #include "core/api/NstApiInput.hpp" typedef struct { int u; int d; int l; int r; int select; int start; int a; int b; int ta; int tb; SDL_Event ju; SDL_Event jd; SDL_Event jl; SDL_Event jr; SDL_Event jselect; SDL_Event jstart; SDL_Event ja; SDL_Event jb; SDL_Event jta; SDL_Event jtb; SDL_Event rwstart; SDL_Event rwstop; SDL_Event softreset; SDL_Event hardreset; } gamepad_t; typedef struct { // User Interface int qsave1; int qsave2; int qload1; int qload2; int screenshot; int fdsflip; int fdsswitch; int insertcoin1; int insertcoin2; int reset; int ffspeed; int rwstart; int rwstop; int fullscreen; // Player 1 int kb_p1u; int kb_p1d; int kb_p1l; int kb_p1r; int kb_p1select; int kb_p1start; int kb_p1a; int kb_p1b; int kb_p1ta; int kb_p1tb; char *js_p1u; char *js_p1d; char *js_p1l; char *js_p1r; char *js_p1select; char *js_p1start; char *js_p1a; char *js_p1b; char *js_p1ta; char *js_p1tb; char *js_rwstart; char *js_rwstop; char *js_softreset; char *js_hardreset; // Player 2 int kb_p2u; int kb_p2d; int kb_p2l; int kb_p2r; int kb_p2select; int kb_p2start; int kb_p2a; int kb_p2b; int kb_p2ta; int kb_p2tb; char *js_p2u; char *js_p2d; char *js_p2l; char *js_p2r; char *js_p2select; char *js_p2start; char *js_p2a; char *js_p2b; char *js_p2ta; char *js_p2tb; } inputsettings_t; using namespace Nes::Api; typedef struct { unsigned char player; unsigned char nescode; unsigned char pressed; unsigned char turboa; unsigned char turbob; } nesinput_t; typedef struct { int p1a; int p1b; int p2a; int p2b; } turbo_t; void nst_input_init(); void nst_input_inject(Input::Controllers *controllers, nesinput_t input); void nst_input_inject_mouse(Input::Controllers *controllers, int b, int s, int x, int y); void nst_input_turbo_init(); void nst_input_turbo_pulse(Input::Controllers *controllers); int nst_input_zapper_present(); int input_configure_item(int pnum, int bnum, int type); void nstsdl_input_conf(int type, int pnum); void nstsdl_input_conf_button(int pnum, int bnum); void nstsdl_input_conf_defaults(); void nstsdl_input_conf_set(SDL_Event event, int pnum, int bnum); void nstsdl_input_conf_read(); void nstsdl_input_conf_write(); void nstsdl_input_joysticks_detect(); void nstsdl_input_joysticks_close(); void nstsdl_input_match_joystick(Input::Controllers *controllers, SDL_Event event); int nstsdl_input_checksign(int axisvalue); void nstsdl_input_process(Input::Controllers *controllers, SDL_Event event); char* nstsdl_input_translate_event(SDL_Event event); SDL_Event nstsdl_input_translate_string(const char *string); void fltkui_input_conf_set(int kval, int pnum, int bnum); void fltkui_input_process_key(int e); #endif nestopia-1.51.1/source/fltkui/nstcommon.cpp000066400000000000000000000644151411157722000207520ustar00rootroot00000000000000/* * Nestopia UE * * Copyright (C) 2007-2008 R. Belmont * Copyright (C) 2012-2021 R. Danbrook * Copyright (C) 2018-2018 Phil Smith * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include #include #include #include #include #include #include #include #include #include #include #include // Nst Common #include "nstcommon.h" #include "config.h" #include "cheats.h" #include "homebrew.h" #include "input.h" #include "audio.h" #include "video.h" #include "samples.h" Emulator emulator; Video::Output *cNstVideo; Sound::Output *cNstSound; Input::Controllers *cNstPads; nstpaths_t nstpaths; static bool ffspeed = false; static bool playing = false; static std::ifstream *nstdb; static std::ifstream *fdsbios; static std::ifstream *moviefile; static std::fstream *movierecfile; void *custompalette = NULL; static size_t custpalsize; int loaded = 0; bool (*nst_archive_select)(const char*, char*, size_t); static bool NST_CALLBACK nst_cb_videolock(void* userData, Video::Output& video) { video.pitch = video_lock_screen(video.pixels); return true; } static void NST_CALLBACK nst_cb_videounlock(void* userData, Video::Output& video) { video_unlock_screen(video.pixels); } static bool NST_CALLBACK nst_cb_soundlock(void* userData, Sound::Output& sound) { audio_queue(); return true; } static void NST_CALLBACK nst_cb_soundunlock(void* userData, Sound::Output& sound) { // Do Nothing } static void NST_CALLBACK nst_cb_event(void *userData, User::Event event, const void* data) { // Handle special events switch (event) { case User::EVENT_CPU_JAM: fprintf(stderr, "Cpu: Jammed\n"); break; case User::EVENT_CPU_UNOFFICIAL_OPCODE: fprintf(stderr, "Cpu: Unofficial Opcode %s\n", (const char*)data); break; case User::EVENT_DISPLAY_TIMER: nst_video_print_time((const char*)data + strlen((char*)data) - 5, true); break; default: break; } } static void NST_CALLBACK nst_cb_log(void *userData, const char *string, unsigned long int length) { // Print logging information to stderr fprintf(stderr, "%s", string); } static void NST_CALLBACK nst_cb_file(void *userData, User::File& file) { unsigned char *compbuffer; int compsize, compoffset; char *filename; switch (file.GetAction()) { case User::File::LOAD_ROM: // Nothing here for now break; case User::File::LOAD_SAMPLE: break; case User::File::LOAD_SAMPLE_MOERO_PRO_YAKYUU: nst_sample_load_samples(file, "moepro"); break; case User::File::LOAD_SAMPLE_MOERO_PRO_YAKYUU_88: nst_sample_load_samples(file, "moepro88"); break; case User::File::LOAD_SAMPLE_MOERO_PRO_TENNIS: nst_sample_load_samples(file, "mptennis"); break; case User::File::LOAD_SAMPLE_TERAO_NO_DOSUKOI_OOZUMOU: nst_sample_load_samples(file, "terao"); break; case User::File::LOAD_SAMPLE_AEROBICS_STUDIO: nst_sample_load_samples(file, "ftaerobi"); break; case User::File::LOAD_BATTERY: // load in battery data from a file case User::File::LOAD_EEPROM: // used by some Bandai games, can be treated the same as battery files case User::File::LOAD_TAPE: // for loading Famicom cassette tapes case User::File::LOAD_TURBOFILE: // for loading turbofile data { std::ifstream batteryFile(nstpaths.savename, std::ifstream::in|std::ifstream::binary); if (batteryFile.is_open()) { file.SetContent(batteryFile); } break; } case User::File::SAVE_BATTERY: // save battery data to a file case User::File::SAVE_EEPROM: // can be treated the same as battery files case User::File::SAVE_TAPE: // for saving Famicom cassette tapes case User::File::SAVE_TURBOFILE: // for saving turbofile data { std::ofstream batteryFile(nstpaths.savename, std::ifstream::out|std::ifstream::binary); const void* savedata; unsigned long savedatasize; file.GetContent(savedata, savedatasize); if (batteryFile.is_open()) { batteryFile.write((const char*) savedata, savedatasize); } break; } case User::File::LOAD_FDS: // for loading modified Famicom Disk System files { char fdsname[512]; snprintf(fdsname, sizeof(fdsname), "%s.ups", nstpaths.fdssave); std::ifstream batteryFile( fdsname, std::ifstream::in|std::ifstream::binary ); // no ups, look for ips if (!batteryFile.is_open()) { snprintf(fdsname, sizeof(fdsname), "%s.ips", nstpaths.fdssave); std::ifstream batteryFile( fdsname, std::ifstream::in|std::ifstream::binary ); if (!batteryFile.is_open()) { return; } file.SetPatchContent(batteryFile); return; } file.SetPatchContent(batteryFile); break; } case User::File::SAVE_FDS: // for saving modified Famicom Disk System files { char fdsname[512]; snprintf(fdsname, sizeof(fdsname), "%s.ups", nstpaths.fdssave); std::ofstream fdsFile( fdsname, std::ifstream::out|std::ifstream::binary ); if (fdsFile.is_open()) file.GetPatchContent( User::File::PATCH_UPS, fdsFile ); break; } } } static Machine::FavoredSystem nst_default_system() { switch (conf.misc_default_system) { case 2: return Machine::FAVORED_NES_PAL; break; case 3: return Machine::FAVORED_FAMICOM; break; case 4: return Machine::FAVORED_DENDY; break; default: return Machine::FAVORED_NES_NTSC; break; } } void* nst_ptr_video() { return &cNstVideo; } void* nst_ptr_sound() { return &cNstSound; } void* nst_ptr_input() { return &cNstPads; } bool nst_archive_checkext(const char *filename) { // Check if the file extension is valid int len = strlen(filename); if ((!strcasecmp(&filename[len-4], ".nes")) || (!strcasecmp(&filename[len-4], ".fds")) || (!strcasecmp(&filename[len-4], ".nsf")) || (!strcasecmp(&filename[len-4], ".unf")) || (!strcasecmp(&filename[len-5], ".unif"))|| (!strcasecmp(&filename[len-4], ".xml"))) { return true; } return false; } bool nst_archive_select_file(const char *filename, char *reqfile, size_t reqsize) { // Select a filename to pull out of the archive struct archive *a; struct archive_entry *entry; int r, numarchives = 0; a = archive_read_new(); archive_read_support_filter_all(a); archive_read_support_format_all(a); r = archive_read_open_filename(a, filename, 10240); // Test if it's actually an archive if (r != ARCHIVE_OK) { r = archive_read_free(a); return false; } // If it is an archive, handle it else { // Find files with valid extensions within the archive while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { const char *currentfile = archive_entry_pathname(entry); if (nst_archive_checkext(currentfile)) { numarchives++; snprintf(reqfile, reqsize, "%s", currentfile); } archive_read_data_skip(a); break; // Load the first one found } // Free the archive r = archive_read_free(a); // If there are no valid files in the archive, return if (numarchives == 0) { return false; } else { return true; } } return false; } bool nst_archive_open(const char *filename, char **rom, int *romsize, const char *reqfile) { // Opens archives struct archive *a; struct archive_entry *entry; int r; int64_t entrysize; a = archive_read_new(); archive_read_support_filter_all(a); archive_read_support_format_all(a); r = archive_read_open_filename(a, filename, 10240); // Test if it's actually an archive if (r != ARCHIVE_OK) { r = archive_read_free(a); return false; } // Scan through the archive for files while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { char *rombuf; const char *currentfile = archive_entry_pathname(entry); if (nst_archive_checkext(currentfile)) { nst_set_paths(currentfile); // If there's a specific file we want, load it if (reqfile != NULL) { if (!strcmp(currentfile, reqfile)) { entrysize = archive_entry_size(entry); rombuf = (char*)malloc(entrysize); archive_read_data(a, rombuf, entrysize); archive_read_data_skip(a); r = archive_read_free(a); *romsize = entrysize; *rom = rombuf; return true; } } // Otherwise just take the first file in the archive else { entrysize = archive_entry_size(entry); rombuf = (char*)malloc(entrysize); archive_read_data(a, rombuf, entrysize); archive_read_data_skip(a); r = archive_read_free(a); *romsize = entrysize; *rom = rombuf; return true; } } } return false; } void nst_db_load() { Nes::Api::Cartridge::Database database(emulator); char dbpath[512]; if (nstdb) { return; } // Try to open the database file snprintf(dbpath, sizeof(dbpath), "%sNstDatabase.xml", nstpaths.nstdir); nstdb = new std::ifstream(dbpath, std::ifstream::in|std::ifstream::binary); if (nstdb->is_open()) { database.Load(*nstdb); database.Enable(true); return; } // If it fails, try looking in the data directory snprintf(dbpath, sizeof(dbpath), "%s/NstDatabase.xml", DATADIR); nstdb = new std::ifstream(dbpath, std::ifstream::in|std::ifstream::binary); if (nstdb->is_open()) { database.Load(*nstdb); database.Enable(true); return; } // If that fails, try looking in the working directory char *pwd = getenv("PWD"); snprintf(dbpath, sizeof(dbpath), "%s/NstDatabase.xml", pwd); nstdb = new std::ifstream(dbpath, std::ifstream::in|std::ifstream::binary); if (nstdb->is_open()) { database.Load(*nstdb); database.Enable(true); return; } else { fprintf(stderr, "NstDatabase.xml not found!\n"); delete nstdb; nstdb = NULL; } } void nst_db_unload() { if (nstdb) { delete nstdb; nstdb = NULL; } } void nst_dipswitch() { // Print DIP switch information and call handler DipSwitches dipswitches(emulator); int numdips = dipswitches.NumDips(); if (numdips > 0) { for (int i = 0; i < numdips; i++) { fprintf(stderr, "%d: %s\n", i, dipswitches.GetDipName(i)); int numvalues = dipswitches.NumValues(i); for (int j = 0; j < numvalues; j++) { fprintf(stderr, " %d: %s\n", j, dipswitches.GetValueName(i, j)); } } char dippath[512]; snprintf(dippath, sizeof(dippath), "%s%s.dip", nstpaths.savedir, nstpaths.gamename); nst_dip_handle(dippath); } } void nst_fds_bios_load() { // Load the Famicom Disk System BIOS Nes::Api::Fds fds(emulator); char biospath[512]; if (fdsbios) { return; } snprintf(biospath, sizeof(biospath), "%sdisksys.rom", nstpaths.nstdir); fdsbios = new std::ifstream(biospath, std::ifstream::in|std::ifstream::binary); if (fdsbios->is_open()) { fds.SetBIOS(fdsbios); } else { fprintf(stderr, "Fds: BIOS not found: %s\n", biospath); delete fdsbios; fdsbios = NULL; } } void nst_fds_bios_unload() { if (fdsbios) { delete fdsbios; fdsbios = NULL; } } void nst_fds_info() { Fds fds(emulator); const char* disk; const char* side; char textbuf[24]; fds.GetCurrentDisk() == 0 ? disk = "1" : disk = "2"; fds.GetCurrentDiskSide() == 0 ? side = "A" : side = "B"; fprintf(stderr, "Fds: Disk %s Side %s\n", disk, side); snprintf(textbuf, sizeof(textbuf), "Disk %s Side %s", disk, side); nst_video_print((const char*)textbuf, 8, 16, 2, true); } void nst_fds_flip() { // Flips the FDS disk Fds fds(emulator); if (fds.CanChangeDiskSide()) { fds.ChangeSide(); nst_fds_info(); } } void nst_fds_switch() { // Switches the FDS disk in multi-disk games Fds fds(emulator); int currentdisk = fds.GetCurrentDisk(); // If it's a multi-disk game, eject and insert the other disk if (fds.GetNumDisks() > 1) { fds.EjectDisk(); fds.InsertDisk(!currentdisk, 0); nst_fds_info(); } } void nst_movie_save(const char *filename) { // Save/Record a movie Movie movie(emulator); movierecfile = new std::fstream(filename, std::ifstream::out|std::ifstream::binary); if (movierecfile->is_open()) { movie.Record((std::iostream&)*movierecfile, Nes::Api::Movie::CLEAN); } else { delete movierecfile; movierecfile = NULL; } } void nst_movie_load(const char *filename) { // Load and play a movie Movie movie(emulator); moviefile = new std::ifstream(filename, std::ifstream::in|std::ifstream::binary); if (moviefile->is_open()) { movie.Play(*moviefile); } else { delete moviefile; moviefile = NULL; } } void nst_movie_stop() { // Stop any movie that is playing or recording Movie movie(emulator); if (movie.IsPlaying() || movie.IsRecording()) { movie.Stop(); movierecfile = NULL; delete movierecfile; moviefile = NULL; delete moviefile; } } bool nst_nsf() { Machine machine(emulator); return machine.Is(Machine::SOUND); } void nst_nsf_play() { Nsf nsf(emulator); nsf.PlaySong(); video_clear_buffer(); video_disp_nsf(); } void nst_nsf_stop() { Nsf nsf(emulator); nsf.StopSong(); } void nst_nsf_prev() { Nsf nsf(emulator); nsf.SelectPrevSong(); video_clear_buffer(); video_disp_nsf(); } void nst_nsf_next() { Nsf nsf(emulator); nsf.SelectNextSong(); video_clear_buffer(); video_disp_nsf(); } bool nst_pal() { Machine machine(emulator); return machine.GetMode() == Machine::PAL; } bool nst_playing() { return playing; } void nst_palette_load(const char *filename) { // Load a custom palette FILE *file; long filesize; // File size in bytes size_t result; char custgamepalpath[512]; snprintf(custgamepalpath, sizeof(custgamepalpath), "%s%s%s", nstpaths.nstdir, nstpaths.gamename, ".pal"); // Try the game-specific palette first file = fopen(custgamepalpath, "rb"); if (!file) { file = fopen(filename, "rb"); } // Then try the global custom palette if (!file) { if (conf.video_palette_mode == 2) { fprintf(stderr, "Custom palette: not found: %s\n", filename); conf.video_palette_mode = 0; } return; } fseek(file, 0, SEEK_END); filesize = ftell(file); fseek(file, 0, SEEK_SET); if (custompalette) { free(custompalette); } custompalette = malloc(filesize * sizeof(uint8_t)); custpalsize = filesize * sizeof(uint8_t); result = fread(custompalette, sizeof(uint8_t), filesize, file); fclose(file); } void nst_palette_save() { // Save a custom palette FILE *file; void *custpalout; file = fopen(nstpaths.palettepath, "wb"); if (!file) { return; } custpalout = malloc(custpalsize); memcpy(custpalout, custompalette, custpalsize); fwrite(custpalout, custpalsize, sizeof(uint8_t), file); fclose(file); free(custpalout); } void nst_palette_unload() { if (custompalette) { free(custompalette); } } bool nst_find_patch(char *patchname, unsigned int patchname_length, const char *filename) { // Check for a patch in the same directory as the game FILE *file; char filedir[512]; // Copy filename (will be used by dirname) // dirname needs a copy because it can modify its argument strncpy(filedir, filename, sizeof(filedir)); filedir[sizeof(filedir) - 1] = '\0'; // Use memmove because dirname can return the same pointer as its argument, // since copying into same string as the argument we don't want any overlap memmove(filedir, dirname(filedir), sizeof(filedir)); filedir[sizeof(filedir) - 1] = '\0'; if (!conf.misc_soft_patching) { return 0; } snprintf(patchname, patchname_length, "%s/%s.ips", filedir, nstpaths.gamename); if ((file = fopen(patchname, "rb")) != NULL) { fclose(file); return 1; } else { snprintf(patchname, patchname_length, "%s/%s.ups", filedir, nstpaths.gamename); if ((file = fopen(patchname, "rb")) != NULL) { fclose(file); return 1; } } return 0; } void nst_set_callbacks() { // Set up the callbacks void *userData = (void*)0xDEADC0DE; Video::Output::lockCallback.Set(nst_cb_videolock, userData); Video::Output::unlockCallback.Set(nst_cb_videounlock, userData); Sound::Output::lockCallback.Set(nst_cb_soundlock, userData); Sound::Output::unlockCallback.Set(nst_cb_soundunlock, userData); User::fileIoCallback.Set(nst_cb_file, userData); User::logCallback.Set(nst_cb_log, userData); User::eventCallback.Set(nst_cb_event, userData); } void nst_set_dirs() { // Set up system directories // create config directory if it doesn't exist if (getenv("XDG_CONFIG_HOME")) { snprintf(nstpaths.nstconfdir, sizeof(nstpaths.nstconfdir), "%s/nestopia/", getenv("XDG_CONFIG_HOME")); } else { snprintf(nstpaths.nstconfdir, sizeof(nstpaths.nstconfdir), "%s/.config/nestopia/", getenv("HOME")); } if (mkdir(nstpaths.nstconfdir, 0755) && errno != EEXIST) { fprintf(stderr, "Failed to create %s: %d\n", nstpaths.nstconfdir, errno); } // create data directory if it doesn't exist if (getenv("XDG_DATA_HOME")) { snprintf(nstpaths.nstdir, sizeof(nstpaths.nstdir), "%s/nestopia/", getenv("XDG_DATA_HOME")); } else { snprintf(nstpaths.nstdir, sizeof(nstpaths.nstdir), "%s/.local/share/nestopia/", getenv("HOME")); } if (mkdir(nstpaths.nstdir, 0755) && errno != EEXIST) { fprintf(stderr, "Failed to create %s: %d\n", nstpaths.nstdir, errno); } // create save and state directories if they don't exist char dirstr[256]; snprintf(dirstr, sizeof(dirstr), "%ssave", nstpaths.nstdir); if (mkdir(dirstr, 0755) && errno != EEXIST) { fprintf(stderr, "Failed to create %s: %d\n", dirstr, errno); } snprintf(dirstr, sizeof(dirstr), "%sstate", nstpaths.nstdir); if (mkdir(dirstr, 0755) && errno != EEXIST) { fprintf(stderr, "Failed to create %s: %d\n", dirstr, errno); } // create cheats directory if it doesn't exist snprintf(dirstr, sizeof(dirstr), "%scheats", nstpaths.nstdir); if (mkdir(dirstr, 0755) && errno != EEXIST) { fprintf(stderr, "Failed to create %s: %d\n", dirstr, errno); } // create screenshots directory if it doesn't exist snprintf(dirstr, sizeof(dirstr), "%sscreenshots", nstpaths.nstdir); if (mkdir(dirstr, 0755) && errno != EEXIST) { fprintf(stderr, "Failed to create %s: %d\n", dirstr, errno); } // Construct the custom palette path snprintf(nstpaths.palettepath, sizeof(nstpaths.palettepath), "%s%s", nstpaths.nstdir, "custom.pal"); // Construct samples directory if it doesn't exist snprintf(dirstr, sizeof(dirstr), "%ssamples", nstpaths.nstdir); if (mkdir(dirstr, 0755) && errno != EEXIST) { fprintf(stderr, "Failed to create %s: %d\n", dirstr, errno); } } void nst_set_paths(const char *filename) { // Set up the save directory snprintf(nstpaths.savedir, sizeof(nstpaths.savedir), "%ssave/", nstpaths.nstdir); // Copy the full file path to the savename variable snprintf(nstpaths.savename, sizeof(nstpaths.savename), "%s", filename); // strip the . and extention off the filename for saving for (int i = strlen(nstpaths.savename)-1; i > 0; i--) { if (nstpaths.savename[i] == '.') { nstpaths.savename[i] = '\0'; break; } } // Set up the sample directory snprintf(nstpaths.sampdir, sizeof(nstpaths.sampdir), "%ssamples/", nstpaths.nstdir); // Get the name of the game minus file path and extension snprintf(nstpaths.gamename, sizeof(nstpaths.gamename), "%s", basename(nstpaths.savename)); // Construct save path snprintf(nstpaths.savename, sizeof(nstpaths.savename), "%s%s%s", nstpaths.savedir, nstpaths.gamename, ".sav"); // Construct path for FDS save patches snprintf(nstpaths.fdssave, sizeof(nstpaths.fdssave), "%s%s", nstpaths.savedir, nstpaths.gamename); // Construct the save state path snprintf(nstpaths.statepath, sizeof(nstpaths.statepath), "%sstate/%s", nstpaths.nstdir, nstpaths.gamename); // Construct the cheat path snprintf(nstpaths.cheatpath, sizeof(nstpaths.cheatpath), "%scheats/%s.xml", nstpaths.nstdir, nstpaths.gamename); } void nst_set_region() { // Set the region Machine machine(emulator); Cartridge::Database database(emulator); /*if (database.IsLoaded()) { std::ifstream dbfile(filename, std::ios::in|std::ios::binary); Cartridge::Profile profile; Cartridge::ReadInes(dbfile, nst_default_system(), profile); dbentry = database.FindEntry(profile.hash, nst_default_system()); printf("Mapper: %d\n", dbentry.GetMapper()); }*/ switch (conf.misc_default_system) { case 0: machine.SetMode(machine.GetDesiredMode()); break; // Auto case 1: machine.SetMode(Machine::NTSC); break; // NTSC case 2: machine.SetMode(Machine::PAL); break; // PAL case 3: machine.SetMode(Machine::NTSC); break; // Famicom case 4: machine.SetMode(Machine::PAL); break; // Dendy } } void nst_set_rewind(int direction) { // Set the rewinder backward or forward switch (direction) { case 0: Rewinder(emulator).SetDirection(Rewinder::BACKWARD); break; case 1: Rewinder(emulator).SetDirection(Rewinder::FORWARD); break; default: break; } } void nst_state_save(const char *filename) { // Save a state by filename Machine machine(emulator); std::ofstream statefile(filename, std::ifstream::out|std::ifstream::binary); if (statefile.is_open()) { machine.SaveState(statefile, Nes::Api::Machine::NO_COMPRESSION); } fprintf(stderr, "State Saved: %s\n", filename); nst_video_print("State Saved", 8, 212, 2, true); } void nst_state_load(const char *filename) { // Load a state by filename Machine machine(emulator); std::ifstream statefile(filename, std::ifstream::in|std::ifstream::binary); if (statefile.is_open()) { machine.LoadState(statefile); } fprintf(stderr, "State Loaded: %s\n", filename); nst_video_print("State Loaded", 8, 212, 2, true); } void nst_state_quicksave(int slot) { // Quick Save State if (!loaded) { return; } char slotpath[520]; snprintf(slotpath, sizeof(slotpath), "%s_%d.nst", nstpaths.statepath, slot); nst_state_save(slotpath); } void nst_state_quickload(int slot) { // Quick Load State if (!loaded) { return; } char slotpath[520]; snprintf(slotpath, sizeof(slotpath), "%s_%d.nst", nstpaths.statepath, slot); struct stat qloadstat; if (stat(slotpath, &qloadstat) == -1) { fprintf(stderr, "No State to Load\n"); nst_video_print("No State to Load", 8, 212, 2, true); return; } nst_state_load(slotpath); } int nst_timing_runframes() { // Calculate how many emulation frames to run if (ffspeed) { return conf.timing_ffspeed; } return 1; } void nst_timing_set_ffspeed() { // Set the framerate to the fast-forward speed ffspeed = true; audio_set_speed(conf.timing_ffspeed); } void nst_timing_set_default() { // Set the framerate to the default ffspeed = false; audio_set_speed(1); } void nst_reset(bool hardreset) { // Reset the machine (soft or hard) Machine machine(emulator); Fds fds(emulator); machine.SetRamPowerState(conf.misc_power_state); machine.Reset(hardreset); // Set the FDS disk to defaults fds.EjectDisk(); fds.InsertDisk(0, 0); } void nst_emuloop() { // Main Emulation Loop if (NES_SUCCEEDED(Rewinder(emulator).Enable(true))) { Rewinder(emulator).EnableSound(true); } if (playing) { // Pulse the turbo buttons nst_input_turbo_pulse(cNstPads); // Execute frames for (int i = 0; i < nst_timing_runframes(); i++) { emulator.Execute(cNstVideo, cNstSound, cNstPads); } } } void nst_unload() { // Remove the cartridge and shut down the NES Machine machine(emulator); // Power down the NES machine.Power(false); // Remove the cartridge machine.Unload(); } void nst_pause() { // Pauses the game if (playing) { audio_pause(); audio_deinit(); } playing = false; } void nst_play() { // Play the game if (playing) { return; } video_init(); audio_init(); nst_input_init(); nst_cheats_init(nstpaths.cheatpath); nst_homebrew_init(); cNstVideo = new Video::Output; cNstSound = new Sound::Output; cNstPads = new Input::Controllers; audio_set_params(cNstSound); audio_unpause(); if (nst_nsf()) { Nsf nsf(emulator); nsf.PlaySong(); video_disp_nsf(); } playing = true; } int nst_load(const char *filename) { // Load a Game ROM Machine machine(emulator); Nsf nsf(emulator); Sound sound(emulator); Nes::Result result; char *rom; int romsize; char patchname[512]; // Pause play before pulling out a cartridge if (playing) { nst_pause(); } // Pull out any inserted cartridges if (loaded) { nst_unload(); } nst_video_print_time("", false); // Check if the file is an archive and select the file within char reqfile[256]; // Requested file inside the archive if (nst_archive_select(filename, reqfile, sizeof(reqfile))) { // Extract the contents nst_archive_open(filename, &rom, &romsize, reqfile); // Convert the malloc'd char* to an istream std::string rombuf(rom, romsize); std::istringstream file(rombuf); free(rom); result = machine.Load(file, nst_default_system()); } else { // Otherwise just load the file std::ifstream file(filename, std::ios::in|std::ios::binary); // Set the file paths nst_set_paths(filename); if (nst_find_patch(patchname, sizeof(patchname), filename)) { // Load with a patch if there is one std::ifstream pfile(patchname, std::ios::in|std::ios::binary); Machine::Patch patch(pfile, false); result = machine.Load(file, nst_default_system(), patch); } else { result = machine.Load(file, nst_default_system()); } } if (NES_FAILED(result)) { char errorstring[32]; switch (result) { case Nes::RESULT_ERR_INVALID_FILE: snprintf(errorstring, sizeof(errorstring), "Error: Invalid file"); break; case Nes::RESULT_ERR_OUT_OF_MEMORY: snprintf(errorstring, sizeof(errorstring), "Error: Out of Memory"); break; case Nes::RESULT_ERR_CORRUPT_FILE: snprintf(errorstring, sizeof(errorstring), "Error: Corrupt or Missing File"); break; case Nes::RESULT_ERR_UNSUPPORTED_MAPPER: snprintf(errorstring, sizeof(errorstring), "Error: Unsupported Mapper"); break; case Nes::RESULT_ERR_MISSING_BIOS: snprintf(errorstring, sizeof(errorstring), "Error: Missing Fds BIOS"); break; default: snprintf(errorstring, sizeof(errorstring), "Error: %d", result); break; } fprintf(stderr, "%s\n", errorstring); return 0; } // Deal with any DIP Switches nst_dipswitch(); // Set the region nst_set_region(); if (machine.Is(Machine::DISK)) { Fds fds(emulator); fds.InsertDisk(0, 0); nst_fds_info(); } // Check if this is an NSF if (nst_nsf()) { nsf.StopSong(); } // Check if sound distortion should be enabled sound.SetGenie(conf.misc_genie_distortion); // Load the custom palette nst_palette_load(nstpaths.palettepath); // Set the RAM's power state machine.SetRamPowerState(conf.misc_power_state); // Power on machine.Power(true); loaded = 1; return loaded; } nestopia-1.51.1/source/fltkui/nstcommon.h000066400000000000000000000045041411157722000204100ustar00rootroot00000000000000#ifndef _NSTCOMMON_H_ #define _NSTCOMMON_H_ // Nst Core #include "core/api/NstApiEmulator.hpp" #include "core/api/NstApiVideo.hpp" #include "core/api/NstApiSound.hpp" #include "core/api/NstApiMachine.hpp" #include "core/api/NstApiCartridge.hpp" #include "core/api/NstApiFds.hpp" #include "core/api/NstApiNsf.hpp" #include "core/api/NstApiUser.hpp" #include "core/api/NstApiRewinder.hpp" #include "core/api/NstApiMovie.hpp" using namespace Nes::Api; typedef struct { char nstdir[256]; char nstconfdir[256]; char savedir[256]; char gamename[256]; char savename[512]; char fdssave[512]; char statepath[512]; char cheatpath[512]; char palettepath[512]; char sampdir[512]; } nstpaths_t; // Pointers void* nst_ptr_video(); void* nst_ptr_sound(); void* nst_ptr_input(); // Archives bool nst_archive_checkext(const char *filename); bool nst_archive_select_file(const char *filename, char *reqfile, size_t reqsize); bool nst_archive_open(const char *filename, char **rom, int *romsize, const char *reqfile); // DIP Switches void nst_dipswitch(); // Database void nst_db_load(); void nst_db_unload(); // FDS void nst_fds_bios_load(); void nst_fds_bios_unload(); void nst_fds_info(); void nst_fds_flip(); void nst_fds_switch(); // Movies void nst_movie_save(const char *filename); void nst_movie_load(const char *filename); void nst_movie_stop(); // NSF bool nst_nsf(); void nst_nsf_play(); void nst_nsf_stop(); void nst_nsf_prev(); void nst_nsf_next(); // PAL bool nst_pal(); // Play check bool nst_playing(); // Palette void nst_palette_load(const char *filename); void nst_palette_save(); void nst_palette_unload(); // Patch bool nst_find_patch(char *patchname, unsigned int patchname_length, const char *filename); // Setters void nst_set_callbacks(); void nst_set_dirs(); void nst_set_overclock(); void nst_set_paths(const char *filename); void nst_set_region(); void nst_set_rewind(int direction); // States void nst_state_save(const char *filename); void nst_state_load(const char *filename); void nst_state_quicksave(int isvst); void nst_state_quickload(int isvst); // Timing int nst_timing_runframes(); void nst_timing_set_ffspeed(); void nst_timing_set_default(); // Main Emulation void nst_reset(bool hardreset); void nst_emuloop(); // Unsorted int nst_load(const char *filename); void nst_unload(); void nst_play(); void nst_pause(); #endif nestopia-1.51.1/source/fltkui/png.cpp000066400000000000000000006466661411157722000175370ustar00rootroot00000000000000/* LodePNG version 20141130 Copyright (c) 2005-2014 Lode Vandevenne This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #include "png.h" #include #include #ifdef LODEPNG_COMPILE_CPP #include #endif /*LODEPNG_COMPILE_CPP*/ #if defined(_MSC_VER) && (_MSC_VER >= 1310) /*Visual Studio: A few warning types are not desired here.*/ #pragma warning( disable : 4244 ) /*implicit conversions: not warned by gcc -Wall -Wextra and requires too much casts*/ #pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/ #endif /*_MSC_VER */ /* This source file is built up in the following large parts. The code sections with the "LODEPNG_COMPILE_" #defines divide this up further in an intermixed way. -Tools for C and common code for PNG and Zlib -C Code for Zlib (huffman, deflate, ...) -C Code for PNG (file format chunks, adam7, PNG filters, color conversions, ...) -The C++ wrapper around all of the above */ /*The malloc, realloc and free functions defined here with "lodepng_" in front of the name, so that you can easily change them to others related to your platform if needed. Everything else in the code calls these. Pass -DLODEPNG_NO_COMPILE_ALLOCATORS to the compiler, or comment out #define LODEPNG_COMPILE_ALLOCATORS in the header, to disable the ones here and define them in your own project's source files without needing to change lodepng source code. Don't forget to remove "static" if you copypaste them from here.*/ #ifdef LODEPNG_COMPILE_ALLOCATORS static void* lodepng_malloc(size_t size) { return malloc(size); } static void* lodepng_realloc(void* ptr, size_t new_size) { return realloc(ptr, new_size); } static void lodepng_free(void* ptr) { free(ptr); } #else /*LODEPNG_COMPILE_ALLOCATORS*/ void* lodepng_malloc(size_t size); void* lodepng_realloc(void* ptr, size_t new_size); void lodepng_free(void* ptr); #endif /*LODEPNG_COMPILE_ALLOCATORS*/ /* ////////////////////////////////////////////////////////////////////////// */ /* ////////////////////////////////////////////////////////////////////////// */ /* // Tools for C, and common code for PNG and Zlib. // */ /* ////////////////////////////////////////////////////////////////////////// */ /* ////////////////////////////////////////////////////////////////////////// */ /* Often in case of an error a value is assigned to a variable and then it breaks out of a loop (to go to the cleanup phase of a function). This macro does that. It makes the error handling code shorter and more readable. Example: if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83); */ #define CERROR_BREAK(errorvar, code)\ {\ errorvar = code;\ break;\ } /*version of CERROR_BREAK that assumes the common case where the error variable is named "error"*/ #define ERROR_BREAK(code) CERROR_BREAK(error, code) /*Set error var to the error code, and return it.*/ #define CERROR_RETURN_ERROR(errorvar, code)\ {\ errorvar = code;\ return code;\ } /*Try the code, if it returns error, also return the error.*/ #define CERROR_TRY_RETURN(call)\ {\ unsigned error = call;\ if(error) return error;\ } /*Set error var to the error code, and return from the void function.*/ #define CERROR_RETURN(errorvar, code)\ {\ errorvar = code;\ return;\ } /* About uivector, ucvector and string: -All of them wrap dynamic arrays or text strings in a similar way. -LodePNG was originally written in C++. The vectors replace the std::vectors that were used in the C++ version. -The string tools are made to avoid problems with compilers that declare things like strncat as deprecated. -They're not used in the interface, only internally in this file as static functions. -As with many other structs in this file, the init and cleanup functions serve as ctor and dtor. */ #ifdef LODEPNG_COMPILE_ZLIB /*dynamic vector of unsigned ints*/ typedef struct uivector { unsigned* data; size_t size; /*size in number of unsigned longs*/ size_t allocsize; /*allocated size in bytes*/ } uivector; static void uivector_cleanup(void* p) { ((uivector*)p)->size = ((uivector*)p)->allocsize = 0; lodepng_free(((uivector*)p)->data); ((uivector*)p)->data = NULL; } /*returns 1 if success, 0 if failure ==> nothing done*/ static unsigned uivector_reserve(uivector* p, size_t allocsize) { if(allocsize > p->allocsize) { size_t newsize = (allocsize > p->allocsize * 2) ? allocsize : (allocsize * 3 / 2); void* data = lodepng_realloc(p->data, newsize); if(data) { p->allocsize = newsize; p->data = (unsigned*)data; } else return 0; /*error: not enough memory*/ } return 1; } /*returns 1 if success, 0 if failure ==> nothing done*/ static unsigned uivector_resize(uivector* p, size_t size) { if(!uivector_reserve(p, size * sizeof(unsigned))) return 0; p->size = size; return 1; /*success*/ } /*resize and give all new elements the value*/ static unsigned uivector_resizev(uivector* p, size_t size, unsigned value) { size_t oldsize = p->size, i; if(!uivector_resize(p, size)) return 0; for(i = oldsize; i < size; ++i) p->data[i] = value; return 1; } static void uivector_init(uivector* p) { p->data = NULL; p->size = p->allocsize = 0; } #ifdef LODEPNG_COMPILE_ENCODER /*returns 1 if success, 0 if failure ==> nothing done*/ static unsigned uivector_push_back(uivector* p, unsigned c) { if(!uivector_resize(p, p->size + 1)) return 0; p->data[p->size - 1] = c; return 1; } /*copy q to p, returns 1 if success, 0 if failure ==> nothing done*/ static unsigned uivector_copy(uivector* p, const uivector* q) { size_t i; if(!uivector_resize(p, q->size)) return 0; for(i = 0; i != q->size; ++i) p->data[i] = q->data[i]; return 1; } #endif /*LODEPNG_COMPILE_ENCODER*/ #endif /*LODEPNG_COMPILE_ZLIB*/ /* /////////////////////////////////////////////////////////////////////////// */ /*dynamic vector of unsigned chars*/ typedef struct ucvector { unsigned char* data; size_t size; /*used size*/ size_t allocsize; /*allocated size*/ } ucvector; /*returns 1 if success, 0 if failure ==> nothing done*/ static unsigned ucvector_reserve(ucvector* p, size_t allocsize) { if(allocsize > p->allocsize) { size_t newsize = (allocsize > p->allocsize * 2) ? allocsize : (allocsize * 3 / 2); void* data = lodepng_realloc(p->data, newsize); if(data) { p->allocsize = newsize; p->data = (unsigned char*)data; } else return 0; /*error: not enough memory*/ } return 1; } /*returns 1 if success, 0 if failure ==> nothing done*/ static unsigned ucvector_resize(ucvector* p, size_t size) { if(!ucvector_reserve(p, size * sizeof(unsigned char))) return 0; p->size = size; return 1; /*success*/ } #ifdef LODEPNG_COMPILE_PNG static void ucvector_cleanup(void* p) { ((ucvector*)p)->size = ((ucvector*)p)->allocsize = 0; lodepng_free(((ucvector*)p)->data); ((ucvector*)p)->data = NULL; } static void ucvector_init(ucvector* p) { p->data = NULL; p->size = p->allocsize = 0; } #ifdef LODEPNG_COMPILE_DECODER /*resize and give all new elements the value*/ static unsigned ucvector_resizev(ucvector* p, size_t size, unsigned char value) { size_t oldsize = p->size, i; if(!ucvector_resize(p, size)) return 0; for(i = oldsize; i < size; ++i) p->data[i] = value; return 1; } #endif /*LODEPNG_COMPILE_DECODER*/ #endif /*LODEPNG_COMPILE_PNG*/ #ifdef LODEPNG_COMPILE_ZLIB /*you can both convert from vector to buffer&size and vica versa. If you use init_buffer to take over a buffer and size, it is not needed to use cleanup*/ static void ucvector_init_buffer(ucvector* p, unsigned char* buffer, size_t size) { p->data = buffer; p->allocsize = p->size = size; } #endif /*LODEPNG_COMPILE_ZLIB*/ #if (defined(LODEPNG_COMPILE_PNG) && defined(LODEPNG_COMPILE_ANCILLARY_CHUNKS)) || defined(LODEPNG_COMPILE_ENCODER) /*returns 1 if success, 0 if failure ==> nothing done*/ static unsigned ucvector_push_back(ucvector* p, unsigned char c) { if(!ucvector_resize(p, p->size + 1)) return 0; p->data[p->size - 1] = c; return 1; } #endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/ /* ////////////////////////////////////////////////////////////////////////// */ #ifdef LODEPNG_COMPILE_PNG #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*returns 1 if success, 0 if failure ==> nothing done*/ static unsigned string_resize(char** out, size_t size) { char* data = (char*)lodepng_realloc(*out, size + 1); if(data) { data[size] = 0; /*null termination char*/ *out = data; } return data != 0; } /*init a {char*, size_t} pair for use as string*/ static void string_init(char** out) { *out = NULL; string_resize(out, 0); } /*free the above pair again*/ static void string_cleanup(char** out) { lodepng_free(*out); *out = NULL; } static void string_set(char** out, const char* in) { size_t insize = strlen(in), i; if(string_resize(out, insize)) { for(i = 0; i != insize; ++i) { (*out)[i] = in[i]; } } } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ #endif /*LODEPNG_COMPILE_PNG*/ /* ////////////////////////////////////////////////////////////////////////// */ unsigned lodepng_read32bitInt(const unsigned char* buffer) { return (unsigned)((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]); } #if defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER) /*buffer must have at least 4 allocated bytes available*/ static void lodepng_set32bitInt(unsigned char* buffer, unsigned value) { buffer[0] = (unsigned char)((value >> 24) & 0xff); buffer[1] = (unsigned char)((value >> 16) & 0xff); buffer[2] = (unsigned char)((value >> 8) & 0xff); buffer[3] = (unsigned char)((value ) & 0xff); } #endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/ #ifdef LODEPNG_COMPILE_ENCODER static void lodepng_add32bitInt(ucvector* buffer, unsigned value) { ucvector_resize(buffer, buffer->size + 4); /*todo: give error if resize failed*/ lodepng_set32bitInt(&buffer->data[buffer->size - 4], value); } #endif /*LODEPNG_COMPILE_ENCODER*/ /* ////////////////////////////////////////////////////////////////////////// */ /* / File IO / */ /* ////////////////////////////////////////////////////////////////////////// */ #ifdef LODEPNG_COMPILE_DISK unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename) { FILE* file; long size; /*provide some proper output values if error will happen*/ *out = 0; *outsize = 0; file = fopen(filename, "rb"); if(!file) return 78; /*get filesize:*/ fseek(file , 0 , SEEK_END); size = ftell(file); rewind(file); /*read contents of the file into the vector*/ *outsize = 0; *out = (unsigned char*)lodepng_malloc((size_t)size); if(size && (*out)) (*outsize) = fread(*out, 1, (size_t)size, file); fclose(file); if(!(*out) && size) return 83; /*the above malloc failed*/ return 0; } /*write given buffer to the file, overwriting the file, it doesn't append to it.*/ unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename) { FILE* file; file = fopen(filename, "wb" ); if(!file) return 79; fwrite((char*)buffer , 1 , buffersize, file); fclose(file); return 0; } #endif /*LODEPNG_COMPILE_DISK*/ /* ////////////////////////////////////////////////////////////////////////// */ /* ////////////////////////////////////////////////////////////////////////// */ /* // End of common code and tools. Begin of Zlib related code. // */ /* ////////////////////////////////////////////////////////////////////////// */ /* ////////////////////////////////////////////////////////////////////////// */ #ifdef LODEPNG_COMPILE_ZLIB #ifdef LODEPNG_COMPILE_ENCODER /*TODO: this ignores potential out of memory errors*/ #define addBitToStream(/*size_t**/ bitpointer, /*ucvector**/ bitstream, /*unsigned char*/ bit)\ {\ /*add a new byte at the end*/\ if(((*bitpointer) & 7) == 0) ucvector_push_back(bitstream, (unsigned char)0);\ /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/\ (bitstream->data[bitstream->size - 1]) |= (bit << ((*bitpointer) & 0x7));\ ++(*bitpointer);\ } static void addBitsToStream(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits) { size_t i; for(i = 0; i != nbits; ++i) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> i) & 1)); } static void addBitsToStreamReversed(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits) { size_t i; for(i = 0; i != nbits; ++i) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> (nbits - 1 - i)) & 1)); } #endif /*LODEPNG_COMPILE_ENCODER*/ #ifdef LODEPNG_COMPILE_DECODER #define READBIT(bitpointer, bitstream) ((bitstream[bitpointer >> 3] >> (bitpointer & 0x7)) & (unsigned char)1) static unsigned char readBitFromStream(size_t* bitpointer, const unsigned char* bitstream) { unsigned char result = (unsigned char)(READBIT(*bitpointer, bitstream)); ++(*bitpointer); return result; } static unsigned readBitsFromStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) { unsigned result = 0, i; for(i = 0; i != nbits; ++i) { result += ((unsigned)READBIT(*bitpointer, bitstream)) << i; ++(*bitpointer); } return result; } #endif /*LODEPNG_COMPILE_DECODER*/ /* ////////////////////////////////////////////////////////////////////////// */ /* / Deflate - Huffman / */ /* ////////////////////////////////////////////////////////////////////////// */ #define FIRST_LENGTH_CODE_INDEX 257 #define LAST_LENGTH_CODE_INDEX 285 /*256 literals, the end code, some length codes, and 2 unused codes*/ #define NUM_DEFLATE_CODE_SYMBOLS 288 /*the distance codes have their own symbols, 30 used, 2 unused*/ #define NUM_DISTANCE_SYMBOLS 32 /*the code length codes. 0-15: code lengths, 16: copy previous 3-6 times, 17: 3-10 zeros, 18: 11-138 zeros*/ #define NUM_CODE_LENGTH_CODES 19 /*the base lengths represented by codes 257-285*/ static const unsigned LENGTHBASE[29] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258}; /*the extra bits used by codes 257-285 (added to base length)*/ static const unsigned LENGTHEXTRA[29] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0}; /*the base backwards distances (the bits of distance codes appear after length codes and use their own huffman tree)*/ static const unsigned DISTANCEBASE[30] = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; /*the extra bits of backwards distances (added to base)*/ static const unsigned DISTANCEEXTRA[30] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; /*the order in which "code length alphabet code lengths" are stored, out of this the huffman tree of the dynamic huffman tree lengths is generated*/ static const unsigned CLCL_ORDER[NUM_CODE_LENGTH_CODES] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; /* ////////////////////////////////////////////////////////////////////////// */ /* Huffman tree struct, containing multiple representations of the tree */ typedef struct HuffmanTree { unsigned* tree2d; unsigned* tree1d; unsigned* lengths; /*the lengths of the codes of the 1d-tree*/ unsigned maxbitlen; /*maximum number of bits a single code can get*/ unsigned numcodes; /*number of symbols in the alphabet = number of codes*/ } HuffmanTree; /*function used for debug purposes to draw the tree in ascii art with C++*/ /* static void HuffmanTree_draw(HuffmanTree* tree) { std::cout << "tree. length: " << tree->numcodes << " maxbitlen: " << tree->maxbitlen << std::endl; for(size_t i = 0; i != tree->tree1d.size; ++i) { if(tree->lengths.data[i]) std::cout << i << " " << tree->tree1d.data[i] << " " << tree->lengths.data[i] << std::endl; } std::cout << std::endl; }*/ static void HuffmanTree_init(HuffmanTree* tree) { tree->tree2d = 0; tree->tree1d = 0; tree->lengths = 0; } static void HuffmanTree_cleanup(HuffmanTree* tree) { lodepng_free(tree->tree2d); lodepng_free(tree->tree1d); lodepng_free(tree->lengths); } /*the tree representation used by the decoder. return value is error*/ static unsigned HuffmanTree_make2DTree(HuffmanTree* tree) { unsigned nodefilled = 0; /*up to which node it is filled*/ unsigned treepos = 0; /*position in the tree (1 of the numcodes columns)*/ unsigned n, i; tree->tree2d = (unsigned*)lodepng_malloc(tree->numcodes * 2 * sizeof(unsigned)); if(!tree->tree2d) return 83; /*alloc fail*/ /* convert tree1d[] to tree2d[][]. In the 2D array, a value of 32767 means uninited, a value >= numcodes is an address to another bit, a value < numcodes is a code. The 2 rows are the 2 possible bit values (0 or 1), there are as many columns as codes - 1. A good huffmann tree has N * 2 - 1 nodes, of which N - 1 are internal nodes. Here, the internal nodes are stored (what their 0 and 1 option point to). There is only memory for such good tree currently, if there are more nodes (due to too long length codes), error 55 will happen */ for(n = 0; n < tree->numcodes * 2; ++n) { tree->tree2d[n] = 32767; /*32767 here means the tree2d isn't filled there yet*/ } for(n = 0; n < tree->numcodes; ++n) /*the codes*/ { for(i = 0; i != tree->lengths[n]; ++i) /*the bits for this code*/ { unsigned char bit = (unsigned char)((tree->tree1d[n] >> (tree->lengths[n] - i - 1)) & 1); /*oversubscribed, see comment in lodepng_error_text*/ if(treepos > 2147483647 || treepos + 2 > tree->numcodes) return 55; if(tree->tree2d[2 * treepos + bit] == 32767) /*not yet filled in*/ { if(i + 1 == tree->lengths[n]) /*last bit*/ { tree->tree2d[2 * treepos + bit] = n; /*put the current code in it*/ treepos = 0; } else { /*put address of the next step in here, first that address has to be found of course (it's just nodefilled + 1)...*/ ++nodefilled; /*addresses encoded with numcodes added to it*/ tree->tree2d[2 * treepos + bit] = nodefilled + tree->numcodes; treepos = nodefilled; } } else treepos = tree->tree2d[2 * treepos + bit] - tree->numcodes; } } for(n = 0; n < tree->numcodes * 2; ++n) { if(tree->tree2d[n] == 32767) tree->tree2d[n] = 0; /*remove possible remaining 32767's*/ } return 0; } /* Second step for the ...makeFromLengths and ...makeFromFrequencies functions. numcodes, lengths and maxbitlen must already be filled in correctly. return value is error. */ static unsigned HuffmanTree_makeFromLengths2(HuffmanTree* tree) { uivector blcount; uivector nextcode; unsigned error = 0; unsigned bits, n; uivector_init(&blcount); uivector_init(&nextcode); tree->tree1d = (unsigned*)lodepng_malloc(tree->numcodes * sizeof(unsigned)); if(!tree->tree1d) error = 83; /*alloc fail*/ if(!uivector_resizev(&blcount, tree->maxbitlen + 1, 0) || !uivector_resizev(&nextcode, tree->maxbitlen + 1, 0)) error = 83; /*alloc fail*/ if(!error) { /*step 1: count number of instances of each code length*/ for(bits = 0; bits != tree->numcodes; ++bits) ++blcount.data[tree->lengths[bits]]; /*step 2: generate the nextcode values*/ for(bits = 1; bits <= tree->maxbitlen; ++bits) { nextcode.data[bits] = (nextcode.data[bits - 1] + blcount.data[bits - 1]) << 1; } /*step 3: generate all the codes*/ for(n = 0; n != tree->numcodes; ++n) { if(tree->lengths[n] != 0) tree->tree1d[n] = nextcode.data[tree->lengths[n]]++; } } uivector_cleanup(&blcount); uivector_cleanup(&nextcode); if(!error) return HuffmanTree_make2DTree(tree); else return error; } /* given the code lengths (as stored in the PNG file), generate the tree as defined by Deflate. maxbitlen is the maximum bits that a code in the tree can have. return value is error. */ static unsigned HuffmanTree_makeFromLengths(HuffmanTree* tree, const unsigned* bitlen, size_t numcodes, unsigned maxbitlen) { unsigned i; tree->lengths = (unsigned*)lodepng_malloc(numcodes * sizeof(unsigned)); if(!tree->lengths) return 83; /*alloc fail*/ for(i = 0; i != numcodes; ++i) tree->lengths[i] = bitlen[i]; tree->numcodes = (unsigned)numcodes; /*number of symbols*/ tree->maxbitlen = maxbitlen; return HuffmanTree_makeFromLengths2(tree); } #ifdef LODEPNG_COMPILE_ENCODER /* A coin, this is the terminology used for the package-merge algorithm and the coin collector's problem. This is used to generate the huffman tree. A coin can be multiple coins (when they're merged) */ typedef struct Coin { uivector symbols; float weight; /*the sum of all weights in this coin*/ } Coin; static void coin_init(Coin* c) { uivector_init(&c->symbols); } /*argument c is void* so that this dtor can be given as function pointer to the vector resize function*/ static void coin_cleanup(void* c) { uivector_cleanup(&((Coin*)c)->symbols); } static void coin_copy(Coin* c1, const Coin* c2) { c1->weight = c2->weight; uivector_copy(&c1->symbols, &c2->symbols); } static void add_coins(Coin* c1, const Coin* c2) { size_t i; for(i = 0; i != c2->symbols.size; ++i) uivector_push_back(&c1->symbols, c2->symbols.data[i]); c1->weight += c2->weight; } static void init_coins(Coin* coins, size_t num) { size_t i; for(i = 0; i != num; ++i) coin_init(&coins[i]); } static void cleanup_coins(Coin* coins, size_t num) { size_t i; for(i = 0; i != num; ++i) coin_cleanup(&coins[i]); } static int coin_compare(const void* a, const void* b) { float wa = ((const Coin*)a)->weight; float wb = ((const Coin*)b)->weight; return wa > wb ? 1 : wa < wb ? -1 : 0; } static unsigned append_symbol_coins(Coin* coins, const unsigned* frequencies, unsigned numcodes, size_t sum) { unsigned i; unsigned j = 0; /*index of present symbols*/ for(i = 0; i != numcodes; ++i) { if(frequencies[i] != 0) /*only include symbols that are present*/ { coins[j].weight = frequencies[i] / (float)sum; uivector_push_back(&coins[j].symbols, i); ++j; } } return 0; } unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, size_t numcodes, unsigned maxbitlen) { unsigned i, j; size_t sum = 0, numpresent = 0; unsigned error = 0; Coin* coins; /*the coins of the currently calculated row*/ Coin* prev_row; /*the previous row of coins*/ size_t numcoins; size_t coinmem; if(numcodes == 0) return 80; /*error: a tree of 0 symbols is not supposed to be made*/ for(i = 0; i != numcodes; ++i) { if(frequencies[i] > 0) { ++numpresent; sum += frequencies[i]; } } for(i = 0; i != numcodes; ++i) lengths[i] = 0; /*ensure at least two present symbols. There should be at least one symbol according to RFC 1951 section 3.2.7. To decoders incorrectly require two. To make these work as well ensure there are at least two symbols. The Package-Merge code below also doesn't work correctly if there's only one symbol, it'd give it the theoritical 0 bits but in practice zlib wants 1 bit*/ if(numpresent == 0) { lengths[0] = lengths[1] = 1; /*note that for RFC 1951 section 3.2.7, only lengths[0] = 1 is needed*/ } else if(numpresent == 1) { for(i = 0; i != numcodes; ++i) { if(frequencies[i]) { lengths[i] = 1; lengths[i == 0 ? 1 : 0] = 1; break; } } } else { /*Package-Merge algorithm represented by coin collector's problem For every symbol, maxbitlen coins will be created*/ coinmem = numpresent * 2; /*max amount of coins needed with the current algo*/ coins = (Coin*)lodepng_malloc(sizeof(Coin) * coinmem); prev_row = (Coin*)lodepng_malloc(sizeof(Coin) * coinmem); if(!coins || !prev_row) { lodepng_free(coins); lodepng_free(prev_row); return 83; /*alloc fail*/ } init_coins(coins, coinmem); init_coins(prev_row, coinmem); /*first row, lowest denominator*/ error = append_symbol_coins(coins, frequencies, numcodes, sum); numcoins = numpresent; qsort(coins, numcoins, sizeof(Coin), coin_compare); if(!error) { unsigned numprev = 0; for(j = 1; j <= maxbitlen && !error; ++j) /*each of the remaining rows*/ { unsigned tempnum; Coin* tempcoins; /*swap prev_row and coins, and their amounts*/ tempcoins = prev_row; prev_row = coins; coins = tempcoins; tempnum = numprev; numprev = numcoins; numcoins = tempnum; cleanup_coins(coins, numcoins); init_coins(coins, numcoins); numcoins = 0; /*fill in the merged coins of the previous row*/ for(i = 0; i + 1 < numprev; i += 2) { /*merge prev_row[i] and prev_row[i + 1] into new coin*/ Coin* coin = &coins[numcoins++]; coin_copy(coin, &prev_row[i]); add_coins(coin, &prev_row[i + 1]); } /*fill in all the original symbols again*/ if(j < maxbitlen) { error = append_symbol_coins(coins + numcoins, frequencies, numcodes, sum); numcoins += numpresent; } qsort(coins, numcoins, sizeof(Coin), coin_compare); } } if(!error) { /*calculate the lengths of each symbol, as the amount of times a coin of each symbol is used*/ for(i = 0; i + 1 < numpresent; ++i) { Coin* coin = &coins[i]; for(j = 0; j < coin->symbols.size; ++j) ++lengths[coin->symbols.data[j]]; } } cleanup_coins(coins, coinmem); lodepng_free(coins); cleanup_coins(prev_row, coinmem); lodepng_free(prev_row); } return error; } /*Create the Huffman tree given the symbol frequencies*/ static unsigned HuffmanTree_makeFromFrequencies(HuffmanTree* tree, const unsigned* frequencies, size_t mincodes, size_t numcodes, unsigned maxbitlen) { unsigned error = 0; while(!frequencies[numcodes - 1] && numcodes > mincodes) --numcodes; /*trim zeroes*/ tree->maxbitlen = maxbitlen; tree->numcodes = (unsigned)numcodes; /*number of symbols*/ tree->lengths = (unsigned*)lodepng_realloc(tree->lengths, numcodes * sizeof(unsigned)); if(!tree->lengths) return 83; /*alloc fail*/ /*initialize all lengths to 0*/ memset(tree->lengths, 0, numcodes * sizeof(unsigned)); error = lodepng_huffman_code_lengths(tree->lengths, frequencies, numcodes, maxbitlen); if(!error) error = HuffmanTree_makeFromLengths2(tree); return error; } static unsigned HuffmanTree_getCode(const HuffmanTree* tree, unsigned index) { return tree->tree1d[index]; } static unsigned HuffmanTree_getLength(const HuffmanTree* tree, unsigned index) { return tree->lengths[index]; } #endif /*LODEPNG_COMPILE_ENCODER*/ /*get the literal and length code tree of a deflated block with fixed tree, as per the deflate specification*/ static unsigned generateFixedLitLenTree(HuffmanTree* tree) { unsigned i, error = 0; unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); if(!bitlen) return 83; /*alloc fail*/ /*288 possible codes: 0-255=literals, 256=endcode, 257-285=lengthcodes, 286-287=unused*/ for(i = 0; i <= 143; ++i) bitlen[i] = 8; for(i = 144; i <= 255; ++i) bitlen[i] = 9; for(i = 256; i <= 279; ++i) bitlen[i] = 7; for(i = 280; i <= 287; ++i) bitlen[i] = 8; error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DEFLATE_CODE_SYMBOLS, 15); lodepng_free(bitlen); return error; } /*get the distance code tree of a deflated block with fixed tree, as specified in the deflate specification*/ static unsigned generateFixedDistanceTree(HuffmanTree* tree) { unsigned i, error = 0; unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); if(!bitlen) return 83; /*alloc fail*/ /*there are 32 distance codes, but 30-31 are unused*/ for(i = 0; i != NUM_DISTANCE_SYMBOLS; ++i) bitlen[i] = 5; error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DISTANCE_SYMBOLS, 15); lodepng_free(bitlen); return error; } #ifdef LODEPNG_COMPILE_DECODER /* returns the code, or (unsigned)(-1) if error happened inbitlength is the length of the complete buffer, in bits (so its byte length times 8) */ static unsigned huffmanDecodeSymbol(const unsigned char* in, size_t* bp, const HuffmanTree* codetree, size_t inbitlength) { unsigned treepos = 0, ct; for(;;) { if(*bp >= inbitlength) return (unsigned)(-1); /*error: end of input memory reached without endcode*/ /* decode the symbol from the tree. The "readBitFromStream" code is inlined in the expression below because this is the biggest bottleneck while decoding */ ct = codetree->tree2d[(treepos << 1) + READBIT(*bp, in)]; ++(*bp); if(ct < codetree->numcodes) return ct; /*the symbol is decoded, return it*/ else treepos = ct - codetree->numcodes; /*symbol not yet decoded, instead move tree position*/ if(treepos >= codetree->numcodes) return (unsigned)(-1); /*error: it appeared outside the codetree*/ } } #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_DECODER /* ////////////////////////////////////////////////////////////////////////// */ /* / Inflator (Decompressor) / */ /* ////////////////////////////////////////////////////////////////////////// */ /*get the tree of a deflated block with fixed tree, as specified in the deflate specification*/ static void getTreeInflateFixed(HuffmanTree* tree_ll, HuffmanTree* tree_d) { /*TODO: check for out of memory errors*/ generateFixedLitLenTree(tree_ll); generateFixedDistanceTree(tree_d); } /*get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree*/ static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d, const unsigned char* in, size_t* bp, size_t inlength) { /*make sure that length values that aren't filled in will be 0, or a wrong tree will be generated*/ unsigned error = 0; unsigned n, HLIT, HDIST, HCLEN, i; size_t inbitlength = inlength * 8; /*see comments in deflateDynamic for explanation of the context and these variables, it is analogous*/ unsigned* bitlen_ll = 0; /*lit,len code lengths*/ unsigned* bitlen_d = 0; /*dist code lengths*/ /*code length code lengths ("clcl"), the bit lengths of the huffman tree used to compress bitlen_ll and bitlen_d*/ unsigned* bitlen_cl = 0; HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree for compressed huffman trees)*/ if((*bp) + 14 > (inlength << 3)) return 49; /*error: the bit pointer is or will go past the memory*/ /*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/ HLIT = readBitsFromStream(bp, in, 5) + 257; /*number of distance codes. Unlike the spec, the value 1 is added to it here already*/ HDIST = readBitsFromStream(bp, in, 5) + 1; /*number of code length codes. Unlike the spec, the value 4 is added to it here already*/ HCLEN = readBitsFromStream(bp, in, 4) + 4; if((*bp) + HCLEN * 3 > (inlength << 3)) return 50; /*error: the bit pointer is or will go past the memory*/ HuffmanTree_init(&tree_cl); while(!error) { /*read the code length codes out of 3 * (amount of code length codes) bits*/ bitlen_cl = (unsigned*)lodepng_malloc(NUM_CODE_LENGTH_CODES * sizeof(unsigned)); if(!bitlen_cl) ERROR_BREAK(83 /*alloc fail*/); for(i = 0; i != NUM_CODE_LENGTH_CODES; ++i) { if(i < HCLEN) bitlen_cl[CLCL_ORDER[i]] = readBitsFromStream(bp, in, 3); else bitlen_cl[CLCL_ORDER[i]] = 0; /*if not, it must stay 0*/ } error = HuffmanTree_makeFromLengths(&tree_cl, bitlen_cl, NUM_CODE_LENGTH_CODES, 7); if(error) break; /*now we can use this tree to read the lengths for the tree that this function will return*/ bitlen_ll = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); bitlen_d = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); if(!bitlen_ll || !bitlen_d) ERROR_BREAK(83 /*alloc fail*/); for(i = 0; i != NUM_DEFLATE_CODE_SYMBOLS; ++i) bitlen_ll[i] = 0; for(i = 0; i != NUM_DISTANCE_SYMBOLS; ++i) bitlen_d[i] = 0; /*i is the current symbol we're reading in the part that contains the code lengths of lit/len and dist codes*/ i = 0; while(i < HLIT + HDIST) { unsigned code = huffmanDecodeSymbol(in, bp, &tree_cl, inbitlength); if(code <= 15) /*a length code*/ { if(i < HLIT) bitlen_ll[i] = code; else bitlen_d[i - HLIT] = code; ++i; } else if(code == 16) /*repeat previous*/ { unsigned replength = 3; /*read in the 2 bits that indicate repeat length (3-6)*/ unsigned value; /*set value to the previous code*/ if (i == 0) ERROR_BREAK(54); /*can't repeat previous if i is 0*/ if((*bp + 2) > inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ replength += readBitsFromStream(bp, in, 2); if(i < HLIT + 1) value = bitlen_ll[i - 1]; else value = bitlen_d[i - HLIT - 1]; /*repeat this value in the next lengths*/ for(n = 0; n < replength; ++n) { if(i >= HLIT + HDIST) ERROR_BREAK(13); /*error: i is larger than the amount of codes*/ if(i < HLIT) bitlen_ll[i] = value; else bitlen_d[i - HLIT] = value; ++i; } } else if(code == 17) /*repeat "0" 3-10 times*/ { unsigned replength = 3; /*read in the bits that indicate repeat length*/ if((*bp + 3) > inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ replength += readBitsFromStream(bp, in, 3); /*repeat this value in the next lengths*/ for(n = 0; n < replength; ++n) { if(i >= HLIT + HDIST) ERROR_BREAK(14); /*error: i is larger than the amount of codes*/ if(i < HLIT) bitlen_ll[i] = 0; else bitlen_d[i - HLIT] = 0; ++i; } } else if(code == 18) /*repeat "0" 11-138 times*/ { unsigned replength = 11; /*read in the bits that indicate repeat length*/ if((*bp + 7) > inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ replength += readBitsFromStream(bp, in, 7); /*repeat this value in the next lengths*/ for(n = 0; n < replength; ++n) { if(i >= HLIT + HDIST) ERROR_BREAK(15); /*error: i is larger than the amount of codes*/ if(i < HLIT) bitlen_ll[i] = 0; else bitlen_d[i - HLIT] = 0; ++i; } } else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ { if(code == (unsigned)(-1)) { /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol (10=no endcode, 11=wrong jump outside of tree)*/ error = (*bp) > inbitlength ? 10 : 11; } else error = 16; /*unexisting code, this can never happen*/ break; } } if(error) break; if(bitlen_ll[256] == 0) ERROR_BREAK(64); /*the length of the end code 256 must be larger than 0*/ /*now we've finally got HLIT and HDIST, so generate the code trees, and the function is done*/ error = HuffmanTree_makeFromLengths(tree_ll, bitlen_ll, NUM_DEFLATE_CODE_SYMBOLS, 15); if(error) break; error = HuffmanTree_makeFromLengths(tree_d, bitlen_d, NUM_DISTANCE_SYMBOLS, 15); break; /*end of error-while*/ } lodepng_free(bitlen_cl); lodepng_free(bitlen_ll); lodepng_free(bitlen_d); HuffmanTree_cleanup(&tree_cl); return error; } /*inflate a block with dynamic of fixed Huffman tree*/ static unsigned inflateHuffmanBlock(ucvector* out, const unsigned char* in, size_t* bp, size_t* pos, size_t inlength, unsigned btype) { unsigned error = 0; HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/ HuffmanTree tree_d; /*the huffman tree for distance codes*/ size_t inbitlength = inlength * 8; HuffmanTree_init(&tree_ll); HuffmanTree_init(&tree_d); if(btype == 1) getTreeInflateFixed(&tree_ll, &tree_d); else if(btype == 2) error = getTreeInflateDynamic(&tree_ll, &tree_d, in, bp, inlength); while(!error) /*decode all symbols until end reached, breaks at end code*/ { /*code_ll is literal, length or end code*/ unsigned code_ll = huffmanDecodeSymbol(in, bp, &tree_ll, inbitlength); if(code_ll <= 255) /*literal symbol*/ { /*ucvector_push_back would do the same, but for some reason the two lines below run 10% faster*/ if(!ucvector_resize(out, (*pos) + 1)) ERROR_BREAK(83 /*alloc fail*/); out->data[*pos] = (unsigned char)code_ll; ++(*pos); } else if(code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/ { unsigned code_d, distance; unsigned numextrabits_l, numextrabits_d; /*extra bits for length and distance*/ size_t start, forward, backward, length; /*part 1: get length base*/ length = LENGTHBASE[code_ll - FIRST_LENGTH_CODE_INDEX]; /*part 2: get extra bits and add the value of that to length*/ numextrabits_l = LENGTHEXTRA[code_ll - FIRST_LENGTH_CODE_INDEX]; if((*bp + numextrabits_l) > inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/ length += readBitsFromStream(bp, in, numextrabits_l); /*part 3: get distance code*/ code_d = huffmanDecodeSymbol(in, bp, &tree_d, inbitlength); if(code_d > 29) { if(code_ll == (unsigned)(-1)) /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ { /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol (10=no endcode, 11=wrong jump outside of tree)*/ error = (*bp) > inlength * 8 ? 10 : 11; } else error = 18; /*error: invalid distance code (30-31 are never used)*/ break; } distance = DISTANCEBASE[code_d]; /*part 4: get extra bits from distance*/ numextrabits_d = DISTANCEEXTRA[code_d]; if((*bp + numextrabits_d) > inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/ distance += readBitsFromStream(bp, in, numextrabits_d); /*part 5: fill in all the out[n] values based on the length and dist*/ start = (*pos); if(distance > start) ERROR_BREAK(52); /*too long backward distance*/ backward = start - distance; if(!ucvector_resize(out, (*pos) + length)) ERROR_BREAK(83 /*alloc fail*/); for(forward = 0; forward < length; ++forward) { out->data[(*pos)] = out->data[backward]; ++(*pos); ++backward; if(backward >= start) backward = start - distance; } } else if(code_ll == 256) { break; /*end code, break the loop*/ } else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ { /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol (10=no endcode, 11=wrong jump outside of tree)*/ error = ((*bp) > inlength * 8) ? 10 : 11; break; } } HuffmanTree_cleanup(&tree_ll); HuffmanTree_cleanup(&tree_d); return error; } static unsigned inflateNoCompression(ucvector* out, const unsigned char* in, size_t* bp, size_t* pos, size_t inlength) { size_t p; unsigned LEN, NLEN, n, error = 0; /*go to first boundary of byte*/ while(((*bp) & 0x7) != 0) ++(*bp); p = (*bp) / 8; /*byte position*/ /*read LEN (2 bytes) and NLEN (2 bytes)*/ if(p + 4 >= inlength) return 52; /*error, bit pointer will jump past memory*/ LEN = in[p] + 256u * in[p + 1]; p += 2; NLEN = in[p] + 256u * in[p + 1]; p += 2; /*check if 16-bit NLEN is really the one's complement of LEN*/ if(LEN + NLEN != 65535) return 21; /*error: NLEN is not one's complement of LEN*/ if(!ucvector_resize(out, (*pos) + LEN)) return 83; /*alloc fail*/ /*read the literal data: LEN bytes are now stored in the out buffer*/ if(p + LEN > inlength) return 23; /*error: reading outside of in buffer*/ for(n = 0; n < LEN; ++n) out->data[(*pos)++] = in[p++]; (*bp) = p * 8; return error; } static unsigned lodepng_inflatev(ucvector* out, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { /*bit pointer in the "in" data, current byte is bp >> 3, current bit is bp & 0x7 (from lsb to msb of the byte)*/ size_t bp = 0; unsigned BFINAL = 0; size_t pos = 0; /*byte position in the out buffer*/ unsigned error = 0; (void)settings; while(!BFINAL) { unsigned BTYPE; if(bp + 2 >= insize * 8) return 52; /*error, bit pointer will jump past memory*/ BFINAL = readBitFromStream(&bp, in); BTYPE = 1u * readBitFromStream(&bp, in); BTYPE += 2u * readBitFromStream(&bp, in); if(BTYPE == 3) return 20; /*error: invalid BTYPE*/ else if(BTYPE == 0) error = inflateNoCompression(out, in, &bp, &pos, insize); /*no compression*/ else error = inflateHuffmanBlock(out, in, &bp, &pos, insize, BTYPE); /*compression, BTYPE 01 or 10*/ if(error) return error; } return error; } unsigned lodepng_inflate(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { unsigned error; ucvector v; ucvector_init_buffer(&v, *out, *outsize); error = lodepng_inflatev(&v, in, insize, settings); *out = v.data; *outsize = v.size; return error; } static unsigned inflate(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { if(settings->custom_inflate) { return settings->custom_inflate(out, outsize, in, insize, settings); } else { return lodepng_inflate(out, outsize, in, insize, settings); } } #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER /* ////////////////////////////////////////////////////////////////////////// */ /* / Deflator (Compressor) / */ /* ////////////////////////////////////////////////////////////////////////// */ static const size_t MAX_SUPPORTED_DEFLATE_LENGTH = 258; /*bitlen is the size in bits of the code*/ static void addHuffmanSymbol(size_t* bp, ucvector* compressed, unsigned code, unsigned bitlen) { addBitsToStreamReversed(bp, compressed, code, bitlen); } /*search the index in the array, that has the largest value smaller than or equal to the given value, given array must be sorted (if no value is smaller, it returns the size of the given array)*/ static size_t searchCodeIndex(const unsigned* array, size_t array_size, size_t value) { /*linear search implementation*/ /*for(size_t i = 1; i < array_size; ++i) if(array[i] > value) return i - 1; return array_size - 1;*/ /*binary search implementation (not that much faster) (precondition: array_size > 0)*/ size_t left = 1; size_t right = array_size - 1; while(left <= right) { size_t mid = (left + right) / 2; if(array[mid] <= value) left = mid + 1; /*the value to find is more to the right*/ else if(array[mid - 1] > value) right = mid - 1; /*the value to find is more to the left*/ else return mid - 1; } return array_size - 1; } static void addLengthDistance(uivector* values, size_t length, size_t distance) { /*values in encoded vector are those used by deflate: 0-255: literal bytes 256: end 257-285: length/distance pair (length code, followed by extra length bits, distance code, extra distance bits) 286-287: invalid*/ unsigned length_code = (unsigned)searchCodeIndex(LENGTHBASE, 29, length); unsigned extra_length = (unsigned)(length - LENGTHBASE[length_code]); unsigned dist_code = (unsigned)searchCodeIndex(DISTANCEBASE, 30, distance); unsigned extra_distance = (unsigned)(distance - DISTANCEBASE[dist_code]); uivector_push_back(values, length_code + FIRST_LENGTH_CODE_INDEX); uivector_push_back(values, extra_length); uivector_push_back(values, dist_code); uivector_push_back(values, extra_distance); } /*3 bytes of data get encoded into two bytes. The hash cannot use more than 3 bytes as input because 3 is the minimum match length for deflate*/ static const unsigned HASH_NUM_VALUES = 65536; static const unsigned HASH_BIT_MASK = 65535; /*HASH_NUM_VALUES - 1, but C90 does not like that as initializer*/ typedef struct Hash { int* head; /*hash value to head circular pos - can be outdated if went around window*/ /*circular pos to prev circular pos*/ unsigned short* chain; int* val; /*circular pos to hash value*/ /*TODO: do this not only for zeros but for any repeated byte. However for PNG it's always going to be the zeros that dominate, so not important for PNG*/ int* headz; /*similar to head, but for chainz*/ unsigned short* chainz; /*those with same amount of zeros*/ unsigned short* zeros; /*length of zeros streak, used as a second hash chain*/ } Hash; static unsigned hash_init(Hash* hash, unsigned windowsize) { unsigned i; hash->head = (int*)lodepng_malloc(sizeof(int) * HASH_NUM_VALUES); hash->val = (int*)lodepng_malloc(sizeof(int) * windowsize); hash->chain = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); hash->zeros = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); hash->headz = (int*)lodepng_malloc(sizeof(int) * (MAX_SUPPORTED_DEFLATE_LENGTH + 1)); hash->chainz = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); if(!hash->head || !hash->chain || !hash->val || !hash->headz|| !hash->chainz || !hash->zeros) { return 83; /*alloc fail*/ } /*initialize hash table*/ for(i = 0; i != HASH_NUM_VALUES; ++i) hash->head[i] = -1; for(i = 0; i != windowsize; ++i) hash->val[i] = -1; for(i = 0; i != windowsize; ++i) hash->chain[i] = i; /*same value as index indicates uninitialized*/ for(i = 0; i <= MAX_SUPPORTED_DEFLATE_LENGTH; ++i) hash->headz[i] = -1; for(i = 0; i != windowsize; ++i) hash->chainz[i] = i; /*same value as index indicates uninitialized*/ return 0; } static void hash_cleanup(Hash* hash) { lodepng_free(hash->head); lodepng_free(hash->val); lodepng_free(hash->chain); lodepng_free(hash->zeros); lodepng_free(hash->headz); lodepng_free(hash->chainz); } static unsigned getHash(const unsigned char* data, size_t size, size_t pos) { unsigned result = 0; if (pos + 2 < size) { /*A simple shift and xor hash is used. Since the data of PNGs is dominated by zeroes due to the filters, a better hash does not have a significant effect on speed in traversing the chain, and causes more time spend on calculating the hash.*/ result ^= (unsigned)(data[pos + 0] << 0u); result ^= (unsigned)(data[pos + 1] << 4u); result ^= (unsigned)(data[pos + 2] << 8u); } else { size_t amount, i; if(pos >= size) return 0; amount = size - pos; for(i = 0; i != amount; ++i) result ^= (unsigned)(data[pos + i] << (i * 8u)); } return result & HASH_BIT_MASK; } static unsigned countZeros(const unsigned char* data, size_t size, size_t pos) { const unsigned char* start = data + pos; const unsigned char* end = start + MAX_SUPPORTED_DEFLATE_LENGTH; if(end > data + size) end = data + size; data = start; while (data != end && *data == 0) ++data; /*subtracting two addresses returned as 32-bit number (max value is MAX_SUPPORTED_DEFLATE_LENGTH)*/ return (unsigned)(data - start); } /*wpos = pos & (windowsize - 1)*/ static void updateHashChain(Hash* hash, size_t wpos, unsigned hashval, unsigned short numzeros) { hash->val[wpos] = (int)hashval; if(hash->head[hashval] != -1) hash->chain[wpos] = hash->head[hashval]; hash->head[hashval] = wpos; hash->zeros[wpos] = numzeros; if(hash->headz[numzeros] != -1) hash->chainz[wpos] = hash->headz[numzeros]; hash->headz[numzeros] = wpos; } /* LZ77-encode the data. Return value is error code. The input are raw bytes, the output is in the form of unsigned integers with codes representing for example literal bytes, or length/distance pairs. It uses a hash table technique to let it encode faster. When doing LZ77 encoding, a sliding window (of windowsize) is used, and all past bytes in that window can be used as the "dictionary". A brute force search through all possible distances would be slow, and this hash technique is one out of several ways to speed this up. */ static unsigned encodeLZ77(uivector* out, Hash* hash, const unsigned char* in, size_t inpos, size_t insize, unsigned windowsize, unsigned minmatch, unsigned nicematch, unsigned lazymatching) { size_t pos; unsigned i, error = 0; /*for large window lengths, assume the user wants no compression loss. Otherwise, max hash chain length speedup.*/ unsigned maxchainlength = windowsize >= 8192 ? windowsize : windowsize / 8; unsigned maxlazymatch = windowsize >= 8192 ? MAX_SUPPORTED_DEFLATE_LENGTH : 64; unsigned usezeros = 1; /*not sure if setting it to false for windowsize < 8192 is better or worse*/ unsigned numzeros = 0; unsigned offset; /*the offset represents the distance in LZ77 terminology*/ unsigned length; unsigned lazy = 0; unsigned lazylength = 0, lazyoffset = 0; unsigned hashval; unsigned current_offset, current_length; unsigned prev_offset; const unsigned char *lastptr, *foreptr, *backptr; unsigned hashpos; if(windowsize == 0 || windowsize > 32768) return 60; /*error: windowsize smaller/larger than allowed*/ if((windowsize & (windowsize - 1)) != 0) return 90; /*error: must be power of two*/ if(nicematch > MAX_SUPPORTED_DEFLATE_LENGTH) nicematch = MAX_SUPPORTED_DEFLATE_LENGTH; for(pos = inpos; pos < insize; ++pos) { size_t wpos = pos & (windowsize - 1); /*position for in 'circular' hash buffers*/ unsigned chainlength = 0; hashval = getHash(in, insize, pos); if(usezeros && hashval == 0) { if (numzeros == 0) numzeros = countZeros(in, insize, pos); else if (pos + numzeros > insize || in[pos + numzeros - 1] != 0) --numzeros; } else { numzeros = 0; } updateHashChain(hash, wpos, hashval, numzeros); /*the length and offset found for the current position*/ length = 0; offset = 0; hashpos = hash->chain[wpos]; lastptr = &in[insize < pos + MAX_SUPPORTED_DEFLATE_LENGTH ? insize : pos + MAX_SUPPORTED_DEFLATE_LENGTH]; /*search for the longest string*/ prev_offset = 0; for(;;) { if(chainlength++ >= maxchainlength) break; current_offset = hashpos <= wpos ? wpos - hashpos : wpos - hashpos + windowsize; if(current_offset < prev_offset) break; /*stop when went completely around the circular buffer*/ prev_offset = current_offset; if(current_offset > 0) { /*test the next characters*/ foreptr = &in[pos]; backptr = &in[pos - current_offset]; /*common case in PNGs is lots of zeros. Quickly skip over them as a speedup*/ if(numzeros >= 3) { unsigned skip = hash->zeros[hashpos]; if(skip > numzeros) skip = numzeros; backptr += skip; foreptr += skip; } while(foreptr != lastptr && *backptr == *foreptr) /*maximum supported length by deflate is max length*/ { ++backptr; ++foreptr; } current_length = (unsigned)(foreptr - &in[pos]); if(current_length > length) { length = current_length; /*the longest length*/ offset = current_offset; /*the offset that is related to this longest length*/ /*jump out once a length of max length is found (speed gain). This also jumps out if length is MAX_SUPPORTED_DEFLATE_LENGTH*/ if(current_length >= nicematch) break; } } if(hashpos == hash->chain[hashpos]) break; if(numzeros >= 3 && length > numzeros) { hashpos = hash->chainz[hashpos]; if(hash->zeros[hashpos] != numzeros) break; } else { hashpos = hash->chain[hashpos]; /*outdated hash value, happens if particular value was not encountered in whole last window*/ if(hash->val[hashpos] != (int)hashval) break; } } if(lazymatching) { if(!lazy && length >= 3 && length <= maxlazymatch && length < MAX_SUPPORTED_DEFLATE_LENGTH) { lazy = 1; lazylength = length; lazyoffset = offset; continue; /*try the next byte*/ } if(lazy) { lazy = 0; if(pos == 0) ERROR_BREAK(81); if(length > lazylength + 1) { /*push the previous character as literal*/ if(!uivector_push_back(out, in[pos - 1])) ERROR_BREAK(83 /*alloc fail*/); } else { length = lazylength; offset = lazyoffset; hash->head[hashval] = -1; /*the same hashchain update will be done, this ensures no wrong alteration*/ hash->headz[numzeros] = -1; /*idem*/ --pos; } } } if(length >= 3 && offset > windowsize) ERROR_BREAK(86 /*too big (or overflown negative) offset*/); /*encode it as length/distance pair or literal value*/ if(length < 3) /*only lengths of 3 or higher are supported as length/distance pair*/ { if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/); } else if(length < minmatch || (length == 3 && offset > 4096)) { /*compensate for the fact that longer offsets have more extra bits, a length of only 3 may be not worth it then*/ if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/); } else { addLengthDistance(out, length, offset); for(i = 1; i < length; ++i) { ++pos; wpos = pos & (windowsize - 1); hashval = getHash(in, insize, pos); if(usezeros && hashval == 0) { if (numzeros == 0) numzeros = countZeros(in, insize, pos); else if (pos + numzeros > insize || in[pos + numzeros - 1] != 0) --numzeros; } else { numzeros = 0; } updateHashChain(hash, wpos, hashval, numzeros); } } } /*end of the loop through each character of input*/ return error; } /* /////////////////////////////////////////////////////////////////////////// */ static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, size_t datasize) { /*non compressed deflate block data: 1 bit BFINAL,2 bits BTYPE,(5 bits): it jumps to start of next byte, 2 bytes LEN, 2 bytes NLEN, LEN bytes literal DATA*/ size_t i, j, numdeflateblocks = (datasize + 65534) / 65535; unsigned datapos = 0; for(i = 0; i != numdeflateblocks; ++i) { unsigned BFINAL, BTYPE, LEN, NLEN; unsigned char firstbyte; BFINAL = (i == numdeflateblocks - 1); BTYPE = 0; firstbyte = (unsigned char)(BFINAL + ((BTYPE & 1) << 1) + ((BTYPE & 2) << 1)); ucvector_push_back(out, firstbyte); LEN = 65535; if(datasize - datapos < 65535) LEN = (unsigned)datasize - datapos; NLEN = 65535 - LEN; ucvector_push_back(out, (unsigned char)(LEN % 256)); ucvector_push_back(out, (unsigned char)(LEN / 256)); ucvector_push_back(out, (unsigned char)(NLEN % 256)); ucvector_push_back(out, (unsigned char)(NLEN / 256)); /*Decompressed data*/ for(j = 0; j < 65535 && datapos < datasize; ++j) { ucvector_push_back(out, data[datapos++]); } } return 0; } /* write the lz77-encoded data, which has lit, len and dist codes, to compressed stream using huffman trees. tree_ll: the tree for lit and len codes. tree_d: the tree for distance codes. */ static void writeLZ77data(size_t* bp, ucvector* out, const uivector* lz77_encoded, const HuffmanTree* tree_ll, const HuffmanTree* tree_d) { size_t i = 0; for(i = 0; i != lz77_encoded->size; ++i) { unsigned val = lz77_encoded->data[i]; addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_ll, val), HuffmanTree_getLength(tree_ll, val)); if(val > 256) /*for a length code, 3 more things have to be added*/ { unsigned length_index = val - FIRST_LENGTH_CODE_INDEX; unsigned n_length_extra_bits = LENGTHEXTRA[length_index]; unsigned length_extra_bits = lz77_encoded->data[++i]; unsigned distance_code = lz77_encoded->data[++i]; unsigned distance_index = distance_code; unsigned n_distance_extra_bits = DISTANCEEXTRA[distance_index]; unsigned distance_extra_bits = lz77_encoded->data[++i]; addBitsToStream(bp, out, length_extra_bits, n_length_extra_bits); addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_d, distance_code), HuffmanTree_getLength(tree_d, distance_code)); addBitsToStream(bp, out, distance_extra_bits, n_distance_extra_bits); } } } /*Deflate for a block of type "dynamic", that is, with freely, optimally, created huffman trees*/ static unsigned deflateDynamic(ucvector* out, size_t* bp, Hash* hash, const unsigned char* data, size_t datapos, size_t dataend, const LodePNGCompressSettings* settings, unsigned final) { unsigned error = 0; /* A block is compressed as follows: The PNG data is lz77 encoded, resulting in literal bytes and length/distance pairs. This is then huffman compressed with two huffman trees. One huffman tree is used for the lit and len values ("ll"), another huffman tree is used for the dist values ("d"). These two trees are stored using their code lengths, and to compress even more these code lengths are also run-length encoded and huffman compressed. This gives a huffman tree of code lengths "cl". The code lenghts used to describe this third tree are the code length code lengths ("clcl"). */ /*The lz77 encoded data, represented with integers since there will also be length and distance codes in it*/ uivector lz77_encoded; HuffmanTree tree_ll; /*tree for lit,len values*/ HuffmanTree tree_d; /*tree for distance codes*/ HuffmanTree tree_cl; /*tree for encoding the code lengths representing tree_ll and tree_d*/ uivector frequencies_ll; /*frequency of lit,len codes*/ uivector frequencies_d; /*frequency of dist codes*/ uivector frequencies_cl; /*frequency of code length codes*/ uivector bitlen_lld; /*lit,len,dist code lenghts (int bits), literally (without repeat codes).*/ uivector bitlen_lld_e; /*bitlen_lld encoded with repeat codes (this is a rudemtary run length compression)*/ /*bitlen_cl is the code length code lengths ("clcl"). The bit lengths of codes to represent tree_cl (these are written as is in the file, it would be crazy to compress these using yet another huffman tree that needs to be represented by yet another set of code lengths)*/ uivector bitlen_cl; size_t datasize = dataend - datapos; /* Due to the huffman compression of huffman tree representations ("two levels"), there are some anologies: bitlen_lld is to tree_cl what data is to tree_ll and tree_d. bitlen_lld_e is to bitlen_lld what lz77_encoded is to data. bitlen_cl is to bitlen_lld_e what bitlen_lld is to lz77_encoded. */ unsigned BFINAL = final; size_t numcodes_ll, numcodes_d, i; unsigned HLIT, HDIST, HCLEN; uivector_init(&lz77_encoded); HuffmanTree_init(&tree_ll); HuffmanTree_init(&tree_d); HuffmanTree_init(&tree_cl); uivector_init(&frequencies_ll); uivector_init(&frequencies_d); uivector_init(&frequencies_cl); uivector_init(&bitlen_lld); uivector_init(&bitlen_lld_e); uivector_init(&bitlen_cl); /*This while loop never loops due to a break at the end, it is here to allow breaking out of it to the cleanup phase on error conditions.*/ while(!error) { if(settings->use_lz77) { error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize, settings->minmatch, settings->nicematch, settings->lazymatching); if(error) break; } else { if(!uivector_resize(&lz77_encoded, datasize)) ERROR_BREAK(83 /*alloc fail*/); for(i = datapos; i < dataend; ++i) lz77_encoded.data[i] = data[i]; /*no LZ77, but still will be Huffman compressed*/ } if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83 /*alloc fail*/); if(!uivector_resizev(&frequencies_d, 30, 0)) ERROR_BREAK(83 /*alloc fail*/); /*Count the frequencies of lit, len and dist codes*/ for(i = 0; i != lz77_encoded.size; ++i) { unsigned symbol = lz77_encoded.data[i]; ++frequencies_ll.data[symbol]; if(symbol > 256) { unsigned dist = lz77_encoded.data[i + 2]; ++frequencies_d.data[dist]; i += 3; } } frequencies_ll.data[256] = 1; /*there will be exactly 1 end code, at the end of the block*/ /*Make both huffman trees, one for the lit and len codes, one for the dist codes*/ error = HuffmanTree_makeFromFrequencies(&tree_ll, frequencies_ll.data, 257, frequencies_ll.size, 15); if(error) break; /*2, not 1, is chosen for mincodes: some buggy PNG decoders require at least 2 symbols in the dist tree*/ error = HuffmanTree_makeFromFrequencies(&tree_d, frequencies_d.data, 2, frequencies_d.size, 15); if(error) break; numcodes_ll = tree_ll.numcodes; if(numcodes_ll > 286) numcodes_ll = 286; numcodes_d = tree_d.numcodes; if(numcodes_d > 30) numcodes_d = 30; /*store the code lengths of both generated trees in bitlen_lld*/ for(i = 0; i != numcodes_ll; ++i) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_ll, (unsigned)i)); for(i = 0; i != numcodes_d; ++i) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_d, (unsigned)i)); /*run-length compress bitlen_ldd into bitlen_lld_e by using repeat codes 16 (copy length 3-6 times), 17 (3-10 zeroes), 18 (11-138 zeroes)*/ for(i = 0; i != (unsigned)bitlen_lld.size; ++i) { unsigned j = 0; /*amount of repititions*/ while(i + j + 1 < (unsigned)bitlen_lld.size && bitlen_lld.data[i + j + 1] == bitlen_lld.data[i]) ++j; if(bitlen_lld.data[i] == 0 && j >= 2) /*repeat code for zeroes*/ { ++j; /*include the first zero*/ if(j <= 10) /*repeat code 17 supports max 10 zeroes*/ { uivector_push_back(&bitlen_lld_e, 17); uivector_push_back(&bitlen_lld_e, j - 3); } else /*repeat code 18 supports max 138 zeroes*/ { if(j > 138) j = 138; uivector_push_back(&bitlen_lld_e, 18); uivector_push_back(&bitlen_lld_e, j - 11); } i += (j - 1); } else if(j >= 3) /*repeat code for value other than zero*/ { size_t k; unsigned num = j / 6, rest = j % 6; uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]); for(k = 0; k < num; ++k) { uivector_push_back(&bitlen_lld_e, 16); uivector_push_back(&bitlen_lld_e, 6 - 3); } if(rest >= 3) { uivector_push_back(&bitlen_lld_e, 16); uivector_push_back(&bitlen_lld_e, rest - 3); } else j -= rest; i += j; } else /*too short to benefit from repeat code*/ { uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]); } } /*generate tree_cl, the huffmantree of huffmantrees*/ if(!uivector_resizev(&frequencies_cl, NUM_CODE_LENGTH_CODES, 0)) ERROR_BREAK(83 /*alloc fail*/); for(i = 0; i != bitlen_lld_e.size; ++i) { ++frequencies_cl.data[bitlen_lld_e.data[i]]; /*after a repeat code come the bits that specify the number of repetitions, those don't need to be in the frequencies_cl calculation*/ if(bitlen_lld_e.data[i] >= 16) ++i; } error = HuffmanTree_makeFromFrequencies(&tree_cl, frequencies_cl.data, frequencies_cl.size, frequencies_cl.size, 7); if(error) break; if(!uivector_resize(&bitlen_cl, tree_cl.numcodes)) ERROR_BREAK(83 /*alloc fail*/); for(i = 0; i != tree_cl.numcodes; ++i) { /*lenghts of code length tree is in the order as specified by deflate*/ bitlen_cl.data[i] = HuffmanTree_getLength(&tree_cl, CLCL_ORDER[i]); } while(bitlen_cl.data[bitlen_cl.size - 1] == 0 && bitlen_cl.size > 4) { /*remove zeros at the end, but minimum size must be 4*/ if(!uivector_resize(&bitlen_cl, bitlen_cl.size - 1)) ERROR_BREAK(83 /*alloc fail*/); } if(error) break; /* Write everything into the output After the BFINAL and BTYPE, the dynamic block consists out of the following: - 5 bits HLIT, 5 bits HDIST, 4 bits HCLEN - (HCLEN+4)*3 bits code lengths of code length alphabet - HLIT + 257 code lenghts of lit/length alphabet (encoded using the code length alphabet, + possible repetition codes 16, 17, 18) - HDIST + 1 code lengths of distance alphabet (encoded using the code length alphabet, + possible repetition codes 16, 17, 18) - compressed data - 256 (end code) */ /*Write block type*/ addBitToStream(bp, out, BFINAL); addBitToStream(bp, out, 0); /*first bit of BTYPE "dynamic"*/ addBitToStream(bp, out, 1); /*second bit of BTYPE "dynamic"*/ /*write the HLIT, HDIST and HCLEN values*/ HLIT = (unsigned)(numcodes_ll - 257); HDIST = (unsigned)(numcodes_d - 1); HCLEN = (unsigned)bitlen_cl.size - 4; /*trim zeroes for HCLEN. HLIT and HDIST were already trimmed at tree creation*/ while(!bitlen_cl.data[HCLEN + 4 - 1] && HCLEN > 0) --HCLEN; addBitsToStream(bp, out, HLIT, 5); addBitsToStream(bp, out, HDIST, 5); addBitsToStream(bp, out, HCLEN, 4); /*write the code lenghts of the code length alphabet*/ for(i = 0; i != HCLEN + 4; ++i) addBitsToStream(bp, out, bitlen_cl.data[i], 3); /*write the lenghts of the lit/len AND the dist alphabet*/ for(i = 0; i != bitlen_lld_e.size; ++i) { addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_cl, bitlen_lld_e.data[i]), HuffmanTree_getLength(&tree_cl, bitlen_lld_e.data[i])); /*extra bits of repeat codes*/ if(bitlen_lld_e.data[i] == 16) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 2); else if(bitlen_lld_e.data[i] == 17) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 3); else if(bitlen_lld_e.data[i] == 18) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 7); } /*write the compressed data symbols*/ writeLZ77data(bp, out, &lz77_encoded, &tree_ll, &tree_d); /*error: the length of the end code 256 must be larger than 0*/ if(HuffmanTree_getLength(&tree_ll, 256) == 0) ERROR_BREAK(64); /*write the end code*/ addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, 256), HuffmanTree_getLength(&tree_ll, 256)); break; /*end of error-while*/ } /*cleanup*/ uivector_cleanup(&lz77_encoded); HuffmanTree_cleanup(&tree_ll); HuffmanTree_cleanup(&tree_d); HuffmanTree_cleanup(&tree_cl); uivector_cleanup(&frequencies_ll); uivector_cleanup(&frequencies_d); uivector_cleanup(&frequencies_cl); uivector_cleanup(&bitlen_lld_e); uivector_cleanup(&bitlen_lld); uivector_cleanup(&bitlen_cl); return error; } static unsigned deflateFixed(ucvector* out, size_t* bp, Hash* hash, const unsigned char* data, size_t datapos, size_t dataend, const LodePNGCompressSettings* settings, unsigned final) { HuffmanTree tree_ll; /*tree for literal values and length codes*/ HuffmanTree tree_d; /*tree for distance codes*/ unsigned BFINAL = final; unsigned error = 0; size_t i; HuffmanTree_init(&tree_ll); HuffmanTree_init(&tree_d); generateFixedLitLenTree(&tree_ll); generateFixedDistanceTree(&tree_d); addBitToStream(bp, out, BFINAL); addBitToStream(bp, out, 1); /*first bit of BTYPE*/ addBitToStream(bp, out, 0); /*second bit of BTYPE*/ if(settings->use_lz77) /*LZ77 encoded*/ { uivector lz77_encoded; uivector_init(&lz77_encoded); error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize, settings->minmatch, settings->nicematch, settings->lazymatching); if(!error) writeLZ77data(bp, out, &lz77_encoded, &tree_ll, &tree_d); uivector_cleanup(&lz77_encoded); } else /*no LZ77, but still will be Huffman compressed*/ { for(i = datapos; i < dataend; ++i) { addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, data[i]), HuffmanTree_getLength(&tree_ll, data[i])); } } /*add END code*/ if(!error) addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, 256), HuffmanTree_getLength(&tree_ll, 256)); /*cleanup*/ HuffmanTree_cleanup(&tree_ll); HuffmanTree_cleanup(&tree_d); return error; } static unsigned lodepng_deflatev(ucvector* out, const unsigned char* in, size_t insize, const LodePNGCompressSettings* settings) { unsigned error = 0; size_t i, blocksize, numdeflateblocks; size_t bp = 0; /*the bit pointer*/ Hash hash; if(settings->btype > 2) return 61; else if(settings->btype == 0) return deflateNoCompression(out, in, insize); else if(settings->btype == 1) blocksize = insize; else /*if(settings->btype == 2)*/ { blocksize = insize / 8 + 8; if(blocksize < 65535) blocksize = 65535; } numdeflateblocks = (insize + blocksize - 1) / blocksize; if(numdeflateblocks == 0) numdeflateblocks = 1; error = hash_init(&hash, settings->windowsize); if(error) return error; for(i = 0; i != numdeflateblocks && !error; ++i) { unsigned final = (i == numdeflateblocks - 1); size_t start = i * blocksize; size_t end = start + blocksize; if(end > insize) end = insize; if(settings->btype == 1) error = deflateFixed(out, &bp, &hash, in, start, end, settings, final); else if(settings->btype == 2) error = deflateDynamic(out, &bp, &hash, in, start, end, settings, final); } hash_cleanup(&hash); return error; } unsigned lodepng_deflate(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGCompressSettings* settings) { unsigned error; ucvector v; ucvector_init_buffer(&v, *out, *outsize); error = lodepng_deflatev(&v, in, insize, settings); *out = v.data; *outsize = v.size; return error; } static unsigned deflate(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGCompressSettings* settings) { if(settings->custom_deflate) { return settings->custom_deflate(out, outsize, in, insize, settings); } else { return lodepng_deflate(out, outsize, in, insize, settings); } } #endif /*LODEPNG_COMPILE_DECODER*/ /* ////////////////////////////////////////////////////////////////////////// */ /* / Adler32 */ /* ////////////////////////////////////////////////////////////////////////// */ static unsigned update_adler32(unsigned adler, const unsigned char* data, unsigned len) { unsigned s1 = adler & 0xffff; unsigned s2 = (adler >> 16) & 0xffff; while(len > 0) { /*at least 5550 sums can be done before the sums overflow, saving a lot of module divisions*/ unsigned amount = len > 5550 ? 5550 : len; len -= amount; while(amount > 0) { s1 += (*data++); s2 += s1; --amount; } s1 %= 65521; s2 %= 65521; } return (s2 << 16) | s1; } /*Return the adler32 of the bytes data[0..len-1]*/ static unsigned adler32(const unsigned char* data, unsigned len) { return update_adler32(1L, data, len); } /* ////////////////////////////////////////////////////////////////////////// */ /* / Zlib / */ /* ////////////////////////////////////////////////////////////////////////// */ #ifdef LODEPNG_COMPILE_DECODER unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { unsigned error = 0; unsigned CM, CINFO, FDICT; if(insize < 2) return 53; /*error, size of zlib data too small*/ /*read information from zlib header*/ if((in[0] * 256 + in[1]) % 31 != 0) { /*error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way*/ return 24; } CM = in[0] & 15; CINFO = (in[0] >> 4) & 15; /*FCHECK = in[1] & 31;*/ /*FCHECK is already tested above*/ FDICT = (in[1] >> 5) & 1; /*FLEVEL = (in[1] >> 6) & 3;*/ /*FLEVEL is not used here*/ if(CM != 8 || CINFO > 7) { /*error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec*/ return 25; } if(FDICT != 0) { /*error: the specification of PNG says about the zlib stream: "The additional flags shall not specify a preset dictionary."*/ return 26; } error = inflate(out, outsize, in + 2, insize - 2, settings); if(error) return error; if(!settings->ignore_adler32) { unsigned ADLER32 = lodepng_read32bitInt(&in[insize - 4]); unsigned checksum = adler32(*out, (unsigned)(*outsize)); if(checksum != ADLER32) return 58; /*error, adler checksum not correct, data must be corrupted*/ } return 0; /*no error*/ } static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { if(settings->custom_zlib) { return settings->custom_zlib(out, outsize, in, insize, settings); } else { return lodepng_zlib_decompress(out, outsize, in, insize, settings); } } #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGCompressSettings* settings) { /*initially, *out must be NULL and outsize 0, if you just give some random *out that's pointing to a non allocated buffer, this'll crash*/ ucvector outv; size_t i; unsigned error; unsigned char* deflatedata = 0; size_t deflatesize = 0; /*zlib data: 1 byte CMF (CM+CINFO), 1 byte FLG, deflate data, 4 byte ADLER32 checksum of the Decompressed data*/ unsigned CMF = 120; /*0b01111000: CM 8, CINFO 7. With CINFO 7, any window size up to 32768 can be used.*/ unsigned FLEVEL = 0; unsigned FDICT = 0; unsigned CMFFLG = 256 * CMF + FDICT * 32 + FLEVEL * 64; unsigned FCHECK = 31 - CMFFLG % 31; CMFFLG += FCHECK; /*ucvector-controlled version of the output buffer, for dynamic array*/ ucvector_init_buffer(&outv, *out, *outsize); ucvector_push_back(&outv, (unsigned char)(CMFFLG / 256)); ucvector_push_back(&outv, (unsigned char)(CMFFLG % 256)); error = deflate(&deflatedata, &deflatesize, in, insize, settings); if(!error) { unsigned ADLER32 = adler32(in, (unsigned)insize); for(i = 0; i != deflatesize; ++i) ucvector_push_back(&outv, deflatedata[i]); lodepng_free(deflatedata); lodepng_add32bitInt(&outv, ADLER32); } *out = outv.data; *outsize = outv.size; return error; } /* compress using the default or custom zlib function */ static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGCompressSettings* settings) { if(settings->custom_zlib) { return settings->custom_zlib(out, outsize, in, insize, settings); } else { return lodepng_zlib_compress(out, outsize, in, insize, settings); } } #endif /*LODEPNG_COMPILE_ENCODER*/ #else /*no LODEPNG_COMPILE_ZLIB*/ #ifdef LODEPNG_COMPILE_DECODER static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { if (!settings->custom_zlib) return 87; /*no custom zlib function provided */ return settings->custom_zlib(out, outsize, in, insize, settings); } #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGCompressSettings* settings) { if (!settings->custom_zlib) return 87; /*no custom zlib function provided */ return settings->custom_zlib(out, outsize, in, insize, settings); } #endif /*LODEPNG_COMPILE_ENCODER*/ #endif /*LODEPNG_COMPILE_ZLIB*/ /* ////////////////////////////////////////////////////////////////////////// */ #ifdef LODEPNG_COMPILE_ENCODER /*this is a good tradeoff between speed and compression ratio*/ #define DEFAULT_WINDOWSIZE 2048 void lodepng_compress_settings_init(LodePNGCompressSettings* settings) { /*compress with dynamic huffman tree (not in the mathematical sense, just not the predefined one)*/ settings->btype = 2; settings->use_lz77 = 1; settings->windowsize = DEFAULT_WINDOWSIZE; settings->minmatch = 3; settings->nicematch = 128; settings->lazymatching = 1; settings->custom_zlib = 0; settings->custom_deflate = 0; settings->custom_context = 0; } const LodePNGCompressSettings lodepng_default_compress_settings = {2, 1, DEFAULT_WINDOWSIZE, 3, 128, 1, 0, 0, 0}; #endif /*LODEPNG_COMPILE_ENCODER*/ #ifdef LODEPNG_COMPILE_DECODER void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings) { settings->ignore_adler32 = 0; settings->custom_zlib = 0; settings->custom_inflate = 0; settings->custom_context = 0; } const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, 0}; #endif /*LODEPNG_COMPILE_DECODER*/ /* ////////////////////////////////////////////////////////////////////////// */ /* ////////////////////////////////////////////////////////////////////////// */ /* // End of Zlib related code. Begin of PNG related code. // */ /* ////////////////////////////////////////////////////////////////////////// */ /* ////////////////////////////////////////////////////////////////////////// */ #ifdef LODEPNG_COMPILE_PNG /* ////////////////////////////////////////////////////////////////////////// */ /* / CRC32 / */ /* ////////////////////////////////////////////////////////////////////////// */ /* CRC polynomial: 0xedb88320 */ static unsigned lodepng_crc32_table[256] = { 0u, 1996959894u, 3993919788u, 2567524794u, 124634137u, 1886057615u, 3915621685u, 2657392035u, 249268274u, 2044508324u, 3772115230u, 2547177864u, 162941995u, 2125561021u, 3887607047u, 2428444049u, 498536548u, 1789927666u, 4089016648u, 2227061214u, 450548861u, 1843258603u, 4107580753u, 2211677639u, 325883990u, 1684777152u, 4251122042u, 2321926636u, 335633487u, 1661365465u, 4195302755u, 2366115317u, 997073096u, 1281953886u, 3579855332u, 2724688242u, 1006888145u, 1258607687u, 3524101629u, 2768942443u, 901097722u, 1119000684u, 3686517206u, 2898065728u, 853044451u, 1172266101u, 3705015759u, 2882616665u, 651767980u, 1373503546u, 3369554304u, 3218104598u, 565507253u, 1454621731u, 3485111705u, 3099436303u, 671266974u, 1594198024u, 3322730930u, 2970347812u, 795835527u, 1483230225u, 3244367275u, 3060149565u, 1994146192u, 31158534u, 2563907772u, 4023717930u, 1907459465u, 112637215u, 2680153253u, 3904427059u, 2013776290u, 251722036u, 2517215374u, 3775830040u, 2137656763u, 141376813u, 2439277719u, 3865271297u, 1802195444u, 476864866u, 2238001368u, 4066508878u, 1812370925u, 453092731u, 2181625025u, 4111451223u, 1706088902u, 314042704u, 2344532202u, 4240017532u, 1658658271u, 366619977u, 2362670323u, 4224994405u, 1303535960u, 984961486u, 2747007092u, 3569037538u, 1256170817u, 1037604311u, 2765210733u, 3554079995u, 1131014506u, 879679996u, 2909243462u, 3663771856u, 1141124467u, 855842277u, 2852801631u, 3708648649u, 1342533948u, 654459306u, 3188396048u, 3373015174u, 1466479909u, 544179635u, 3110523913u, 3462522015u, 1591671054u, 702138776u, 2966460450u, 3352799412u, 1504918807u, 783551873u, 3082640443u, 3233442989u, 3988292384u, 2596254646u, 62317068u, 1957810842u, 3939845945u, 2647816111u, 81470997u, 1943803523u, 3814918930u, 2489596804u, 225274430u, 2053790376u, 3826175755u, 2466906013u, 167816743u, 2097651377u, 4027552580u, 2265490386u, 503444072u, 1762050814u, 4150417245u, 2154129355u, 426522225u, 1852507879u, 4275313526u, 2312317920u, 282753626u, 1742555852u, 4189708143u, 2394877945u, 397917763u, 1622183637u, 3604390888u, 2714866558u, 953729732u, 1340076626u, 3518719985u, 2797360999u, 1068828381u, 1219638859u, 3624741850u, 2936675148u, 906185462u, 1090812512u, 3747672003u, 2825379669u, 829329135u, 1181335161u, 3412177804u, 3160834842u, 628085408u, 1382605366u, 3423369109u, 3138078467u, 570562233u, 1426400815u, 3317316542u, 2998733608u, 733239954u, 1555261956u, 3268935591u, 3050360625u, 752459403u, 1541320221u, 2607071920u, 3965973030u, 1969922972u, 40735498u, 2617837225u, 3943577151u, 1913087877u, 83908371u, 2512341634u, 3803740692u, 2075208622u, 213261112u, 2463272603u, 3855990285u, 2094854071u, 198958881u, 2262029012u, 4057260610u, 1759359992u, 534414190u, 2176718541u, 4139329115u, 1873836001u, 414664567u, 2282248934u, 4279200368u, 1711684554u, 285281116u, 2405801727u, 4167216745u, 1634467795u, 376229701u, 2685067896u, 3608007406u, 1308918612u, 956543938u, 2808555105u, 3495958263u, 1231636301u, 1047427035u, 2932959818u, 3654703836u, 1088359270u, 936918000u, 2847714899u, 3736837829u, 1202900863u, 817233897u, 3183342108u, 3401237130u, 1404277552u, 615818150u, 3134207493u, 3453421203u, 1423857449u, 601450431u, 3009837614u, 3294710456u, 1567103746u, 711928724u, 3020668471u, 3272380065u, 1510334235u, 755167117u }; /*Return the CRC of the bytes buf[0..len-1].*/ unsigned lodepng_crc32(const unsigned char* buf, size_t len) { unsigned c = 0xffffffffL; size_t n; for(n = 0; n < len; ++n) { c = lodepng_crc32_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); } return c ^ 0xffffffffL; } /* ////////////////////////////////////////////////////////////////////////// */ /* / Reading and writing single bits and bytes from/to stream for LodePNG / */ /* ////////////////////////////////////////////////////////////////////////// */ static unsigned char readBitFromReversedStream(size_t* bitpointer, const unsigned char* bitstream) { unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> (7 - ((*bitpointer) & 0x7))) & 1); ++(*bitpointer); return result; } static unsigned readBitsFromReversedStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) { unsigned result = 0; size_t i; for(i = nbits - 1; i < nbits; --i) { result += (unsigned)readBitFromReversedStream(bitpointer, bitstream) << i; } return result; } #ifdef LODEPNG_COMPILE_DECODER static void setBitOfReversedStream0(size_t* bitpointer, unsigned char* bitstream, unsigned char bit) { /*the current bit in bitstream must be 0 for this to work*/ if(bit) { /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/ bitstream[(*bitpointer) >> 3] |= (bit << (7 - ((*bitpointer) & 0x7))); } ++(*bitpointer); } #endif /*LODEPNG_COMPILE_DECODER*/ static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream, unsigned char bit) { /*the current bit in bitstream may be 0 or 1 for this to work*/ if(bit == 0) bitstream[(*bitpointer) >> 3] &= (unsigned char)(~(1 << (7 - ((*bitpointer) & 0x7)))); else bitstream[(*bitpointer) >> 3] |= (1 << (7 - ((*bitpointer) & 0x7))); ++(*bitpointer); } /* ////////////////////////////////////////////////////////////////////////// */ /* / PNG chunks / */ /* ////////////////////////////////////////////////////////////////////////// */ unsigned lodepng_chunk_length(const unsigned char* chunk) { return lodepng_read32bitInt(&chunk[0]); } void lodepng_chunk_type(char type[5], const unsigned char* chunk) { unsigned i; for(i = 0; i != 4; ++i) type[i] = (char)chunk[4 + i]; type[4] = 0; /*null termination char*/ } unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type) { if(strlen(type) != 4) return 0; return (chunk[4] == type[0] && chunk[5] == type[1] && chunk[6] == type[2] && chunk[7] == type[3]); } unsigned char lodepng_chunk_ancillary(const unsigned char* chunk) { return((chunk[4] & 32) != 0); } unsigned char lodepng_chunk_private(const unsigned char* chunk) { return((chunk[6] & 32) != 0); } unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk) { return((chunk[7] & 32) != 0); } unsigned char* lodepng_chunk_data(unsigned char* chunk) { return &chunk[8]; } const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk) { return &chunk[8]; } unsigned lodepng_chunk_check_crc(const unsigned char* chunk) { unsigned length = lodepng_chunk_length(chunk); unsigned CRC = lodepng_read32bitInt(&chunk[length + 8]); /*the CRC is taken of the data and the 4 chunk type letters, not the length*/ unsigned checksum = lodepng_crc32(&chunk[4], length + 4); if(CRC != checksum) return 1; else return 0; } void lodepng_chunk_generate_crc(unsigned char* chunk) { unsigned length = lodepng_chunk_length(chunk); unsigned CRC = lodepng_crc32(&chunk[4], length + 4); lodepng_set32bitInt(chunk + 8 + length, CRC); } unsigned char* lodepng_chunk_next(unsigned char* chunk) { unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; return &chunk[total_chunk_length]; } const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk) { unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; return &chunk[total_chunk_length]; } unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk) { unsigned i; unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; unsigned char *chunk_start, *new_buffer; size_t new_length = (*outlength) + total_chunk_length; if(new_length < total_chunk_length || new_length < (*outlength)) return 77; /*integer overflow happened*/ new_buffer = (unsigned char*)lodepng_realloc(*out, new_length); if(!new_buffer) return 83; /*alloc fail*/ (*out) = new_buffer; (*outlength) = new_length; chunk_start = &(*out)[new_length - total_chunk_length]; for(i = 0; i != total_chunk_length; ++i) chunk_start[i] = chunk[i]; return 0; } unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, const char* type, const unsigned char* data) { unsigned i; unsigned char *chunk, *new_buffer; size_t new_length = (*outlength) + length + 12; if(new_length < length + 12 || new_length < (*outlength)) return 77; /*integer overflow happened*/ new_buffer = (unsigned char*)lodepng_realloc(*out, new_length); if(!new_buffer) return 83; /*alloc fail*/ (*out) = new_buffer; (*outlength) = new_length; chunk = &(*out)[(*outlength) - length - 12]; /*1: length*/ lodepng_set32bitInt(chunk, (unsigned)length); /*2: chunk name (4 letters)*/ chunk[4] = (unsigned char)type[0]; chunk[5] = (unsigned char)type[1]; chunk[6] = (unsigned char)type[2]; chunk[7] = (unsigned char)type[3]; /*3: the data*/ for(i = 0; i != length; ++i) chunk[8 + i] = data[i]; /*4: CRC (of the chunkname characters and the data)*/ lodepng_chunk_generate_crc(chunk); return 0; } /* ////////////////////////////////////////////////////////////////////////// */ /* / Color types and such / */ /* ////////////////////////////////////////////////////////////////////////// */ /*return type is a LodePNG error code*/ static unsigned checkColorValidity(LodePNGColorType colortype, unsigned bd) /*bd = bitdepth*/ { switch(colortype) { case 0: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; break; /*grey*/ case 2: if(!( bd == 8 || bd == 16)) return 37; break; /*RGB*/ case 3: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 )) return 37; break; /*palette*/ case 4: if(!( bd == 8 || bd == 16)) return 37; break; /*grey + alpha*/ case 6: if(!( bd == 8 || bd == 16)) return 37; break; /*RGBA*/ default: return 31; } return 0; /*allowed color type / bits combination*/ } static unsigned getNumColorChannels(LodePNGColorType colortype) { switch(colortype) { case 0: return 1; /*grey*/ case 2: return 3; /*RGB*/ case 3: return 1; /*palette*/ case 4: return 2; /*grey + alpha*/ case 6: return 4; /*RGBA*/ } return 0; /*unexisting color type*/ } static unsigned lodepng_get_bpp_lct(LodePNGColorType colortype, unsigned bitdepth) { /*bits per pixel is amount of channels * bits per channel*/ return getNumColorChannels(colortype) * bitdepth; } /* ////////////////////////////////////////////////////////////////////////// */ void lodepng_color_mode_init(LodePNGColorMode* info) { info->key_defined = 0; info->key_r = info->key_g = info->key_b = 0; info->colortype = LCT_RGBA; info->bitdepth = 8; info->palette = 0; info->palettesize = 0; } void lodepng_color_mode_cleanup(LodePNGColorMode* info) { lodepng_palette_clear(info); } unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source) { size_t i; lodepng_color_mode_cleanup(dest); *dest = *source; if(source->palette) { dest->palette = (unsigned char*)lodepng_malloc(1024); if(!dest->palette && source->palettesize) return 83; /*alloc fail*/ for(i = 0; i != source->palettesize * 4; ++i) dest->palette[i] = source->palette[i]; } return 0; } static int lodepng_color_mode_equal(const LodePNGColorMode* a, const LodePNGColorMode* b) { size_t i; if(a->colortype != b->colortype) return 0; if(a->bitdepth != b->bitdepth) return 0; if(a->key_defined != b->key_defined) return 0; if(a->key_defined) { if(a->key_r != b->key_r) return 0; if(a->key_g != b->key_g) return 0; if(a->key_b != b->key_b) return 0; } if(a->palettesize != b->palettesize) return 0; for(i = 0; i != a->palettesize * 4; ++i) { if(a->palette[i] != b->palette[i]) return 0; } return 1; } void lodepng_palette_clear(LodePNGColorMode* info) { if(info->palette) lodepng_free(info->palette); info->palette = 0; info->palettesize = 0; } unsigned lodepng_palette_add(LodePNGColorMode* info, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { unsigned char* data; /*the same resize technique as C++ std::vectors is used, and here it's made so that for a palette with the max of 256 colors, it'll have the exact alloc size*/ if(!info->palette) /*allocate palette if empty*/ { /*room for 256 colors with 4 bytes each*/ data = (unsigned char*)lodepng_realloc(info->palette, 1024); if(!data) return 83; /*alloc fail*/ else info->palette = data; } info->palette[4 * info->palettesize + 0] = r; info->palette[4 * info->palettesize + 1] = g; info->palette[4 * info->palettesize + 2] = b; info->palette[4 * info->palettesize + 3] = a; ++info->palettesize; return 0; } unsigned lodepng_get_bpp(const LodePNGColorMode* info) { /*calculate bits per pixel out of colortype and bitdepth*/ return lodepng_get_bpp_lct(info->colortype, info->bitdepth); } unsigned lodepng_get_channels(const LodePNGColorMode* info) { return getNumColorChannels(info->colortype); } unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info) { return info->colortype == LCT_GREY || info->colortype == LCT_GREY_ALPHA; } unsigned lodepng_is_alpha_type(const LodePNGColorMode* info) { return (info->colortype & 4) != 0; /*4 or 6*/ } unsigned lodepng_is_palette_type(const LodePNGColorMode* info) { return info->colortype == LCT_PALETTE; } unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info) { size_t i; for(i = 0; i != info->palettesize; ++i) { if(info->palette[i * 4 + 3] < 255) return 1; } return 0; } unsigned lodepng_can_have_alpha(const LodePNGColorMode* info) { return info->key_defined || lodepng_is_alpha_type(info) || lodepng_has_palette_alpha(info); } size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color) { return (w * h * lodepng_get_bpp(color) + 7) / 8; } size_t lodepng_get_raw_size_lct(unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) { return (w * h * lodepng_get_bpp_lct(colortype, bitdepth) + 7) / 8; } #ifdef LODEPNG_COMPILE_PNG #ifdef LODEPNG_COMPILE_DECODER /*in an idat chunk, each scanline is a multiple of 8 bits, unlike the lodepng output buffer*/ static size_t lodepng_get_raw_size_idat(unsigned w, unsigned h, const LodePNGColorMode* color) { return h * ((w * lodepng_get_bpp(color) + 7) / 8); } #endif /*LODEPNG_COMPILE_DECODER*/ #endif /*LODEPNG_COMPILE_PNG*/ #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS static void LodePNGUnknownChunks_init(LodePNGInfo* info) { unsigned i; for(i = 0; i != 3; ++i) info->unknown_chunks_data[i] = 0; for(i = 0; i != 3; ++i) info->unknown_chunks_size[i] = 0; } static void LodePNGUnknownChunks_cleanup(LodePNGInfo* info) { unsigned i; for(i = 0; i != 3; ++i) lodepng_free(info->unknown_chunks_data[i]); } static unsigned LodePNGUnknownChunks_copy(LodePNGInfo* dest, const LodePNGInfo* src) { unsigned i; LodePNGUnknownChunks_cleanup(dest); for(i = 0; i != 3; ++i) { size_t j; dest->unknown_chunks_size[i] = src->unknown_chunks_size[i]; dest->unknown_chunks_data[i] = (unsigned char*)lodepng_malloc(src->unknown_chunks_size[i]); if(!dest->unknown_chunks_data[i] && dest->unknown_chunks_size[i]) return 83; /*alloc fail*/ for(j = 0; j < src->unknown_chunks_size[i]; ++j) { dest->unknown_chunks_data[i][j] = src->unknown_chunks_data[i][j]; } } return 0; } /******************************************************************************/ static void LodePNGText_init(LodePNGInfo* info) { info->text_num = 0; info->text_keys = NULL; info->text_strings = NULL; } static void LodePNGText_cleanup(LodePNGInfo* info) { size_t i; for(i = 0; i != info->text_num; ++i) { string_cleanup(&info->text_keys[i]); string_cleanup(&info->text_strings[i]); } lodepng_free(info->text_keys); lodepng_free(info->text_strings); } static unsigned LodePNGText_copy(LodePNGInfo* dest, const LodePNGInfo* source) { size_t i = 0; dest->text_keys = 0; dest->text_strings = 0; dest->text_num = 0; for(i = 0; i != source->text_num; ++i) { CERROR_TRY_RETURN(lodepng_add_text(dest, source->text_keys[i], source->text_strings[i])); } return 0; } void lodepng_clear_text(LodePNGInfo* info) { LodePNGText_cleanup(info); } unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str) { char** new_keys = (char**)(lodepng_realloc(info->text_keys, sizeof(char*) * (info->text_num + 1))); char** new_strings = (char**)(lodepng_realloc(info->text_strings, sizeof(char*) * (info->text_num + 1))); if(!new_keys || !new_strings) { lodepng_free(new_keys); lodepng_free(new_strings); return 83; /*alloc fail*/ } ++info->text_num; info->text_keys = new_keys; info->text_strings = new_strings; string_init(&info->text_keys[info->text_num - 1]); string_set(&info->text_keys[info->text_num - 1], key); string_init(&info->text_strings[info->text_num - 1]); string_set(&info->text_strings[info->text_num - 1], str); return 0; } /******************************************************************************/ static void LodePNGIText_init(LodePNGInfo* info) { info->itext_num = 0; info->itext_keys = NULL; info->itext_langtags = NULL; info->itext_transkeys = NULL; info->itext_strings = NULL; } static void LodePNGIText_cleanup(LodePNGInfo* info) { size_t i; for(i = 0; i != info->itext_num; ++i) { string_cleanup(&info->itext_keys[i]); string_cleanup(&info->itext_langtags[i]); string_cleanup(&info->itext_transkeys[i]); string_cleanup(&info->itext_strings[i]); } lodepng_free(info->itext_keys); lodepng_free(info->itext_langtags); lodepng_free(info->itext_transkeys); lodepng_free(info->itext_strings); } static unsigned LodePNGIText_copy(LodePNGInfo* dest, const LodePNGInfo* source) { size_t i = 0; dest->itext_keys = 0; dest->itext_langtags = 0; dest->itext_transkeys = 0; dest->itext_strings = 0; dest->itext_num = 0; for(i = 0; i != source->itext_num; ++i) { CERROR_TRY_RETURN(lodepng_add_itext(dest, source->itext_keys[i], source->itext_langtags[i], source->itext_transkeys[i], source->itext_strings[i])); } return 0; } void lodepng_clear_itext(LodePNGInfo* info) { LodePNGIText_cleanup(info); } unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, const char* transkey, const char* str) { char** new_keys = (char**)(lodepng_realloc(info->itext_keys, sizeof(char*) * (info->itext_num + 1))); char** new_langtags = (char**)(lodepng_realloc(info->itext_langtags, sizeof(char*) * (info->itext_num + 1))); char** new_transkeys = (char**)(lodepng_realloc(info->itext_transkeys, sizeof(char*) * (info->itext_num + 1))); char** new_strings = (char**)(lodepng_realloc(info->itext_strings, sizeof(char*) * (info->itext_num + 1))); if(!new_keys || !new_langtags || !new_transkeys || !new_strings) { lodepng_free(new_keys); lodepng_free(new_langtags); lodepng_free(new_transkeys); lodepng_free(new_strings); return 83; /*alloc fail*/ } ++info->itext_num; info->itext_keys = new_keys; info->itext_langtags = new_langtags; info->itext_transkeys = new_transkeys; info->itext_strings = new_strings; string_init(&info->itext_keys[info->itext_num - 1]); string_set(&info->itext_keys[info->itext_num - 1], key); string_init(&info->itext_langtags[info->itext_num - 1]); string_set(&info->itext_langtags[info->itext_num - 1], langtag); string_init(&info->itext_transkeys[info->itext_num - 1]); string_set(&info->itext_transkeys[info->itext_num - 1], transkey); string_init(&info->itext_strings[info->itext_num - 1]); string_set(&info->itext_strings[info->itext_num - 1], str); return 0; } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ void lodepng_info_init(LodePNGInfo* info) { lodepng_color_mode_init(&info->color); info->interlace_method = 0; info->compression_method = 0; info->filter_method = 0; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS info->background_defined = 0; info->background_r = info->background_g = info->background_b = 0; LodePNGText_init(info); LodePNGIText_init(info); info->time_defined = 0; info->phys_defined = 0; LodePNGUnknownChunks_init(info); #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } void lodepng_info_cleanup(LodePNGInfo* info) { lodepng_color_mode_cleanup(&info->color); #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS LodePNGText_cleanup(info); LodePNGIText_cleanup(info); LodePNGUnknownChunks_cleanup(info); #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source) { lodepng_info_cleanup(dest); *dest = *source; lodepng_color_mode_init(&dest->color); CERROR_TRY_RETURN(lodepng_color_mode_copy(&dest->color, &source->color)); #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS CERROR_TRY_RETURN(LodePNGText_copy(dest, source)); CERROR_TRY_RETURN(LodePNGIText_copy(dest, source)); LodePNGUnknownChunks_init(dest); CERROR_TRY_RETURN(LodePNGUnknownChunks_copy(dest, source)); #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ return 0; } void lodepng_info_swap(LodePNGInfo* a, LodePNGInfo* b) { LodePNGInfo temp = *a; *a = *b; *b = temp; } /* ////////////////////////////////////////////////////////////////////////// */ /*index: bitgroup index, bits: bitgroup size(1, 2 or 4), in: bitgroup value, out: octet array to add bits to*/ static void addColorBits(unsigned char* out, size_t index, unsigned bits, unsigned in) { unsigned m = bits == 1 ? 7 : bits == 2 ? 3 : 1; /*8 / bits - 1*/ /*p = the partial index in the byte, e.g. with 4 palettebits it is 0 for first half or 1 for second half*/ unsigned p = index & m; in &= (1u << bits) - 1u; /*filter out any other bits of the input value*/ in = in << (bits * (m - p)); if(p == 0) out[index * bits / 8] = in; else out[index * bits / 8] |= in; } typedef struct ColorTree ColorTree; /* One node of a color tree This is the data structure used to count the number of unique colors and to get a palette index for a color. It's like an octree, but because the alpha channel is used too, each node has 16 instead of 8 children. */ struct ColorTree { ColorTree* children[16]; /*up to 16 pointers to ColorTree of next level*/ int index; /*the payload. Only has a meaningful value if this is in the last level*/ }; static void color_tree_init(ColorTree* tree) { int i; for(i = 0; i != 16; ++i) tree->children[i] = 0; tree->index = -1; } static void color_tree_cleanup(ColorTree* tree) { int i; for(i = 0; i != 16; ++i) { if(tree->children[i]) { color_tree_cleanup(tree->children[i]); lodepng_free(tree->children[i]); } } } /*returns -1 if color not present, its index otherwise*/ static int color_tree_get(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { int bit = 0; for(bit = 0; bit < 8; ++bit) { int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); if(!tree->children[i]) return -1; else tree = tree->children[i]; } return tree ? tree->index : -1; } #ifdef LODEPNG_COMPILE_ENCODER static int color_tree_has(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { return color_tree_get(tree, r, g, b, a) >= 0; } #endif /*LODEPNG_COMPILE_ENCODER*/ /*color is not allowed to already exist. Index should be >= 0 (it's signed to be compatible with using -1 for "doesn't exist")*/ static void color_tree_add(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned index) { int bit; for(bit = 0; bit < 8; ++bit) { int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); if(!tree->children[i]) { tree->children[i] = (ColorTree*)lodepng_malloc(sizeof(ColorTree)); color_tree_init(tree->children[i]); } tree = tree->children[i]; } tree->index = (int)index; } /*put a pixel, given its RGBA color, into image of any color type*/ static unsigned rgba8ToPixel(unsigned char* out, size_t i, const LodePNGColorMode* mode, ColorTree* tree /*for palette*/, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { if(mode->colortype == LCT_GREY) { unsigned char grey = r; /*((unsigned short)r + g + b) / 3*/; if(mode->bitdepth == 8) out[i] = grey; else if(mode->bitdepth == 16) out[i * 2 + 0] = out[i * 2 + 1] = grey; else { /*take the most significant bits of grey*/ grey = (grey >> (8 - mode->bitdepth)) & ((1 << mode->bitdepth) - 1); addColorBits(out, i, mode->bitdepth, grey); } } else if(mode->colortype == LCT_RGB) { if(mode->bitdepth == 8) { out[i * 3 + 0] = r; out[i * 3 + 1] = g; out[i * 3 + 2] = b; } else { out[i * 6 + 0] = out[i * 6 + 1] = r; out[i * 6 + 2] = out[i * 6 + 3] = g; out[i * 6 + 4] = out[i * 6 + 5] = b; } } else if(mode->colortype == LCT_PALETTE) { int index = color_tree_get(tree, r, g, b, a); if(index < 0) return 82; /*color not in palette*/ if(mode->bitdepth == 8) out[i] = index; else addColorBits(out, i, mode->bitdepth, (unsigned)index); } else if(mode->colortype == LCT_GREY_ALPHA) { unsigned char grey = r; /*((unsigned short)r + g + b) / 3*/; if(mode->bitdepth == 8) { out[i * 2 + 0] = grey; out[i * 2 + 1] = a; } else if(mode->bitdepth == 16) { out[i * 4 + 0] = out[i * 4 + 1] = grey; out[i * 4 + 2] = out[i * 4 + 3] = a; } } else if(mode->colortype == LCT_RGBA) { if(mode->bitdepth == 8) { out[i * 4 + 0] = r; out[i * 4 + 1] = g; out[i * 4 + 2] = b; out[i * 4 + 3] = a; } else { out[i * 8 + 0] = out[i * 8 + 1] = r; out[i * 8 + 2] = out[i * 8 + 3] = g; out[i * 8 + 4] = out[i * 8 + 5] = b; out[i * 8 + 6] = out[i * 8 + 7] = a; } } return 0; /*no error*/ } /*put a pixel, given its RGBA16 color, into image of any color 16-bitdepth type*/ static void rgba16ToPixel(unsigned char* out, size_t i, const LodePNGColorMode* mode, unsigned short r, unsigned short g, unsigned short b, unsigned short a) { if(mode->colortype == LCT_GREY) { unsigned short grey = r; /*((unsigned)r + g + b) / 3*/; out[i * 2 + 0] = (grey >> 8) & 255; out[i * 2 + 1] = grey & 255; } else if(mode->colortype == LCT_RGB) { out[i * 6 + 0] = (r >> 8) & 255; out[i * 6 + 1] = r & 255; out[i * 6 + 2] = (g >> 8) & 255; out[i * 6 + 3] = g & 255; out[i * 6 + 4] = (b >> 8) & 255; out[i * 6 + 5] = b & 255; } else if(mode->colortype == LCT_GREY_ALPHA) { unsigned short grey = r; /*((unsigned)r + g + b) / 3*/; out[i * 4 + 0] = (grey >> 8) & 255; out[i * 4 + 1] = grey & 255; out[i * 4 + 2] = (a >> 8) & 255; out[i * 4 + 3] = a & 255; } else if(mode->colortype == LCT_RGBA) { out[i * 8 + 0] = (r >> 8) & 255; out[i * 8 + 1] = r & 255; out[i * 8 + 2] = (g >> 8) & 255; out[i * 8 + 3] = g & 255; out[i * 8 + 4] = (b >> 8) & 255; out[i * 8 + 5] = b & 255; out[i * 8 + 6] = (a >> 8) & 255; out[i * 8 + 7] = a & 255; } } /*Get RGBA8 color of pixel with index i (y * width + x) from the raw image with given color type.*/ static void getPixelColorRGBA8(unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a, const unsigned char* in, size_t i, const LodePNGColorMode* mode) { if(mode->colortype == LCT_GREY) { if(mode->bitdepth == 8) { *r = *g = *b = in[i]; if(mode->key_defined && *r == mode->key_r) *a = 0; else *a = 255; } else if(mode->bitdepth == 16) { *r = *g = *b = in[i * 2 + 0]; if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0; else *a = 255; } else { unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ size_t j = i * mode->bitdepth; unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); *r = *g = *b = (value * 255) / highest; if(mode->key_defined && value == mode->key_r) *a = 0; else *a = 255; } } else if(mode->colortype == LCT_RGB) { if(mode->bitdepth == 8) { *r = in[i * 3 + 0]; *g = in[i * 3 + 1]; *b = in[i * 3 + 2]; if(mode->key_defined && *r == mode->key_r && *g == mode->key_g && *b == mode->key_b) *a = 0; else *a = 255; } else { *r = in[i * 6 + 0]; *g = in[i * 6 + 2]; *b = in[i * 6 + 4]; if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0; else *a = 255; } } else if(mode->colortype == LCT_PALETTE) { unsigned index; if(mode->bitdepth == 8) index = in[i]; else { size_t j = i * mode->bitdepth; index = readBitsFromReversedStream(&j, in, mode->bitdepth); } if(index >= mode->palettesize) { /*This is an error according to the PNG spec, but common PNG decoders make it black instead. Done here too, slightly faster due to no error handling needed.*/ *r = *g = *b = 0; *a = 255; } else { *r = mode->palette[index * 4 + 0]; *g = mode->palette[index * 4 + 1]; *b = mode->palette[index * 4 + 2]; *a = mode->palette[index * 4 + 3]; } } else if(mode->colortype == LCT_GREY_ALPHA) { if(mode->bitdepth == 8) { *r = *g = *b = in[i * 2 + 0]; *a = in[i * 2 + 1]; } else { *r = *g = *b = in[i * 4 + 0]; *a = in[i * 4 + 2]; } } else if(mode->colortype == LCT_RGBA) { if(mode->bitdepth == 8) { *r = in[i * 4 + 0]; *g = in[i * 4 + 1]; *b = in[i * 4 + 2]; *a = in[i * 4 + 3]; } else { *r = in[i * 8 + 0]; *g = in[i * 8 + 2]; *b = in[i * 8 + 4]; *a = in[i * 8 + 6]; } } } /*Similar to getPixelColorRGBA8, but with all the for loops inside of the color mode test cases, optimized to convert the colors much faster, when converting to RGBA or RGB with 8 bit per cannel. buffer must be RGBA or RGB output with enough memory, if has_alpha is true the output is RGBA. mode has the color mode of the input buffer.*/ static void getPixelColorsRGBA8(unsigned char* buffer, size_t numpixels, unsigned has_alpha, const unsigned char* in, const LodePNGColorMode* mode) { unsigned num_channels = has_alpha ? 4 : 3; size_t i; if(mode->colortype == LCT_GREY) { if(mode->bitdepth == 8) { for(i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = buffer[1] = buffer[2] = in[i]; if(has_alpha) buffer[3] = mode->key_defined && in[i] == mode->key_r ? 0 : 255; } } else if(mode->bitdepth == 16) { for(i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = buffer[1] = buffer[2] = in[i * 2]; if(has_alpha) buffer[3] = mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r ? 0 : 255; } } else { unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ size_t j = 0; for(i = 0; i != numpixels; ++i, buffer += num_channels) { unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); buffer[0] = buffer[1] = buffer[2] = (value * 255) / highest; if(has_alpha) buffer[3] = mode->key_defined && value == mode->key_r ? 0 : 255; } } } else if(mode->colortype == LCT_RGB) { if(mode->bitdepth == 8) { for(i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = in[i * 3 + 0]; buffer[1] = in[i * 3 + 1]; buffer[2] = in[i * 3 + 2]; if(has_alpha) buffer[3] = mode->key_defined && buffer[0] == mode->key_r && buffer[1]== mode->key_g && buffer[2] == mode->key_b ? 0 : 255; } } else { for(i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = in[i * 6 + 0]; buffer[1] = in[i * 6 + 2]; buffer[2] = in[i * 6 + 4]; if(has_alpha) buffer[3] = mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b ? 0 : 255; } } } else if(mode->colortype == LCT_PALETTE) { unsigned index; size_t j = 0; for(i = 0; i != numpixels; ++i, buffer += num_channels) { if(mode->bitdepth == 8) index = in[i]; else index = readBitsFromReversedStream(&j, in, mode->bitdepth); if(index >= mode->palettesize) { /*This is an error according to the PNG spec, but most PNG decoders make it black instead. Done here too, slightly faster due to no error handling needed.*/ buffer[0] = buffer[1] = buffer[2] = 0; if(has_alpha) buffer[3] = 255; } else { buffer[0] = mode->palette[index * 4 + 0]; buffer[1] = mode->palette[index * 4 + 1]; buffer[2] = mode->palette[index * 4 + 2]; if(has_alpha) buffer[3] = mode->palette[index * 4 + 3]; } } } else if(mode->colortype == LCT_GREY_ALPHA) { if(mode->bitdepth == 8) { for(i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = buffer[1] = buffer[2] = in[i * 2 + 0]; if(has_alpha) buffer[3] = in[i * 2 + 1]; } } else { for(i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = buffer[1] = buffer[2] = in[i * 4 + 0]; if(has_alpha) buffer[3] = in[i * 4 + 2]; } } } else if(mode->colortype == LCT_RGBA) { if(mode->bitdepth == 8) { for(i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = in[i * 4 + 0]; buffer[1] = in[i * 4 + 1]; buffer[2] = in[i * 4 + 2]; if(has_alpha) buffer[3] = in[i * 4 + 3]; } } else { for(i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = in[i * 8 + 0]; buffer[1] = in[i * 8 + 2]; buffer[2] = in[i * 8 + 4]; if(has_alpha) buffer[3] = in[i * 8 + 6]; } } } } /*Get RGBA16 color of pixel with index i (y * width + x) from the raw image with given color type, but the given color type must be 16-bit itself.*/ static void getPixelColorRGBA16(unsigned short* r, unsigned short* g, unsigned short* b, unsigned short* a, const unsigned char* in, size_t i, const LodePNGColorMode* mode) { if(mode->colortype == LCT_GREY) { *r = *g = *b = 256 * in[i * 2 + 0] + in[i * 2 + 1]; if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0; else *a = 65535; } else if(mode->colortype == LCT_RGB) { *r = 256 * in[i * 6 + 0] + in[i * 6 + 1]; *g = 256 * in[i * 6 + 2] + in[i * 6 + 3]; *b = 256 * in[i * 6 + 4] + in[i * 6 + 5]; if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0; else *a = 65535; } else if(mode->colortype == LCT_GREY_ALPHA) { *r = *g = *b = 256 * in[i * 4 + 0] + in[i * 4 + 1]; *a = 256 * in[i * 4 + 2] + in[i * 4 + 3]; } else if(mode->colortype == LCT_RGBA) { *r = 256 * in[i * 8 + 0] + in[i * 8 + 1]; *g = 256 * in[i * 8 + 2] + in[i * 8 + 3]; *b = 256 * in[i * 8 + 4] + in[i * 8 + 5]; *a = 256 * in[i * 8 + 6] + in[i * 8 + 7]; } } unsigned lodepng_convert(unsigned char* out, const unsigned char* in, LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, unsigned w, unsigned h) { size_t i; ColorTree tree; size_t numpixels = w * h; if(lodepng_color_mode_equal(mode_out, mode_in)) { size_t numbytes = lodepng_get_raw_size(w, h, mode_in); for(i = 0; i != numbytes; ++i) out[i] = in[i]; return 0; } if(mode_out->colortype == LCT_PALETTE) { size_t palsize = 1u << mode_out->bitdepth; if(mode_out->palettesize < palsize) palsize = mode_out->palettesize; color_tree_init(&tree); for(i = 0; i != palsize; ++i) { unsigned char* p = &mode_out->palette[i * 4]; color_tree_add(&tree, p[0], p[1], p[2], p[3], i); } } if(mode_in->bitdepth == 16 && mode_out->bitdepth == 16) { for(i = 0; i != numpixels; ++i) { unsigned short r = 0, g = 0, b = 0, a = 0; getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in); rgba16ToPixel(out, i, mode_out, r, g, b, a); } } else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGBA) { getPixelColorsRGBA8(out, numpixels, 1, in, mode_in); } else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGB) { getPixelColorsRGBA8(out, numpixels, 0, in, mode_in); } else { unsigned char r = 0, g = 0, b = 0, a = 0; for(i = 0; i != numpixels; ++i) { getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in); rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a); } } if(mode_out->colortype == LCT_PALETTE) { color_tree_cleanup(&tree); } return 0; /*no error (this function currently never has one, but maybe OOM detection added later.)*/ } #ifdef LODEPNG_COMPILE_ENCODER void lodepng_color_profile_init(LodePNGColorProfile* profile) { profile->colored = 0; profile->key = 0; profile->alpha = 0; profile->key_r = profile->key_g = profile->key_b = 0; profile->numcolors = 0; profile->bits = 1; } /*function used for debug purposes with C++*/ /*void printColorProfile(LodePNGColorProfile* p) { std::cout << "colored: " << (int)p->colored << ", "; std::cout << "key: " << (int)p->key << ", "; std::cout << "key_r: " << (int)p->key_r << ", "; std::cout << "key_g: " << (int)p->key_g << ", "; std::cout << "key_b: " << (int)p->key_b << ", "; std::cout << "alpha: " << (int)p->alpha << ", "; std::cout << "numcolors: " << (int)p->numcolors << ", "; std::cout << "bits: " << (int)p->bits << std::endl; }*/ /*Returns how many bits needed to represent given value (max 8 bit)*/ static unsigned getValueRequiredBits(unsigned char value) { if(value == 0 || value == 255) return 1; /*The scaling of 2-bit and 4-bit values uses multiples of 85 and 17*/ if(value % 17 == 0) return value % 85 == 0 ? 2 : 4; return 8; } /*profile must already have been inited with mode. It's ok to set some parameters of profile to done already.*/ unsigned lodepng_get_color_profile(LodePNGColorProfile* profile, const unsigned char* in, unsigned w, unsigned h, const LodePNGColorMode* mode) { unsigned error = 0; size_t i; ColorTree tree; size_t numpixels = w * h; unsigned colored_done = lodepng_is_greyscale_type(mode) ? 1 : 0; unsigned alpha_done = lodepng_can_have_alpha(mode) ? 0 : 1; unsigned numcolors_done = 0; unsigned bpp = lodepng_get_bpp(mode); unsigned bits_done = bpp == 1 ? 1 : 0; unsigned maxnumcolors = 257; unsigned sixteen = 0; if(bpp <= 8) maxnumcolors = bpp == 1 ? 2 : (bpp == 2 ? 4 : (bpp == 4 ? 16 : 256)); color_tree_init(&tree); /*Check if the 16-bit input is truly 16-bit*/ if(mode->bitdepth == 16) { unsigned short r, g, b, a; for(i = 0; i != numpixels; ++i) { getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode); if((r & 255) != ((r >> 8) & 255) || (g & 255) != ((g >> 8) & 255) || (b & 255) != ((b >> 8) & 255) || (a & 255) != ((a >> 8) & 255)) /*first and second byte differ*/ { sixteen = 1; break; } } } if(sixteen) { unsigned short r = 0, g = 0, b = 0, a = 0; profile->bits = 16; bits_done = numcolors_done = 1; /*counting colors no longer useful, palette doesn't support 16-bit*/ for(i = 0; i != numpixels; ++i) { getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode); if(!colored_done && (r != g || r != b)) { profile->colored = 1; colored_done = 1; } if(!alpha_done) { unsigned matchkey = (r == profile->key_r && g == profile->key_g && b == profile->key_b); if(a != 65535 && (a != 0 || (profile->key && !matchkey))) { profile->alpha = 1; alpha_done = 1; if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ } else if(a == 0 && !profile->alpha && !profile->key) { profile->key = 1; profile->key_r = r; profile->key_g = g; profile->key_b = b; } else if(a == 65535 && profile->key && matchkey) { /* Color key cannot be used if an opaque pixel also has that RGB color. */ profile->alpha = 1; alpha_done = 1; } } if(alpha_done && numcolors_done && colored_done && bits_done) break; } } else /* < 16-bit */ { for(i = 0; i != numpixels; ++i) { unsigned char r = 0, g = 0, b = 0, a = 0; getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode); if(!bits_done && profile->bits < 8) { /*only r is checked, < 8 bits is only relevant for greyscale*/ unsigned bits = getValueRequiredBits(r); if(bits > profile->bits) profile->bits = bits; } bits_done = (profile->bits >= bpp); if(!colored_done && (r != g || r != b)) { profile->colored = 1; colored_done = 1; if(profile->bits < 8) profile->bits = 8; /*PNG has no colored modes with less than 8-bit per channel*/ } if(!alpha_done) { unsigned matchkey = (r == profile->key_r && g == profile->key_g && b == profile->key_b); if(a != 255 && (a != 0 || (profile->key && !matchkey))) { profile->alpha = 1; alpha_done = 1; if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ } else if(a == 0 && !profile->alpha && !profile->key) { profile->key = 1; profile->key_r = r; profile->key_g = g; profile->key_b = b; } else if(a == 255 && profile->key && matchkey) { /* Color key cannot be used if an opaque pixel also has that RGB color. */ profile->alpha = 1; alpha_done = 1; if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ } } if(!numcolors_done) { if(!color_tree_has(&tree, r, g, b, a)) { color_tree_add(&tree, r, g, b, a, profile->numcolors); if(profile->numcolors < 256) { unsigned char* p = profile->palette; unsigned n = profile->numcolors; p[n * 4 + 0] = r; p[n * 4 + 1] = g; p[n * 4 + 2] = b; p[n * 4 + 3] = a; } ++profile->numcolors; numcolors_done = profile->numcolors >= maxnumcolors; } } if(alpha_done && numcolors_done && colored_done && bits_done) break; } /*make the profile's key always 16-bit for consistency - repeat each byte twice*/ profile->key_r += (profile->key_r << 8); profile->key_g += (profile->key_g << 8); profile->key_b += (profile->key_b << 8); } color_tree_cleanup(&tree); return error; } /*Automatically chooses color type that gives smallest amount of bits in the output image, e.g. grey if there are only greyscale pixels, palette if there are less than 256 colors, ... Updates values of mode with a potentially smaller color model. mode_out should contain the user chosen color model, but will be overwritten with the new chosen one.*/ unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out, const unsigned char* image, unsigned w, unsigned h, const LodePNGColorMode* mode_in) { LodePNGColorProfile prof; unsigned error = 0; unsigned i, n, palettebits, grey_ok, palette_ok; lodepng_color_profile_init(&prof); error = lodepng_get_color_profile(&prof, image, w, h, mode_in); if(error) return error; mode_out->key_defined = 0; if(prof.key && w * h <= 16) { prof.alpha = 1; /*too few pixels to justify tRNS chunk overhead*/ if(prof.bits < 8) prof.bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ } grey_ok = !prof.colored && !prof.alpha; /*grey without alpha, with potentially low bits*/ n = prof.numcolors; palettebits = n <= 2 ? 1 : (n <= 4 ? 2 : (n <= 16 ? 4 : 8)); palette_ok = n <= 256 && (n * 2 < w * h) && prof.bits <= 8; if(w * h < n * 2) palette_ok = 0; /*don't add palette overhead if image has only a few pixels*/ if(grey_ok && prof.bits <= palettebits) palette_ok = 0; /*grey is less overhead*/ if(palette_ok) { unsigned char* p = prof.palette; lodepng_palette_clear(mode_out); /*remove potential earlier palette*/ for(i = 0; i != prof.numcolors; ++i) { error = lodepng_palette_add(mode_out, p[i * 4 + 0], p[i * 4 + 1], p[i * 4 + 2], p[i * 4 + 3]); if(error) break; } mode_out->colortype = LCT_PALETTE; mode_out->bitdepth = palettebits; if(mode_in->colortype == LCT_PALETTE && mode_in->palettesize >= mode_out->palettesize && mode_in->bitdepth == mode_out->bitdepth) { /*If input should have same palette colors, keep original to preserve its order and prevent conversion*/ lodepng_color_mode_cleanup(mode_out); lodepng_color_mode_copy(mode_out, mode_in); } } else /*8-bit or 16-bit per channel*/ { mode_out->bitdepth = prof.bits; mode_out->colortype = prof.alpha ? (prof.colored ? LCT_RGBA : LCT_GREY_ALPHA) : (prof.colored ? LCT_RGB : LCT_GREY); if(prof.key && !prof.alpha) { unsigned mask = (1u << mode_out->bitdepth) - 1u; /*profile always uses 16-bit, mask converts it*/ mode_out->key_r = prof.key_r & mask; mode_out->key_g = prof.key_g & mask; mode_out->key_b = prof.key_b & mask; mode_out->key_defined = 1; } } return error; } #endif /* #ifdef LODEPNG_COMPILE_ENCODER */ /* Paeth predicter, used by PNG filter type 4 The parameters are of type short, but should come from unsigned chars, the shorts are only needed to make the paeth calculation correct. */ static unsigned char paethPredictor(short a, short b, short c) { short pa = abs(b - c); short pb = abs(a - c); short pc = abs(a + b - c - c); if(pc < pa && pc < pb) return (unsigned char)c; else if(pb < pa) return (unsigned char)b; else return (unsigned char)a; } /*shared values used by multiple Adam7 related functions*/ static const unsigned ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/ static const unsigned ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/ static const unsigned ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/ static const unsigned ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/ /* Outputs various dimensions and positions in the image related to the Adam7 reduced images. passw: output containing the width of the 7 passes passh: output containing the height of the 7 passes filter_passstart: output containing the index of the start and end of each reduced image with filter bytes padded_passstart output containing the index of the start and end of each reduced image when without filter bytes but with padded scanlines passstart: output containing the index of the start and end of each reduced image without padding between scanlines, but still padding between the images w, h: width and height of non-interlaced image bpp: bits per pixel "padded" is only relevant if bpp is less than 8 and a scanline or image does not end at a full byte */ static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t filter_passstart[8], size_t padded_passstart[8], size_t passstart[8], unsigned w, unsigned h, unsigned bpp) { /*the passstart values have 8 values: the 8th one indicates the byte after the end of the 7th (= last) pass*/ unsigned i; /*calculate width and height in pixels of each pass*/ for(i = 0; i != 7; ++i) { passw[i] = (w + ADAM7_DX[i] - ADAM7_IX[i] - 1) / ADAM7_DX[i]; passh[i] = (h + ADAM7_DY[i] - ADAM7_IY[i] - 1) / ADAM7_DY[i]; if(passw[i] == 0) passh[i] = 0; if(passh[i] == 0) passw[i] = 0; } filter_passstart[0] = padded_passstart[0] = passstart[0] = 0; for(i = 0; i != 7; ++i) { /*if passw[i] is 0, it's 0 bytes, not 1 (no filtertype-byte)*/ filter_passstart[i + 1] = filter_passstart[i] + ((passw[i] && passh[i]) ? passh[i] * (1 + (passw[i] * bpp + 7) / 8) : 0); /*bits padded if needed to fill full byte at end of each scanline*/ padded_passstart[i + 1] = padded_passstart[i] + passh[i] * ((passw[i] * bpp + 7) / 8); /*only padded at end of reduced image*/ passstart[i + 1] = passstart[i] + (passh[i] * passw[i] * bpp + 7) / 8; } } #ifdef LODEPNG_COMPILE_DECODER /* ////////////////////////////////////////////////////////////////////////// */ /* / PNG Decoder / */ /* ////////////////////////////////////////////////////////////////////////// */ /*read the information from the header and store it in the LodePNGInfo. return value is error*/ unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state, const unsigned char* in, size_t insize) { LodePNGInfo* info = &state->info_png; if(insize == 0 || in == 0) { CERROR_RETURN_ERROR(state->error, 48); /*error: the given data is empty*/ } if(insize < 33) { CERROR_RETURN_ERROR(state->error, 27); /*error: the data length is smaller than the length of a PNG header*/ } /*when decoding a new PNG image, make sure all parameters created after previous decoding are reset*/ lodepng_info_cleanup(info); lodepng_info_init(info); if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) { CERROR_RETURN_ERROR(state->error, 28); /*error: the first 8 bytes are not the correct PNG signature*/ } if(in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || in[15] != 'R') { CERROR_RETURN_ERROR(state->error, 29); /*error: it doesn't start with a IHDR chunk!*/ } /*read the values given in the header*/ *w = lodepng_read32bitInt(&in[16]); *h = lodepng_read32bitInt(&in[20]); info->color.bitdepth = in[24]; info->color.colortype = (LodePNGColorType)in[25]; info->compression_method = in[26]; info->filter_method = in[27]; info->interlace_method = in[28]; if(*w == 0 || *h == 0) { CERROR_RETURN_ERROR(state->error, 93); } if(!state->decoder.ignore_crc) { unsigned CRC = lodepng_read32bitInt(&in[29]); unsigned checksum = lodepng_crc32(&in[12], 17); if(CRC != checksum) { CERROR_RETURN_ERROR(state->error, 57); /*invalid CRC*/ } } /*error: only compression method 0 is allowed in the specification*/ if(info->compression_method != 0) CERROR_RETURN_ERROR(state->error, 32); /*error: only filter method 0 is allowed in the specification*/ if(info->filter_method != 0) CERROR_RETURN_ERROR(state->error, 33); /*error: only interlace methods 0 and 1 exist in the specification*/ if(info->interlace_method > 1) CERROR_RETURN_ERROR(state->error, 34); state->error = checkColorValidity(info->color.colortype, info->color.bitdepth); return state->error; } static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, size_t bytewidth, unsigned char filterType, size_t length) { /* For PNG filter method 0 unfilter a PNG image scanline by scanline. when the pixels are smaller than 1 byte, the filter works byte per byte (bytewidth = 1) precon is the previous unfiltered scanline, recon the result, scanline the current one the incoming scanlines do NOT include the filtertype byte, that one is given in the parameter filterType instead recon and scanline MAY be the same memory address! precon must be disjoint. */ size_t i; switch(filterType) { case 0: for(i = 0; i != length; ++i) recon[i] = scanline[i]; break; case 1: for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i]; for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + recon[i - bytewidth]; break; case 2: if(precon) { for(i = 0; i != length; ++i) recon[i] = scanline[i] + precon[i]; } else { for(i = 0; i != length; ++i) recon[i] = scanline[i]; } break; case 3: if(precon) { for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i] + precon[i] / 2; for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2); } else { for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i]; for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + recon[i - bytewidth] / 2; } break; case 4: if(precon) { for(i = 0; i != bytewidth; ++i) { recon[i] = (scanline[i] + precon[i]); /*paethPredictor(0, precon[i], 0) is always precon[i]*/ } for(i = bytewidth; i < length; ++i) { recon[i] = (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth])); } } else { for(i = 0; i != bytewidth; ++i) { recon[i] = scanline[i]; } for(i = bytewidth; i < length; ++i) { /*paethPredictor(recon[i - bytewidth], 0, 0) is always recon[i - bytewidth]*/ recon[i] = (scanline[i] + recon[i - bytewidth]); } } break; default: return 36; /*error: unexisting filter type given*/ } return 0; } static unsigned unfilter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) { /* For PNG filter method 0 this function unfilters a single image (e.g. without interlacing this is called once, with Adam7 seven times) out must have enough bytes allocated already, in must have the scanlines + 1 filtertype byte per scanline w and h are image dimensions or dimensions of reduced image, bpp is bits per pixel in and out are allowed to be the same memory address (but aren't the same size since in has the extra filter bytes) */ unsigned y; unsigned char* prevline = 0; /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ size_t bytewidth = (bpp + 7) / 8; size_t linebytes = (w * bpp + 7) / 8; for(y = 0; y < h; ++y) { size_t outindex = linebytes * y; size_t inindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ unsigned char filterType = in[inindex]; CERROR_TRY_RETURN(unfilterScanline(&out[outindex], &in[inindex + 1], prevline, bytewidth, filterType, linebytes)); prevline = &out[outindex]; } return 0; } /* in: Adam7 interlaced image, with no padding bits between scanlines, but between reduced images so that each reduced image starts at a byte. out: the same pixels, but re-ordered so that they're now a non-interlaced image with size w*h bpp: bits per pixel out has the following size in bits: w * h * bpp. in is possibly bigger due to padding bits between reduced images. out must be big enough AND must be 0 everywhere if bpp < 8 in the current implementation (because that's likely a little bit faster) NOTE: comments about padding bits are only relevant if bpp < 8 */ static void Adam7_deinterlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) { unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; unsigned i; Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); if(bpp >= 8) { for(i = 0; i != 7; ++i) { unsigned x, y, b; size_t bytewidth = bpp / 8; for(y = 0; y < passh[i]; ++y) for(x = 0; x < passw[i]; ++x) { size_t pixelinstart = passstart[i] + (y * passw[i] + x) * bytewidth; size_t pixeloutstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; for(b = 0; b < bytewidth; ++b) { out[pixeloutstart + b] = in[pixelinstart + b]; } } } } else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ { for(i = 0; i != 7; ++i) { unsigned x, y, b; unsigned ilinebits = bpp * passw[i]; unsigned olinebits = bpp * w; size_t obp, ibp; /*bit pointers (for out and in buffer)*/ for(y = 0; y < passh[i]; ++y) for(x = 0; x < passw[i]; ++x) { ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp); obp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; for(b = 0; b < bpp; ++b) { unsigned char bit = readBitFromReversedStream(&ibp, in); /*note that this function assumes the out buffer is completely 0, use setBitOfReversedStream otherwise*/ setBitOfReversedStream0(&obp, out, bit); } } } } } static void removePaddingBits(unsigned char* out, const unsigned char* in, size_t olinebits, size_t ilinebits, unsigned h) { /* After filtering there are still padding bits if scanlines have non multiple of 8 bit amounts. They need to be removed (except at last scanline of (Adam7-reduced) image) before working with pure image buffers for the Adam7 code, the color convert code and the output to the user. in and out are allowed to be the same buffer, in may also be higher but still overlapping; in must have >= ilinebits*h bits, out must have >= olinebits*h bits, olinebits must be <= ilinebits also used to move bits after earlier such operations happened, e.g. in a sequence of reduced images from Adam7 only useful if (ilinebits - olinebits) is a value in the range 1..7 */ unsigned y; size_t diff = ilinebits - olinebits; size_t ibp = 0, obp = 0; /*input and output bit pointers*/ for(y = 0; y < h; ++y) { size_t x; for(x = 0; x < olinebits; ++x) { unsigned char bit = readBitFromReversedStream(&ibp, in); setBitOfReversedStream(&obp, out, bit); } ibp += diff; } } /*out must be buffer big enough to contain full image, and in must contain the full decompressed data from the IDAT chunks (with filter index bytes and possible padding bits) return value is error*/ static unsigned postProcessScanlines(unsigned char* out, unsigned char* in, unsigned w, unsigned h, const LodePNGInfo* info_png) { /* This function converts the filtered-padded-interlaced data into pure 2D image buffer with the PNG's colortype. Steps: *) if no Adam7: 1) unfilter 2) remove padding bits (= posible extra bits per scanline if bpp < 8) *) if adam7: 1) 7x unfilter 2) 7x remove padding bits 3) Adam7_deinterlace NOTE: the in buffer will be overwritten with intermediate data! */ unsigned bpp = lodepng_get_bpp(&info_png->color); if(bpp == 0) return 31; /*error: invalid colortype*/ if(info_png->interlace_method == 0) { if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8) { CERROR_TRY_RETURN(unfilter(in, in, w, h, bpp)); removePaddingBits(out, in, w * bpp, ((w * bpp + 7) / 8) * 8, h); } /*we can immediatly filter into the out buffer, no other steps needed*/ else CERROR_TRY_RETURN(unfilter(out, in, w, h, bpp)); } else /*interlace_method is 1 (Adam7)*/ { unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; unsigned i; Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); for(i = 0; i != 7; ++i) { CERROR_TRY_RETURN(unfilter(&in[padded_passstart[i]], &in[filter_passstart[i]], passw[i], passh[i], bpp)); /*TODO: possible efficiency improvement: if in this reduced image the bits fit nicely in 1 scanline, move bytes instead of bits or move not at all*/ if(bpp < 8) { /*remove padding bits in scanlines; after this there still may be padding bits between the different reduced images: each reduced image still starts nicely at a byte*/ removePaddingBits(&in[passstart[i]], &in[padded_passstart[i]], passw[i] * bpp, ((passw[i] * bpp + 7) / 8) * 8, passh[i]); } } Adam7_deinterlace(out, in, w, h, bpp); } return 0; } static unsigned readChunk_PLTE(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) { unsigned pos = 0, i; if(color->palette) lodepng_free(color->palette); color->palettesize = chunkLength / 3; color->palette = (unsigned char*)lodepng_malloc(4 * color->palettesize); if(!color->palette && color->palettesize) { color->palettesize = 0; return 83; /*alloc fail*/ } if(color->palettesize > 256) return 38; /*error: palette too big*/ for(i = 0; i != color->palettesize; ++i) { color->palette[4 * i + 0] = data[pos++]; /*R*/ color->palette[4 * i + 1] = data[pos++]; /*G*/ color->palette[4 * i + 2] = data[pos++]; /*B*/ color->palette[4 * i + 3] = 255; /*alpha*/ } return 0; /* OK */ } static unsigned readChunk_tRNS(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) { unsigned i; if(color->colortype == LCT_PALETTE) { /*error: more alpha values given than there are palette entries*/ if(chunkLength > color->palettesize) return 38; for(i = 0; i != chunkLength; ++i) color->palette[4 * i + 3] = data[i]; } else if(color->colortype == LCT_GREY) { /*error: this chunk must be 2 bytes for greyscale image*/ if(chunkLength != 2) return 30; color->key_defined = 1; color->key_r = color->key_g = color->key_b = 256u * data[0] + data[1]; } else if(color->colortype == LCT_RGB) { /*error: this chunk must be 6 bytes for RGB image*/ if(chunkLength != 6) return 41; color->key_defined = 1; color->key_r = 256u * data[0] + data[1]; color->key_g = 256u * data[2] + data[3]; color->key_b = 256u * data[4] + data[5]; } else return 42; /*error: tRNS chunk not allowed for other color models*/ return 0; /* OK */ } #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*background color chunk (bKGD)*/ static unsigned readChunk_bKGD(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { if(info->color.colortype == LCT_PALETTE) { /*error: this chunk must be 1 byte for indexed color image*/ if(chunkLength != 1) return 43; info->background_defined = 1; info->background_r = info->background_g = info->background_b = data[0]; } else if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) { /*error: this chunk must be 2 bytes for greyscale image*/ if(chunkLength != 2) return 44; info->background_defined = 1; info->background_r = info->background_g = info->background_b = 256u * data[0] + data[1]; } else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) { /*error: this chunk must be 6 bytes for greyscale image*/ if(chunkLength != 6) return 45; info->background_defined = 1; info->background_r = 256u * data[0] + data[1]; info->background_g = 256u * data[2] + data[3]; info->background_b = 256u * data[4] + data[5]; } return 0; /* OK */ } /*text chunk (tEXt)*/ static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { unsigned error = 0; char *key = 0, *str = 0; unsigned i; while(!error) /*not really a while loop, only used to break on error*/ { unsigned length, string2_begin; length = 0; while(length < chunkLength && data[length] != 0) ++length; /*even though it's not allowed by the standard, no error is thrown if there's no null termination char, if the text is empty*/ if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ key = (char*)lodepng_malloc(length + 1); if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ key[length] = 0; for(i = 0; i != length; ++i) key[i] = (char)data[i]; string2_begin = length + 1; /*skip keyword null terminator*/ length = chunkLength < string2_begin ? 0 : chunkLength - string2_begin; str = (char*)lodepng_malloc(length + 1); if(!str) CERROR_BREAK(error, 83); /*alloc fail*/ str[length] = 0; for(i = 0; i != length; ++i) str[i] = (char)data[string2_begin + i]; error = lodepng_add_text(info, key, str); break; } lodepng_free(key); lodepng_free(str); return error; } /*compressed text chunk (zTXt)*/ static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings, const unsigned char* data, size_t chunkLength) { unsigned error = 0; unsigned i; unsigned length, string2_begin; char *key = 0; ucvector decoded; ucvector_init(&decoded); while(!error) /*not really a while loop, only used to break on error*/ { for(length = 0; length < chunkLength && data[length] != 0; ++length) ; if(length + 2 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ key = (char*)lodepng_malloc(length + 1); if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ key[length] = 0; for(i = 0; i != length; ++i) key[i] = (char)data[i]; if(data[length + 1] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ string2_begin = length + 2; if(string2_begin > chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ length = chunkLength - string2_begin; /*will fail if zlib error, e.g. if length is too small*/ error = zlib_decompress(&decoded.data, &decoded.size, (unsigned char*)(&data[string2_begin]), length, zlibsettings); if(error) break; ucvector_push_back(&decoded, 0); error = lodepng_add_text(info, key, (char*)decoded.data); break; } lodepng_free(key); ucvector_cleanup(&decoded); return error; } /*international text chunk (iTXt)*/ static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings, const unsigned char* data, size_t chunkLength) { unsigned error = 0; unsigned i; unsigned length, begin, compressed; char *key = 0, *langtag = 0, *transkey = 0; ucvector decoded; ucvector_init(&decoded); while(!error) /*not really a while loop, only used to break on error*/ { /*Quick check if the chunk length isn't too small. Even without check it'd still fail with other error checks below if it's too short. This just gives a different error code.*/ if(chunkLength < 5) CERROR_BREAK(error, 30); /*iTXt chunk too short*/ /*read the key*/ for(length = 0; length < chunkLength && data[length] != 0; ++length) ; if(length + 3 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination char, corrupt?*/ if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ key = (char*)lodepng_malloc(length + 1); if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ key[length] = 0; for(i = 0; i != length; ++i) key[i] = (char)data[i]; /*read the compression method*/ compressed = data[length + 1]; if(data[length + 2] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ /*even though it's not allowed by the standard, no error is thrown if there's no null termination char, if the text is empty for the next 3 texts*/ /*read the langtag*/ begin = length + 3; length = 0; for(i = begin; i < chunkLength && data[i] != 0; ++i) ++length; langtag = (char*)lodepng_malloc(length + 1); if(!langtag) CERROR_BREAK(error, 83); /*alloc fail*/ langtag[length] = 0; for(i = 0; i != length; ++i) langtag[i] = (char)data[begin + i]; /*read the transkey*/ begin += length + 1; length = 0; for(i = begin; i < chunkLength && data[i] != 0; ++i) ++length; transkey = (char*)lodepng_malloc(length + 1); if(!transkey) CERROR_BREAK(error, 83); /*alloc fail*/ transkey[length] = 0; for(i = 0; i != length; ++i) transkey[i] = (char)data[begin + i]; /*read the actual text*/ begin += length + 1; length = chunkLength < begin ? 0 : chunkLength - begin; if(compressed) { /*will fail if zlib error, e.g. if length is too small*/ error = zlib_decompress(&decoded.data, &decoded.size, (unsigned char*)(&data[begin]), length, zlibsettings); if(error) break; if(decoded.allocsize < decoded.size) decoded.allocsize = decoded.size; ucvector_push_back(&decoded, 0); } else { if(!ucvector_resize(&decoded, length + 1)) CERROR_BREAK(error, 83 /*alloc fail*/); decoded.data[length] = 0; for(i = 0; i != length; ++i) decoded.data[i] = data[begin + i]; } error = lodepng_add_itext(info, key, langtag, transkey, (char*)decoded.data); break; } lodepng_free(key); lodepng_free(langtag); lodepng_free(transkey); ucvector_cleanup(&decoded); return error; } static unsigned readChunk_tIME(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { if(chunkLength != 7) return 73; /*invalid tIME chunk size*/ info->time_defined = 1; info->time.year = 256u * data[0] + data[1]; info->time.month = data[2]; info->time.day = data[3]; info->time.hour = data[4]; info->time.minute = data[5]; info->time.second = data[6]; return 0; /* OK */ } static unsigned readChunk_pHYs(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { if(chunkLength != 9) return 74; /*invalid pHYs chunk size*/ info->phys_defined = 1; info->phys_x = 16777216u * data[0] + 65536u * data[1] + 256u * data[2] + data[3]; info->phys_y = 16777216u * data[4] + 65536u * data[5] + 256u * data[6] + data[7]; info->phys_unit = data[8]; return 0; /* OK */ } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /*read a PNG, the result will be in the same color type as the PNG (hence "generic")*/ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, LodePNGState* state, const unsigned char* in, size_t insize) { unsigned char IEND = 0; const unsigned char* chunk; size_t i; ucvector idat; /*the data from idat chunks*/ ucvector scanlines; size_t predict; size_t numpixels; /*for unknown chunk order*/ unsigned unknown = 0; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS unsigned critical_pos = 1; /*1 = after IHDR, 2 = after PLTE, 3 = after IDAT*/ #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /*provide some proper output values if error will happen*/ *out = 0; state->error = lodepng_inspect(w, h, state, in, insize); /*reads header and resets other parameters in state->info_png*/ if(state->error) return; numpixels = *w * *h; /*multiplication overflow*/ if(*h != 0 && numpixels / *h != *w) CERROR_RETURN(state->error, 92); /*multiplication overflow possible further below. Allows up to 2^31-1 pixel bytes with 16-bit RGBA, the rest is room for filter bytes.*/ if(numpixels > 268435455) CERROR_RETURN(state->error, 92); ucvector_init(&idat); chunk = &in[33]; /*first byte of the first chunk after the header*/ /*loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. IDAT data is put at the start of the in buffer*/ while(!IEND && !state->error) { unsigned chunkLength; const unsigned char* data; /*the data in the chunk*/ /*error: size of the in buffer too small to contain next chunk*/ if((size_t)((chunk - in) + 12) > insize || chunk < in) CERROR_BREAK(state->error, 30); /*length of the data of the chunk, excluding the length bytes, chunk type and CRC bytes*/ chunkLength = lodepng_chunk_length(chunk); /*error: chunk length larger than the max PNG chunk size*/ if(chunkLength > 2147483647) CERROR_BREAK(state->error, 63); if((size_t)((chunk - in) + chunkLength + 12) > insize || (chunk + chunkLength + 12) < in) { CERROR_BREAK(state->error, 64); /*error: size of the in buffer too small to contain next chunk*/ } data = lodepng_chunk_data_const(chunk); /*IDAT chunk, containing compressed image data*/ if(lodepng_chunk_type_equals(chunk, "IDAT")) { size_t oldsize = idat.size; if(!ucvector_resize(&idat, oldsize + chunkLength)) CERROR_BREAK(state->error, 83 /*alloc fail*/); for(i = 0; i != chunkLength; ++i) idat.data[oldsize + i] = data[i]; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS critical_pos = 3; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } /*IEND chunk*/ else if(lodepng_chunk_type_equals(chunk, "IEND")) { IEND = 1; } /*palette chunk (PLTE)*/ else if(lodepng_chunk_type_equals(chunk, "PLTE")) { state->error = readChunk_PLTE(&state->info_png.color, data, chunkLength); if(state->error) break; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS critical_pos = 2; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } /*palette transparency chunk (tRNS)*/ else if(lodepng_chunk_type_equals(chunk, "tRNS")) { state->error = readChunk_tRNS(&state->info_png.color, data, chunkLength); if(state->error) break; } #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*background color chunk (bKGD)*/ else if(lodepng_chunk_type_equals(chunk, "bKGD")) { state->error = readChunk_bKGD(&state->info_png, data, chunkLength); if(state->error) break; } /*text chunk (tEXt)*/ else if(lodepng_chunk_type_equals(chunk, "tEXt")) { if(state->decoder.read_text_chunks) { state->error = readChunk_tEXt(&state->info_png, data, chunkLength); if(state->error) break; } } /*compressed text chunk (zTXt)*/ else if(lodepng_chunk_type_equals(chunk, "zTXt")) { if(state->decoder.read_text_chunks) { state->error = readChunk_zTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength); if(state->error) break; } } /*international text chunk (iTXt)*/ else if(lodepng_chunk_type_equals(chunk, "iTXt")) { if(state->decoder.read_text_chunks) { state->error = readChunk_iTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength); if(state->error) break; } } else if(lodepng_chunk_type_equals(chunk, "tIME")) { state->error = readChunk_tIME(&state->info_png, data, chunkLength); if(state->error) break; } else if(lodepng_chunk_type_equals(chunk, "pHYs")) { state->error = readChunk_pHYs(&state->info_png, data, chunkLength); if(state->error) break; } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ else /*it's not an implemented chunk type, so ignore it: skip over the data*/ { /*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/ if(!lodepng_chunk_ancillary(chunk)) CERROR_BREAK(state->error, 69); unknown = 1; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS if(state->decoder.remember_unknown_chunks) { state->error = lodepng_chunk_append(&state->info_png.unknown_chunks_data[critical_pos - 1], &state->info_png.unknown_chunks_size[critical_pos - 1], chunk); if(state->error) break; } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } if(!state->decoder.ignore_crc && !unknown) /*check CRC if wanted, only on known chunk types*/ { if(lodepng_chunk_check_crc(chunk)) CERROR_BREAK(state->error, 57); /*invalid CRC*/ } if(!IEND) chunk = lodepng_chunk_next_const(chunk); } ucvector_init(&scanlines); /*predict output size, to allocate exact size for output buffer to avoid more dynamic allocation. If the decompressed size does not match the prediction, the image must be corrupt.*/ if(state->info_png.interlace_method == 0) { /*The extra *h is added because this are the filter bytes every scanline starts with*/ predict = lodepng_get_raw_size_idat(*w, *h, &state->info_png.color) + *h; } else { /*Adam-7 interlaced: predicted size is the sum of the 7 sub-images sizes*/ const LodePNGColorMode* color = &state->info_png.color; predict = 0; predict += lodepng_get_raw_size_idat((*w + 7) / 8, (*h + 7) / 8, color) + (*h + 7) / 8; if(*w > 4) predict += lodepng_get_raw_size_idat((*w + 3) / 8, (*h + 7) / 8, color) + (*h + 7) / 8; predict += lodepng_get_raw_size_idat((*w + 3) / 4, (*h + 3) / 8, color) + (*h + 3) / 8; if(*w > 2) predict += lodepng_get_raw_size_idat((*w + 1) / 4, (*h + 3) / 4, color) + (*h + 3) / 4; predict += lodepng_get_raw_size_idat((*w + 1) / 2, (*h + 1) / 4, color) + (*h + 1) / 4; if(*w > 1) predict += lodepng_get_raw_size_idat((*w + 0) / 2, (*h + 1) / 2, color) + (*h + 1) / 2; predict += lodepng_get_raw_size_idat((*w + 0) / 1, (*h + 0) / 2, color) + (*h + 0) / 2; } if(!state->error && !ucvector_reserve(&scanlines, predict)) state->error = 83; /*alloc fail*/ if(!state->error) { state->error = zlib_decompress(&scanlines.data, &scanlines.size, idat.data, idat.size, &state->decoder.zlibsettings); if(!state->error && scanlines.size != predict) state->error = 91; /*decompressed size doesn't match prediction*/ } ucvector_cleanup(&idat); if(!state->error) { size_t outsize = lodepng_get_raw_size(*w, *h, &state->info_png.color); ucvector outv; ucvector_init(&outv); if(!ucvector_resizev(&outv, outsize, 0)) state->error = 83; /*alloc fail*/ if(!state->error) state->error = postProcessScanlines(outv.data, scanlines.data, *w, *h, &state->info_png); *out = outv.data; } ucvector_cleanup(&scanlines); } unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, LodePNGState* state, const unsigned char* in, size_t insize) { *out = 0; decodeGeneric(out, w, h, state, in, insize); if(state->error) return state->error; if(!state->decoder.color_convert || lodepng_color_mode_equal(&state->info_raw, &state->info_png.color)) { /*same color type, no copying or converting of data needed*/ /*store the info_png color settings on the info_raw so that the info_raw still reflects what colortype the raw image has to the end user*/ if(!state->decoder.color_convert) { state->error = lodepng_color_mode_copy(&state->info_raw, &state->info_png.color); if(state->error) return state->error; } } else { /*color conversion needed; sort of copy of the data*/ unsigned char* data = *out; size_t outsize; /*TODO: check if this works according to the statement in the documentation: "The converter can convert from greyscale input color type, to 8-bit greyscale or greyscale with alpha"*/ if(!(state->info_raw.colortype == LCT_RGB || state->info_raw.colortype == LCT_RGBA) && !(state->info_raw.bitdepth == 8)) { return 56; /*unsupported color mode conversion*/ } outsize = lodepng_get_raw_size(*w, *h, &state->info_raw); *out = (unsigned char*)lodepng_malloc(outsize); if(!(*out)) { state->error = 83; /*alloc fail*/ } else state->error = lodepng_convert(*out, data, &state->info_raw, &state->info_png.color, *w, *h); lodepng_free(data); } return state->error; } unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize, LodePNGColorType colortype, unsigned bitdepth) { unsigned error; LodePNGState state; lodepng_state_init(&state); state.info_raw.colortype = colortype; state.info_raw.bitdepth = bitdepth; error = lodepng_decode(out, w, h, &state, in, insize); lodepng_state_cleanup(&state); return error; } unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) { return lodepng_decode_memory(out, w, h, in, insize, LCT_RGBA, 8); } unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) { return lodepng_decode_memory(out, w, h, in, insize, LCT_RGB, 8); } #ifdef LODEPNG_COMPILE_DISK unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename, LodePNGColorType colortype, unsigned bitdepth) { unsigned char* buffer; size_t buffersize; unsigned error; error = lodepng_load_file(&buffer, &buffersize, filename); if(!error) error = lodepng_decode_memory(out, w, h, buffer, buffersize, colortype, bitdepth); lodepng_free(buffer); return error; } unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) { return lodepng_decode_file(out, w, h, filename, LCT_RGBA, 8); } unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) { return lodepng_decode_file(out, w, h, filename, LCT_RGB, 8); } #endif /*LODEPNG_COMPILE_DISK*/ void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings) { settings->color_convert = 1; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS settings->read_text_chunks = 1; settings->remember_unknown_chunks = 0; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ settings->ignore_crc = 0; lodepng_decompress_settings_init(&settings->zlibsettings); } #endif /*LODEPNG_COMPILE_DECODER*/ #if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) void lodepng_state_init(LodePNGState* state) { #ifdef LODEPNG_COMPILE_DECODER lodepng_decoder_settings_init(&state->decoder); #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER lodepng_encoder_settings_init(&state->encoder); #endif /*LODEPNG_COMPILE_ENCODER*/ lodepng_color_mode_init(&state->info_raw); lodepng_info_init(&state->info_png); state->error = 1; } void lodepng_state_cleanup(LodePNGState* state) { lodepng_color_mode_cleanup(&state->info_raw); lodepng_info_cleanup(&state->info_png); } void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source) { lodepng_state_cleanup(dest); *dest = *source; lodepng_color_mode_init(&dest->info_raw); lodepng_info_init(&dest->info_png); dest->error = lodepng_color_mode_copy(&dest->info_raw, &source->info_raw); if(dest->error) return; dest->error = lodepng_info_copy(&dest->info_png, &source->info_png); if(dest->error) return; } #endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ #ifdef LODEPNG_COMPILE_ENCODER /* ////////////////////////////////////////////////////////////////////////// */ /* / PNG Encoder / */ /* ////////////////////////////////////////////////////////////////////////// */ /*chunkName must be string of 4 characters*/ static unsigned addChunk(ucvector* out, const char* chunkName, const unsigned char* data, size_t length) { CERROR_TRY_RETURN(lodepng_chunk_create(&out->data, &out->size, (unsigned)length, chunkName, data)); out->allocsize = out->size; /*fix the allocsize again*/ return 0; } static void writeSignature(ucvector* out) { /*8 bytes PNG signature, aka the magic bytes*/ ucvector_push_back(out, 137); ucvector_push_back(out, 80); ucvector_push_back(out, 78); ucvector_push_back(out, 71); ucvector_push_back(out, 13); ucvector_push_back(out, 10); ucvector_push_back(out, 26); ucvector_push_back(out, 10); } static unsigned addChunk_IHDR(ucvector* out, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth, unsigned interlace_method) { unsigned error = 0; ucvector header; ucvector_init(&header); lodepng_add32bitInt(&header, w); /*width*/ lodepng_add32bitInt(&header, h); /*height*/ ucvector_push_back(&header, (unsigned char)bitdepth); /*bit depth*/ ucvector_push_back(&header, (unsigned char)colortype); /*color type*/ ucvector_push_back(&header, 0); /*compression method*/ ucvector_push_back(&header, 0); /*filter method*/ ucvector_push_back(&header, interlace_method); /*interlace method*/ error = addChunk(out, "IHDR", header.data, header.size); ucvector_cleanup(&header); return error; } static unsigned addChunk_PLTE(ucvector* out, const LodePNGColorMode* info) { unsigned error = 0; size_t i; ucvector PLTE; ucvector_init(&PLTE); for(i = 0; i != info->palettesize * 4; ++i) { /*add all channels except alpha channel*/ if(i % 4 != 3) ucvector_push_back(&PLTE, info->palette[i]); } error = addChunk(out, "PLTE", PLTE.data, PLTE.size); ucvector_cleanup(&PLTE); return error; } static unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info) { unsigned error = 0; size_t i; ucvector tRNS; ucvector_init(&tRNS); if(info->colortype == LCT_PALETTE) { size_t amount = info->palettesize; /*the tail of palette values that all have 255 as alpha, does not have to be encoded*/ for(i = info->palettesize; i != 0; --i) { if(info->palette[4 * (i - 1) + 3] == 255) --amount; else break; } /*add only alpha channel*/ for(i = 0; i != amount; ++i) ucvector_push_back(&tRNS, info->palette[4 * i + 3]); } else if(info->colortype == LCT_GREY) { if(info->key_defined) { ucvector_push_back(&tRNS, (unsigned char)(info->key_r / 256)); ucvector_push_back(&tRNS, (unsigned char)(info->key_r % 256)); } } else if(info->colortype == LCT_RGB) { if(info->key_defined) { ucvector_push_back(&tRNS, (unsigned char)(info->key_r / 256)); ucvector_push_back(&tRNS, (unsigned char)(info->key_r % 256)); ucvector_push_back(&tRNS, (unsigned char)(info->key_g / 256)); ucvector_push_back(&tRNS, (unsigned char)(info->key_g % 256)); ucvector_push_back(&tRNS, (unsigned char)(info->key_b / 256)); ucvector_push_back(&tRNS, (unsigned char)(info->key_b % 256)); } } error = addChunk(out, "tRNS", tRNS.data, tRNS.size); ucvector_cleanup(&tRNS); return error; } static unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t datasize, LodePNGCompressSettings* zlibsettings) { ucvector zlibdata; unsigned error = 0; /*compress with the Zlib compressor*/ ucvector_init(&zlibdata); error = zlib_compress(&zlibdata.data, &zlibdata.size, data, datasize, zlibsettings); if(!error) error = addChunk(out, "IDAT", zlibdata.data, zlibdata.size); ucvector_cleanup(&zlibdata); return error; } static unsigned addChunk_IEND(ucvector* out) { unsigned error = 0; error = addChunk(out, "IEND", 0, 0); return error; } #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* textstring) { unsigned error = 0; size_t i; ucvector text; ucvector_init(&text); for(i = 0; keyword[i] != 0; ++i) ucvector_push_back(&text, (unsigned char)keyword[i]); if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ ucvector_push_back(&text, 0); /*0 termination char*/ for(i = 0; textstring[i] != 0; ++i) ucvector_push_back(&text, (unsigned char)textstring[i]); error = addChunk(out, "tEXt", text.data, text.size); ucvector_cleanup(&text); return error; } static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* textstring, LodePNGCompressSettings* zlibsettings) { unsigned error = 0; ucvector data, compressed; size_t i, textsize = strlen(textstring); ucvector_init(&data); ucvector_init(&compressed); for(i = 0; keyword[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)keyword[i]); if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ ucvector_push_back(&data, 0); /*0 termination char*/ ucvector_push_back(&data, 0); /*compression method: 0*/ error = zlib_compress(&compressed.data, &compressed.size, (unsigned char*)textstring, textsize, zlibsettings); if(!error) { for(i = 0; i != compressed.size; ++i) ucvector_push_back(&data, compressed.data[i]); error = addChunk(out, "zTXt", data.data, data.size); } ucvector_cleanup(&compressed); ucvector_cleanup(&data); return error; } static unsigned addChunk_iTXt(ucvector* out, unsigned compressed, const char* keyword, const char* langtag, const char* transkey, const char* textstring, LodePNGCompressSettings* zlibsettings) { unsigned error = 0; ucvector data; size_t i, textsize = strlen(textstring); ucvector_init(&data); for(i = 0; keyword[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)keyword[i]); if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ ucvector_push_back(&data, 0); /*null termination char*/ ucvector_push_back(&data, compressed ? 1 : 0); /*compression flag*/ ucvector_push_back(&data, 0); /*compression method*/ for(i = 0; langtag[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)langtag[i]); ucvector_push_back(&data, 0); /*null termination char*/ for(i = 0; transkey[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)transkey[i]); ucvector_push_back(&data, 0); /*null termination char*/ if(compressed) { ucvector compressed_data; ucvector_init(&compressed_data); error = zlib_compress(&compressed_data.data, &compressed_data.size, (unsigned char*)textstring, textsize, zlibsettings); if(!error) { for(i = 0; i != compressed_data.size; ++i) ucvector_push_back(&data, compressed_data.data[i]); } ucvector_cleanup(&compressed_data); } else /*not compressed*/ { for(i = 0; textstring[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)textstring[i]); } if(!error) error = addChunk(out, "iTXt", data.data, data.size); ucvector_cleanup(&data); return error; } static unsigned addChunk_bKGD(ucvector* out, const LodePNGInfo* info) { unsigned error = 0; ucvector bKGD; ucvector_init(&bKGD); if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) { ucvector_push_back(&bKGD, (unsigned char)(info->background_r / 256)); ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); } else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) { ucvector_push_back(&bKGD, (unsigned char)(info->background_r / 256)); ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); ucvector_push_back(&bKGD, (unsigned char)(info->background_g / 256)); ucvector_push_back(&bKGD, (unsigned char)(info->background_g % 256)); ucvector_push_back(&bKGD, (unsigned char)(info->background_b / 256)); ucvector_push_back(&bKGD, (unsigned char)(info->background_b % 256)); } else if(info->color.colortype == LCT_PALETTE) { ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); /*palette index*/ } error = addChunk(out, "bKGD", bKGD.data, bKGD.size); ucvector_cleanup(&bKGD); return error; } static unsigned addChunk_tIME(ucvector* out, const LodePNGTime* time) { unsigned error = 0; unsigned char* data = (unsigned char*)lodepng_malloc(7); if(!data) return 83; /*alloc fail*/ data[0] = (unsigned char)(time->year / 256); data[1] = (unsigned char)(time->year % 256); data[2] = (unsigned char)time->month; data[3] = (unsigned char)time->day; data[4] = (unsigned char)time->hour; data[5] = (unsigned char)time->minute; data[6] = (unsigned char)time->second; error = addChunk(out, "tIME", data, 7); lodepng_free(data); return error; } static unsigned addChunk_pHYs(ucvector* out, const LodePNGInfo* info) { unsigned error = 0; ucvector data; ucvector_init(&data); lodepng_add32bitInt(&data, info->phys_x); lodepng_add32bitInt(&data, info->phys_y); ucvector_push_back(&data, info->phys_unit); error = addChunk(out, "pHYs", data.data, data.size); ucvector_cleanup(&data); return error; } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ static void filterScanline(unsigned char* out, const unsigned char* scanline, const unsigned char* prevline, size_t length, size_t bytewidth, unsigned char filterType) { size_t i; switch(filterType) { case 0: /*None*/ for(i = 0; i != length; ++i) out[i] = scanline[i]; break; case 1: /*Sub*/ for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - scanline[i - bytewidth]; break; case 2: /*Up*/ if(prevline) { for(i = 0; i != length; ++i) out[i] = scanline[i] - prevline[i]; } else { for(i = 0; i != length; ++i) out[i] = scanline[i]; } break; case 3: /*Average*/ if(prevline) { for(i = 0; i != bytewidth; ++i) out[i] = scanline[i] - prevline[i] / 2; for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - ((scanline[i - bytewidth] + prevline[i]) / 2); } else { for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - scanline[i - bytewidth] / 2; } break; case 4: /*Paeth*/ if(prevline) { /*paethPredictor(0, prevline[i], 0) is always prevline[i]*/ for(i = 0; i != bytewidth; ++i) out[i] = (scanline[i] - prevline[i]); for(i = bytewidth; i < length; ++i) { out[i] = (scanline[i] - paethPredictor(scanline[i - bytewidth], prevline[i], prevline[i - bytewidth])); } } else { for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; /*paethPredictor(scanline[i - bytewidth], 0, 0) is always scanline[i - bytewidth]*/ for(i = bytewidth; i < length; ++i) out[i] = (scanline[i] - scanline[i - bytewidth]); } break; default: return; /*unexisting filter type given*/ } } /* log2 approximation. A slight bit faster than std::log. */ static float flog2(float f) { float result = 0; while(f > 32) { result += 4; f /= 16; } while(f > 2) { ++result; f /= 2; } return result + 1.442695f * (f * f * f / 3 - 3 * f * f / 2 + 3 * f - 1.83333f); } static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, const LodePNGColorMode* info, const LodePNGEncoderSettings* settings) { /* For PNG filter method 0 out must be a buffer with as size: h + (w * h * bpp + 7) / 8, because there are the scanlines with 1 extra byte per scanline */ unsigned bpp = lodepng_get_bpp(info); /*the width of a scanline in bytes, not including the filter type*/ size_t linebytes = (w * bpp + 7) / 8; /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ size_t bytewidth = (bpp + 7) / 8; const unsigned char* prevline = 0; unsigned x, y; unsigned error = 0; LodePNGFilterStrategy strategy = settings->filter_strategy; /* There is a heuristic called the minimum sum of absolute differences heuristic, suggested by the PNG standard: * If the image type is Palette, or the bit depth is smaller than 8, then do not filter the image (i.e. use fixed filtering, with the filter None). * (The other case) If the image type is Grayscale or RGB (with or without Alpha), and the bit depth is not smaller than 8, then use adaptive filtering heuristic as follows: independently for each row, apply all five filters and select the filter that produces the smallest sum of absolute values per row. This heuristic is used if filter strategy is LFS_MINSUM and filter_palette_zero is true. If filter_palette_zero is true and filter_strategy is not LFS_MINSUM, the above heuristic is followed, but for "the other case", whatever strategy filter_strategy is set to instead of the minimum sum heuristic is used. */ if(settings->filter_palette_zero && (info->colortype == LCT_PALETTE || info->bitdepth < 8)) strategy = LFS_ZERO; if(bpp == 0) return 31; /*error: invalid color type*/ if(strategy == LFS_ZERO) { for(y = 0; y != h; ++y) { size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ size_t inindex = linebytes * y; out[outindex] = 0; /*filter type byte*/ filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, 0); prevline = &in[inindex]; } } else if(strategy == LFS_MINSUM) { /*adaptive filtering*/ size_t sum[5]; ucvector attempt[5]; /*five filtering attempts, one for each filter type*/ size_t smallest = 0; unsigned char type, bestType = 0; for(type = 0; type != 5; ++type) { ucvector_init(&attempt[type]); if(!ucvector_resize(&attempt[type], linebytes)) return 83; /*alloc fail*/ } if(!error) { for(y = 0; y != h; ++y) { /*try the 5 filter types*/ for(type = 0; type != 5; ++type) { filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type); /*calculate the sum of the result*/ sum[type] = 0; if(type == 0) { for(x = 0; x != linebytes; ++x) sum[type] += (unsigned char)(attempt[type].data[x]); } else { for(x = 0; x != linebytes; ++x) { /*For differences, each byte should be treated as signed, values above 127 are negative (converted to signed char). Filtertype 0 isn't a difference though, so use unsigned there. This means filtertype 0 is almost never chosen, but that is justified.*/ unsigned char s = attempt[type].data[x]; sum[type] += s < 128 ? s : (255U - s); } } /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ if(type == 0 || sum[type] < smallest) { bestType = type; smallest = sum[type]; } } prevline = &in[y * linebytes]; /*now fill the out values*/ out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; } } for(type = 0; type != 5; ++type) ucvector_cleanup(&attempt[type]); } else if(strategy == LFS_ENTROPY) { float sum[5]; ucvector attempt[5]; /*five filtering attempts, one for each filter type*/ float smallest = 0; unsigned type, bestType = 0; unsigned count[256]; for(type = 0; type != 5; ++type) { ucvector_init(&attempt[type]); if(!ucvector_resize(&attempt[type], linebytes)) return 83; /*alloc fail*/ } for(y = 0; y != h; ++y) { /*try the 5 filter types*/ for(type = 0; type != 5; ++type) { filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type); for(x = 0; x != 256; ++x) count[x] = 0; for(x = 0; x != linebytes; ++x) ++count[attempt[type].data[x]]; ++count[type]; /*the filter type itself is part of the scanline*/ sum[type] = 0; for(x = 0; x != 256; ++x) { float p = count[x] / (float)(linebytes + 1); sum[type] += count[x] == 0 ? 0 : flog2(1 / p) * p; } /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ if(type == 0 || sum[type] < smallest) { bestType = type; smallest = sum[type]; } } prevline = &in[y * linebytes]; /*now fill the out values*/ out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; } for(type = 0; type != 5; ++type) ucvector_cleanup(&attempt[type]); } else if(strategy == LFS_PREDEFINED) { for(y = 0; y != h; ++y) { size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ size_t inindex = linebytes * y; unsigned char type = settings->predefined_filters[y]; out[outindex] = type; /*filter type byte*/ filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type); prevline = &in[inindex]; } } else if(strategy == LFS_BRUTE_FORCE) { /*brute force filter chooser. deflate the scanline after every filter attempt to see which one deflates best. This is very slow and gives only slightly smaller, sometimes even larger, result*/ size_t size[5]; ucvector attempt[5]; /*five filtering attempts, one for each filter type*/ size_t smallest = 0; unsigned type = 0, bestType = 0; unsigned char* dummy; LodePNGCompressSettings zlibsettings = settings->zlibsettings; /*use fixed tree on the attempts so that the tree is not adapted to the filtertype on purpose, to simulate the true case where the tree is the same for the whole image. Sometimes it gives better result with dynamic tree anyway. Using the fixed tree sometimes gives worse, but in rare cases better compression. It does make this a bit less slow, so it's worth doing this.*/ zlibsettings.btype = 1; /*a custom encoder likely doesn't read the btype setting and is optimized for complete PNG images only, so disable it*/ zlibsettings.custom_zlib = 0; zlibsettings.custom_deflate = 0; for(type = 0; type != 5; ++type) { ucvector_init(&attempt[type]); ucvector_resize(&attempt[type], linebytes); /*todo: give error if resize failed*/ } for(y = 0; y != h; ++y) /*try the 5 filter types*/ { for(type = 0; type != 5; ++type) { unsigned testsize = attempt[type].size; /*if(testsize > 8) testsize /= 8;*/ /*it already works good enough by testing a part of the row*/ filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type); size[type] = 0; dummy = 0; zlib_compress(&dummy, &size[type], attempt[type].data, testsize, &zlibsettings); lodepng_free(dummy); /*check if this is smallest size (or if type == 0 it's the first case so always store the values)*/ if(type == 0 || size[type] < smallest) { bestType = type; smallest = size[type]; } } prevline = &in[y * linebytes]; out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; } for(type = 0; type != 5; ++type) ucvector_cleanup(&attempt[type]); } else return 88; /* unknown filter strategy */ return error; } static void addPaddingBits(unsigned char* out, const unsigned char* in, size_t olinebits, size_t ilinebits, unsigned h) { /*The opposite of the removePaddingBits function olinebits must be >= ilinebits*/ unsigned y; size_t diff = olinebits - ilinebits; size_t obp = 0, ibp = 0; /*bit pointers*/ for(y = 0; y != h; ++y) { size_t x; for(x = 0; x < ilinebits; ++x) { unsigned char bit = readBitFromReversedStream(&ibp, in); setBitOfReversedStream(&obp, out, bit); } /*obp += diff; --> no, fill in some value in the padding bits too, to avoid "Use of uninitialised value of size ###" warning from valgrind*/ for(x = 0; x != diff; ++x) setBitOfReversedStream(&obp, out, 0); } } /* in: non-interlaced image with size w*h out: the same pixels, but re-ordered according to PNG's Adam7 interlacing, with no padding bits between scanlines, but between reduced images so that each reduced image starts at a byte. bpp: bits per pixel there are no padding bits, not between scanlines, not between reduced images in has the following size in bits: w * h * bpp. out is possibly bigger due to padding bits between reduced images NOTE: comments about padding bits are only relevant if bpp < 8 */ static void Adam7_interlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) { unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; unsigned i; Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); if(bpp >= 8) { for(i = 0; i != 7; ++i) { unsigned x, y, b; size_t bytewidth = bpp / 8; for(y = 0; y < passh[i]; ++y) for(x = 0; x < passw[i]; ++x) { size_t pixelinstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; size_t pixeloutstart = passstart[i] + (y * passw[i] + x) * bytewidth; for(b = 0; b < bytewidth; ++b) { out[pixeloutstart + b] = in[pixelinstart + b]; } } } } else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ { for(i = 0; i != 7; ++i) { unsigned x, y, b; unsigned ilinebits = bpp * passw[i]; unsigned olinebits = bpp * w; size_t obp, ibp; /*bit pointers (for out and in buffer)*/ for(y = 0; y < passh[i]; ++y) for(x = 0; x < passw[i]; ++x) { ibp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; obp = (8 * passstart[i]) + (y * ilinebits + x * bpp); for(b = 0; b < bpp; ++b) { unsigned char bit = readBitFromReversedStream(&ibp, in); setBitOfReversedStream(&obp, out, bit); } } } } } /*out must be buffer big enough to contain uncompressed IDAT chunk data, and in must contain the full image. return value is error**/ static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const unsigned char* in, unsigned w, unsigned h, const LodePNGInfo* info_png, const LodePNGEncoderSettings* settings) { /* This function converts the pure 2D image with the PNG's colortype, into filtered-padded-interlaced data. Steps: *) if no Adam7: 1) add padding bits (= posible extra bits per scanline if bpp < 8) 2) filter *) if adam7: 1) Adam7_interlace 2) 7x add padding bits 3) 7x filter */ unsigned bpp = lodepng_get_bpp(&info_png->color); unsigned error = 0; if(info_png->interlace_method == 0) { *outsize = h + (h * ((w * bpp + 7) / 8)); /*image size plus an extra byte per scanline + possible padding bits*/ *out = (unsigned char*)lodepng_malloc(*outsize); if(!(*out) && (*outsize)) error = 83; /*alloc fail*/ if(!error) { /*non multiple of 8 bits per scanline, padding bits needed per scanline*/ if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8) { unsigned char* padded = (unsigned char*)lodepng_malloc(h * ((w * bpp + 7) / 8)); if(!padded) error = 83; /*alloc fail*/ if(!error) { addPaddingBits(padded, in, ((w * bpp + 7) / 8) * 8, w * bpp, h); error = filter(*out, padded, w, h, &info_png->color, settings); } lodepng_free(padded); } else { /*we can immediatly filter into the out buffer, no other steps needed*/ error = filter(*out, in, w, h, &info_png->color, settings); } } } else /*interlace_method is 1 (Adam7)*/ { unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; unsigned char* adam7; Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); *outsize = filter_passstart[7]; /*image size plus an extra byte per scanline + possible padding bits*/ *out = (unsigned char*)lodepng_malloc(*outsize); if(!(*out)) error = 83; /*alloc fail*/ adam7 = (unsigned char*)lodepng_malloc(passstart[7]); if(!adam7 && passstart[7]) error = 83; /*alloc fail*/ if(!error) { unsigned i; Adam7_interlace(adam7, in, w, h, bpp); for(i = 0; i != 7; ++i) { if(bpp < 8) { unsigned char* padded = (unsigned char*)lodepng_malloc(padded_passstart[i + 1] - padded_passstart[i]); if(!padded) ERROR_BREAK(83); /*alloc fail*/ addPaddingBits(padded, &adam7[passstart[i]], ((passw[i] * bpp + 7) / 8) * 8, passw[i] * bpp, passh[i]); error = filter(&(*out)[filter_passstart[i]], padded, passw[i], passh[i], &info_png->color, settings); lodepng_free(padded); } else { error = filter(&(*out)[filter_passstart[i]], &adam7[padded_passstart[i]], passw[i], passh[i], &info_png->color, settings); } if(error) break; } } lodepng_free(adam7); } return error; } /* palette must have 4 * palettesize bytes allocated, and given in format RGBARGBARGBARGBA... returns 0 if the palette is opaque, returns 1 if the palette has a single color with alpha 0 ==> color key returns 2 if the palette is semi-translucent. */ static unsigned getPaletteTranslucency(const unsigned char* palette, size_t palettesize) { size_t i; unsigned key = 0; unsigned r = 0, g = 0, b = 0; /*the value of the color with alpha 0, so long as color keying is possible*/ for(i = 0; i != palettesize; ++i) { if(!key && palette[4 * i + 3] == 0) { r = palette[4 * i + 0]; g = palette[4 * i + 1]; b = palette[4 * i + 2]; key = 1; i = (size_t)(-1); /*restart from beginning, to detect earlier opaque colors with key's value*/ } else if(palette[4 * i + 3] != 255) return 2; /*when key, no opaque RGB may have key's RGB*/ else if(key && r == palette[i * 4 + 0] && g == palette[i * 4 + 1] && b == palette[i * 4 + 2]) return 2; } return key; } #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS static unsigned addUnknownChunks(ucvector* out, unsigned char* data, size_t datasize) { unsigned char* inchunk = data; while((size_t)(inchunk - data) < datasize) { CERROR_TRY_RETURN(lodepng_chunk_append(&out->data, &out->size, inchunk)); out->allocsize = out->size; /*fix the allocsize again*/ inchunk = lodepng_chunk_next(inchunk); } return 0; } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ unsigned lodepng_encode(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h, LodePNGState* state) { LodePNGInfo info; ucvector outv; unsigned char* data = 0; /*uncompressed version of the IDAT chunk data*/ size_t datasize = 0; /*provide some proper output values if error will happen*/ *out = 0; *outsize = 0; state->error = 0; lodepng_info_init(&info); lodepng_info_copy(&info, &state->info_png); if((info.color.colortype == LCT_PALETTE || state->encoder.force_palette) && (info.color.palettesize == 0 || info.color.palettesize > 256)) { state->error = 68; /*invalid palette size, it is only allowed to be 1-256*/ return state->error; } if(state->encoder.auto_convert) { state->error = lodepng_auto_choose_color(&info.color, image, w, h, &state->info_raw); } if(state->error) return state->error; if(state->encoder.zlibsettings.btype > 2) { CERROR_RETURN_ERROR(state->error, 61); /*error: unexisting btype*/ } if(state->info_png.interlace_method > 1) { CERROR_RETURN_ERROR(state->error, 71); /*error: unexisting interlace mode*/ } state->error = checkColorValidity(info.color.colortype, info.color.bitdepth); if(state->error) return state->error; /*error: unexisting color type given*/ state->error = checkColorValidity(state->info_raw.colortype, state->info_raw.bitdepth); if(state->error) return state->error; /*error: unexisting color type given*/ if(!lodepng_color_mode_equal(&state->info_raw, &info.color)) { unsigned char* converted; size_t size = (w * h * lodepng_get_bpp(&info.color) + 7) / 8; converted = (unsigned char*)lodepng_malloc(size); if(!converted && size) state->error = 83; /*alloc fail*/ if(!state->error) { state->error = lodepng_convert(converted, image, &info.color, &state->info_raw, w, h); } if(!state->error) preProcessScanlines(&data, &datasize, converted, w, h, &info, &state->encoder); lodepng_free(converted); } else preProcessScanlines(&data, &datasize, image, w, h, &info, &state->encoder); ucvector_init(&outv); while(!state->error) /*while only executed once, to break on error*/ { #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS size_t i; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /*write signature and chunks*/ writeSignature(&outv); /*IHDR*/ addChunk_IHDR(&outv, w, h, info.color.colortype, info.color.bitdepth, info.interlace_method); #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*unknown chunks between IHDR and PLTE*/ if(info.unknown_chunks_data[0]) { state->error = addUnknownChunks(&outv, info.unknown_chunks_data[0], info.unknown_chunks_size[0]); if(state->error) break; } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /*PLTE*/ if(info.color.colortype == LCT_PALETTE) { addChunk_PLTE(&outv, &info.color); } if(state->encoder.force_palette && (info.color.colortype == LCT_RGB || info.color.colortype == LCT_RGBA)) { addChunk_PLTE(&outv, &info.color); } /*tRNS*/ if(info.color.colortype == LCT_PALETTE && getPaletteTranslucency(info.color.palette, info.color.palettesize) != 0) { addChunk_tRNS(&outv, &info.color); } if((info.color.colortype == LCT_GREY || info.color.colortype == LCT_RGB) && info.color.key_defined) { addChunk_tRNS(&outv, &info.color); } #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*bKGD (must come between PLTE and the IDAt chunks*/ if(info.background_defined) addChunk_bKGD(&outv, &info); /*pHYs (must come before the IDAT chunks)*/ if(info.phys_defined) addChunk_pHYs(&outv, &info); /*unknown chunks between PLTE and IDAT*/ if(info.unknown_chunks_data[1]) { state->error = addUnknownChunks(&outv, info.unknown_chunks_data[1], info.unknown_chunks_size[1]); if(state->error) break; } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /*IDAT (multiple IDAT chunks must be consecutive)*/ state->error = addChunk_IDAT(&outv, data, datasize, &state->encoder.zlibsettings); if(state->error) break; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*tIME*/ if(info.time_defined) addChunk_tIME(&outv, &info.time); /*tEXt and/or zTXt*/ for(i = 0; i != info.text_num; ++i) { if(strlen(info.text_keys[i]) > 79) { state->error = 66; /*text chunk too large*/ break; } if(strlen(info.text_keys[i]) < 1) { state->error = 67; /*text chunk too small*/ break; } if(state->encoder.text_compression) { addChunk_zTXt(&outv, info.text_keys[i], info.text_strings[i], &state->encoder.zlibsettings); } else { addChunk_tEXt(&outv, info.text_keys[i], info.text_strings[i]); } } /*LodePNG version id in text chunk*/ if(state->encoder.add_id) { unsigned alread_added_id_text = 0; for(i = 0; i != info.text_num; ++i) { if(!strcmp(info.text_keys[i], "LodePNG")) { alread_added_id_text = 1; break; } } if(alread_added_id_text == 0) { addChunk_tEXt(&outv, "LodePNG", LODEPNG_VERSION_STRING); /*it's shorter as tEXt than as zTXt chunk*/ } } /*iTXt*/ for(i = 0; i != info.itext_num; ++i) { if(strlen(info.itext_keys[i]) > 79) { state->error = 66; /*text chunk too large*/ break; } if(strlen(info.itext_keys[i]) < 1) { state->error = 67; /*text chunk too small*/ break; } addChunk_iTXt(&outv, state->encoder.text_compression, info.itext_keys[i], info.itext_langtags[i], info.itext_transkeys[i], info.itext_strings[i], &state->encoder.zlibsettings); } /*unknown chunks between IDAT and IEND*/ if(info.unknown_chunks_data[2]) { state->error = addUnknownChunks(&outv, info.unknown_chunks_data[2], info.unknown_chunks_size[2]); if(state->error) break; } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ addChunk_IEND(&outv); break; /*this isn't really a while loop; no error happened so break out now!*/ } lodepng_info_cleanup(&info); lodepng_free(data); /*instead of cleaning the vector up, give it to the output*/ *out = outv.data; *outsize = outv.size; return state->error; } unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) { unsigned error; LodePNGState state; lodepng_state_init(&state); state.info_raw.colortype = colortype; state.info_raw.bitdepth = bitdepth; state.info_png.color.colortype = colortype; state.info_png.color.bitdepth = bitdepth; lodepng_encode(out, outsize, image, w, h, &state); error = state.error; lodepng_state_cleanup(&state); return error; } unsigned lodepng_encode32(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) { return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGBA, 8); } unsigned lodepng_encode24(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) { return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGB, 8); } #ifdef LODEPNG_COMPILE_DISK unsigned lodepng_encode_file(const char* filename, const unsigned char* image, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) { unsigned char* buffer; size_t buffersize; unsigned error = lodepng_encode_memory(&buffer, &buffersize, image, w, h, colortype, bitdepth); if(!error) error = lodepng_save_file(buffer, buffersize, filename); lodepng_free(buffer); return error; } unsigned lodepng_encode32_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) { return lodepng_encode_file(filename, image, w, h, LCT_RGBA, 8); } unsigned lodepng_encode24_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) { return lodepng_encode_file(filename, image, w, h, LCT_RGB, 8); } #endif /*LODEPNG_COMPILE_DISK*/ void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings) { lodepng_compress_settings_init(&settings->zlibsettings); settings->filter_palette_zero = 1; settings->filter_strategy = LFS_MINSUM; settings->auto_convert = 1; settings->force_palette = 0; settings->predefined_filters = 0; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS settings->add_id = 0; settings->text_compression = 1; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } #endif /*LODEPNG_COMPILE_ENCODER*/ #endif /*LODEPNG_COMPILE_PNG*/ #ifdef LODEPNG_COMPILE_ERROR_TEXT /* This returns the description of a numerical error code in English. This is also the documentation of all the error codes. */ const char* lodepng_error_text(unsigned code) { switch(code) { case 0: return "no error, everything went ok"; case 1: return "nothing done yet"; /*the Encoder/Decoder has done nothing yet, error checking makes no sense yet*/ case 10: return "end of input memory reached without huffman end code"; /*while huffman decoding*/ case 11: return "error in code tree made it jump outside of huffman tree"; /*while huffman decoding*/ case 13: return "problem while processing dynamic deflate block"; case 14: return "problem while processing dynamic deflate block"; case 15: return "problem while processing dynamic deflate block"; case 16: return "unexisting code while processing dynamic deflate block"; case 17: return "end of out buffer memory reached while inflating"; case 18: return "invalid distance code while inflating"; case 19: return "end of out buffer memory reached while inflating"; case 20: return "invalid deflate block BTYPE encountered while decoding"; case 21: return "NLEN is not ones complement of LEN in a deflate block"; /*end of out buffer memory reached while inflating: This can happen if the inflated deflate data is longer than the amount of bytes required to fill up all the pixels of the image, given the color depth and image dimensions. Something that doesn't happen in a normal, well encoded, PNG image.*/ case 22: return "end of out buffer memory reached while inflating"; case 23: return "end of in buffer memory reached while inflating"; case 24: return "invalid FCHECK in zlib header"; case 25: return "invalid compression method in zlib header"; case 26: return "FDICT encountered in zlib header while it's not used for PNG"; case 27: return "PNG file is smaller than a PNG header"; /*Checks the magic file header, the first 8 bytes of the PNG file*/ case 28: return "incorrect PNG signature, it's no PNG or corrupted"; case 29: return "first chunk is not the header chunk"; case 30: return "chunk length too large, chunk broken off at end of file"; case 31: return "illegal PNG color type or bpp"; case 32: return "illegal PNG compression method"; case 33: return "illegal PNG filter method"; case 34: return "illegal PNG interlace method"; case 35: return "chunk length of a chunk is too large or the chunk too small"; case 36: return "illegal PNG filter type encountered"; case 37: return "illegal bit depth for this color type given"; case 38: return "the palette is too big"; /*more than 256 colors*/ case 39: return "more palette alpha values given in tRNS chunk than there are colors in the palette"; case 40: return "tRNS chunk has wrong size for greyscale image"; case 41: return "tRNS chunk has wrong size for RGB image"; case 42: return "tRNS chunk appeared while it was not allowed for this color type"; case 43: return "bKGD chunk has wrong size for palette image"; case 44: return "bKGD chunk has wrong size for greyscale image"; case 45: return "bKGD chunk has wrong size for RGB image"; /*the input data is empty, maybe a PNG file doesn't exist or is in the wrong path*/ case 48: return "empty input or file doesn't exist"; case 49: return "jumped past memory while generating dynamic huffman tree"; case 50: return "jumped past memory while generating dynamic huffman tree"; case 51: return "jumped past memory while inflating huffman block"; case 52: return "jumped past memory while inflating"; case 53: return "size of zlib data too small"; case 54: return "repeat symbol in tree while there was no value symbol yet"; /*jumped past tree while generating huffman tree, this could be when the tree will have more leaves than symbols after generating it out of the given lenghts. They call this an oversubscribed dynamic bit lengths tree in zlib.*/ case 55: return "jumped past tree while generating huffman tree"; case 56: return "given output image colortype or bitdepth not supported for color conversion"; case 57: return "invalid CRC encountered (checking CRC can be disabled)"; case 58: return "invalid ADLER32 encountered (checking ADLER32 can be disabled)"; case 59: return "requested color conversion not supported"; case 60: return "invalid window size given in the settings of the encoder (must be 0-32768)"; case 61: return "invalid BTYPE given in the settings of the encoder (only 0, 1 and 2 are allowed)"; /*LodePNG leaves the choice of RGB to greyscale conversion formula to the user.*/ case 62: return "conversion from color to greyscale not supported"; case 63: return "length of a chunk too long, max allowed for PNG is 2147483647 bytes per chunk"; /*(2^31-1)*/ /*this would result in the inability of a deflated block to ever contain an end code. It must be at least 1.*/ case 64: return "the length of the END symbol 256 in the Huffman tree is 0"; case 66: return "the length of a text chunk keyword given to the encoder is longer than the maximum of 79 bytes"; case 67: return "the length of a text chunk keyword given to the encoder is smaller than the minimum of 1 byte"; case 68: return "tried to encode a PLTE chunk with a palette that has less than 1 or more than 256 colors"; case 69: return "unknown chunk type with 'critical' flag encountered by the decoder"; case 71: return "unexisting interlace mode given to encoder (must be 0 or 1)"; case 72: return "while decoding, unexisting compression method encountering in zTXt or iTXt chunk (it must be 0)"; case 73: return "invalid tIME chunk size"; case 74: return "invalid pHYs chunk size"; /*length could be wrong, or data chopped off*/ case 75: return "no null termination char found while decoding text chunk"; case 76: return "iTXt chunk too short to contain required bytes"; case 77: return "integer overflow in buffer size"; case 78: return "failed to open file for reading"; /*file doesn't exist or couldn't be opened for reading*/ case 79: return "failed to open file for writing"; case 80: return "tried creating a tree of 0 symbols"; case 81: return "lazy matching at pos 0 is impossible"; case 82: return "color conversion to palette requested while a color isn't in palette"; case 83: return "memory allocation failed"; case 84: return "given image too small to contain all pixels to be encoded"; case 86: return "impossible offset in lz77 encoding (internal bug)"; case 87: return "must provide custom zlib function pointer if LODEPNG_COMPILE_ZLIB is not defined"; case 88: return "invalid filter strategy given for LodePNGEncoderSettings.filter_strategy"; case 89: return "text chunk keyword too short or long: must have size 1-79"; /*the windowsize in the LodePNGCompressSettings. Requiring POT(==> & instead of %) makes encoding 12% faster.*/ case 90: return "windowsize must be a power of two"; case 91: return "invalid decompressed idat size"; case 92: return "too many pixels, not supported"; case 93: return "zero width or height is invalid"; } return "unknown error code"; } #endif /*LODEPNG_COMPILE_ERROR_TEXT*/ /* ////////////////////////////////////////////////////////////////////////// */ /* ////////////////////////////////////////////////////////////////////////// */ /* // C++ Wrapper // */ /* ////////////////////////////////////////////////////////////////////////// */ /* ////////////////////////////////////////////////////////////////////////// */ #ifdef LODEPNG_COMPILE_CPP namespace lodepng { #ifdef LODEPNG_COMPILE_DISK void load_file(std::vector& buffer, const std::string& filename) { std::ifstream file(filename.c_str(), std::ios::in|std::ios::binary|std::ios::ate); /*get filesize*/ std::streamsize size = 0; if(file.seekg(0, std::ios::end).good()) size = file.tellg(); if(file.seekg(0, std::ios::beg).good()) size -= file.tellg(); /*read contents of the file into the vector*/ buffer.resize(size_t(size)); if(size > 0) file.read((char*)(&buffer[0]), size); } /*write given buffer to the file, overwriting the file, it doesn't append to it.*/ void save_file(const std::vector& buffer, const std::string& filename) { std::ofstream file(filename.c_str(), std::ios::out|std::ios::binary); file.write(buffer.empty() ? 0 : (char*)&buffer[0], std::streamsize(buffer.size())); } #endif //LODEPNG_COMPILE_DISK #ifdef LODEPNG_COMPILE_ZLIB #ifdef LODEPNG_COMPILE_DECODER unsigned decompress(std::vector& out, const unsigned char* in, size_t insize, const LodePNGDecompressSettings& settings) { unsigned char* buffer = 0; size_t buffersize = 0; unsigned error = zlib_decompress(&buffer, &buffersize, in, insize, &settings); if(buffer) { out.insert(out.end(), &buffer[0], &buffer[buffersize]); lodepng_free(buffer); } return error; } unsigned decompress(std::vector& out, const std::vector& in, const LodePNGDecompressSettings& settings) { return decompress(out, in.empty() ? 0 : &in[0], in.size(), settings); } #endif //LODEPNG_COMPILE_DECODER #ifdef LODEPNG_COMPILE_ENCODER unsigned compress(std::vector& out, const unsigned char* in, size_t insize, const LodePNGCompressSettings& settings) { unsigned char* buffer = 0; size_t buffersize = 0; unsigned error = zlib_compress(&buffer, &buffersize, in, insize, &settings); if(buffer) { out.insert(out.end(), &buffer[0], &buffer[buffersize]); lodepng_free(buffer); } return error; } unsigned compress(std::vector& out, const std::vector& in, const LodePNGCompressSettings& settings) { return compress(out, in.empty() ? 0 : &in[0], in.size(), settings); } #endif //LODEPNG_COMPILE_ENCODER #endif //LODEPNG_COMPILE_ZLIB #ifdef LODEPNG_COMPILE_PNG State::State() { lodepng_state_init(this); } State::State(const State& other) { lodepng_state_init(this); lodepng_state_copy(this, &other); } State::~State() { lodepng_state_cleanup(this); } State& State::operator=(const State& other) { lodepng_state_copy(this, &other); return *this; } #ifdef LODEPNG_COMPILE_DECODER unsigned decode(std::vector& out, unsigned& w, unsigned& h, const unsigned char* in, size_t insize, LodePNGColorType colortype, unsigned bitdepth) { unsigned char* buffer; unsigned error = lodepng_decode_memory(&buffer, &w, &h, in, insize, colortype, bitdepth); if(buffer && !error) { State state; state.info_raw.colortype = colortype; state.info_raw.bitdepth = bitdepth; size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw); out.insert(out.end(), &buffer[0], &buffer[buffersize]); lodepng_free(buffer); } return error; } unsigned decode(std::vector& out, unsigned& w, unsigned& h, const std::vector& in, LodePNGColorType colortype, unsigned bitdepth) { return decode(out, w, h, in.empty() ? 0 : &in[0], (unsigned)in.size(), colortype, bitdepth); } unsigned decode(std::vector& out, unsigned& w, unsigned& h, State& state, const unsigned char* in, size_t insize) { unsigned char* buffer = NULL; unsigned error = lodepng_decode(&buffer, &w, &h, &state, in, insize); if(buffer && !error) { size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw); out.insert(out.end(), &buffer[0], &buffer[buffersize]); } lodepng_free(buffer); return error; } unsigned decode(std::vector& out, unsigned& w, unsigned& h, State& state, const std::vector& in) { return decode(out, w, h, state, in.empty() ? 0 : &in[0], in.size()); } #ifdef LODEPNG_COMPILE_DISK unsigned decode(std::vector& out, unsigned& w, unsigned& h, const std::string& filename, LodePNGColorType colortype, unsigned bitdepth) { std::vector buffer; load_file(buffer, filename); return decode(out, w, h, buffer, colortype, bitdepth); } #endif //LODEPNG_COMPILE_DECODER #endif //LODEPNG_COMPILE_DISK #ifdef LODEPNG_COMPILE_ENCODER unsigned encode(std::vector& out, const unsigned char* in, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) { unsigned char* buffer; size_t buffersize; unsigned error = lodepng_encode_memory(&buffer, &buffersize, in, w, h, colortype, bitdepth); if(buffer) { out.insert(out.end(), &buffer[0], &buffer[buffersize]); lodepng_free(buffer); } return error; } unsigned encode(std::vector& out, const std::vector& in, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) { if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84; return encode(out, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth); } unsigned encode(std::vector& out, const unsigned char* in, unsigned w, unsigned h, State& state) { unsigned char* buffer; size_t buffersize; unsigned error = lodepng_encode(&buffer, &buffersize, in, w, h, &state); if(buffer) { out.insert(out.end(), &buffer[0], &buffer[buffersize]); lodepng_free(buffer); } return error; } unsigned encode(std::vector& out, const std::vector& in, unsigned w, unsigned h, State& state) { if(lodepng_get_raw_size(w, h, &state.info_raw) > in.size()) return 84; return encode(out, in.empty() ? 0 : &in[0], w, h, state); } #ifdef LODEPNG_COMPILE_DISK unsigned encode(const std::string& filename, const unsigned char* in, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) { std::vector buffer; unsigned error = encode(buffer, in, w, h, colortype, bitdepth); if(!error) save_file(buffer, filename); return error; } unsigned encode(const std::string& filename, const std::vector& in, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) { if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84; return encode(filename, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth); } #endif //LODEPNG_COMPILE_DISK #endif //LODEPNG_COMPILE_ENCODER #endif //LODEPNG_COMPILE_PNG } //namespace lodepng #endif /*LODEPNG_COMPILE_CPP*/ nestopia-1.51.1/source/fltkui/png.h000066400000000000000000002324501411157722000171620ustar00rootroot00000000000000/* LodePNG version 20141130 Copyright (c) 2005-2014 Lode Vandevenne This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #ifndef LODEPNG_H #define LODEPNG_H #include /*for size_t*/ #ifdef __cplusplus #include #include #endif /*__cplusplus*/ #define LODEPNG_VERSION_STRING "20141130" /* The following #defines are used to create code sections. They can be disabled to disable code sections, which can give faster compile time and smaller binary. The "NO_COMPILE" defines are designed to be used to pass as defines to the compiler command to disable them without modifying this header, e.g. -DLODEPNG_NO_COMPILE_ZLIB for gcc. */ /*deflate & zlib. If disabled, you must specify alternative zlib functions in the custom_zlib field of the compress and decompress settings*/ #ifndef LODEPNG_NO_COMPILE_ZLIB #define LODEPNG_COMPILE_ZLIB #endif /*png encoder and png decoder*/ #ifndef LODEPNG_NO_COMPILE_PNG #define LODEPNG_COMPILE_PNG #endif /*deflate&zlib decoder and png decoder*/ #ifndef LODEPNG_NO_COMPILE_DECODER #define LODEPNG_COMPILE_DECODER #endif /*deflate&zlib encoder and png encoder*/ #ifndef LODEPNG_NO_COMPILE_ENCODER #define LODEPNG_COMPILE_ENCODER #endif /*the optional built in harddisk file loading and saving functions*/ #ifndef LODEPNG_NO_COMPILE_DISK #define LODEPNG_COMPILE_DISK #endif /*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/ #ifndef LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS #define LODEPNG_COMPILE_ANCILLARY_CHUNKS #endif /*ability to convert error numerical codes to English text string*/ #ifndef LODEPNG_NO_COMPILE_ERROR_TEXT #define LODEPNG_COMPILE_ERROR_TEXT #endif /*Compile the default allocators (C's free, malloc and realloc). If you disable this, you can define the functions lodepng_free, lodepng_malloc and lodepng_realloc in your source files with custom allocators.*/ #ifndef LODEPNG_NO_COMPILE_ALLOCATORS #define LODEPNG_COMPILE_ALLOCATORS #endif /*compile the C++ version (you can disable the C++ wrapper here even when compiling for C++)*/ #ifdef __cplusplus #ifndef LODEPNG_NO_COMPILE_CPP #define LODEPNG_COMPILE_CPP #endif #endif #ifdef LODEPNG_COMPILE_PNG /*The PNG color types (also used for raw).*/ typedef enum LodePNGColorType { LCT_GREY = 0, /*greyscale: 1,2,4,8,16 bit*/ LCT_RGB = 2, /*RGB: 8,16 bit*/ LCT_PALETTE = 3, /*palette: 1,2,4,8 bit*/ LCT_GREY_ALPHA = 4, /*greyscale with alpha: 8,16 bit*/ LCT_RGBA = 6 /*RGB with alpha: 8,16 bit*/ } LodePNGColorType; #ifdef LODEPNG_COMPILE_DECODER /* Converts PNG data in memory to raw pixel data. out: Output parameter. Pointer to buffer that will contain the raw pixel data. After decoding, its size is w * h * (bytes per pixel) bytes larger than initially. Bytes per pixel depends on colortype and bitdepth. Must be freed after usage with free(*out). Note: for 16-bit per channel colors, uses big endian format like PNG does. w: Output parameter. Pointer to width of pixel data. h: Output parameter. Pointer to height of pixel data. in: Memory buffer with the PNG file. insize: size of the in buffer. colortype: the desired color type for the raw output image. See explanation on PNG color types. bitdepth: the desired bit depth for the raw output image. See explanation on PNG color types. Return value: LodePNG error code (0 means no error). */ unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize, LodePNGColorType colortype, unsigned bitdepth); /*Same as lodepng_decode_memory, but always decodes to 32-bit RGBA raw image*/ unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize); /*Same as lodepng_decode_memory, but always decodes to 24-bit RGB raw image*/ unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize); #ifdef LODEPNG_COMPILE_DISK /* Load PNG from disk, from file with given name. Same as the other decode functions, but instead takes a filename as input. */ unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename, LodePNGColorType colortype, unsigned bitdepth); /*Same as lodepng_decode_file, but always decodes to 32-bit RGBA raw image.*/ unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename); /*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image.*/ unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename); #endif /*LODEPNG_COMPILE_DISK*/ #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER /* Converts raw pixel data into a PNG image in memory. The colortype and bitdepth of the output PNG image cannot be chosen, they are automatically determined by the colortype, bitdepth and content of the input pixel data. Note: for 16-bit per channel colors, needs big endian format like PNG does. out: Output parameter. Pointer to buffer that will contain the PNG image data. Must be freed after usage with free(*out). outsize: Output parameter. Pointer to the size in bytes of the out buffer. image: The raw pixel data to encode. The size of this buffer should be w * h * (bytes per pixel), bytes per pixel depends on colortype and bitdepth. w: width of the raw pixel data in pixels. h: height of the raw pixel data in pixels. colortype: the color type of the raw input image. See explanation on PNG color types. bitdepth: the bit depth of the raw input image. See explanation on PNG color types. Return value: LodePNG error code (0 means no error). */ unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth); /*Same as lodepng_encode_memory, but always encodes from 32-bit RGBA raw image.*/ unsigned lodepng_encode32(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h); /*Same as lodepng_encode_memory, but always encodes from 24-bit RGB raw image.*/ unsigned lodepng_encode24(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h); #ifdef LODEPNG_COMPILE_DISK /* Converts raw pixel data into a PNG file on disk. Same as the other encode functions, but instead takes a filename as output. NOTE: This overwrites existing files without warning! */ unsigned lodepng_encode_file(const char* filename, const unsigned char* image, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth); /*Same as lodepng_encode_file, but always encodes from 32-bit RGBA raw image.*/ unsigned lodepng_encode32_file(const char* filename, const unsigned char* image, unsigned w, unsigned h); /*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image.*/ unsigned lodepng_encode24_file(const char* filename, const unsigned char* image, unsigned w, unsigned h); #endif /*LODEPNG_COMPILE_DISK*/ #endif /*LODEPNG_COMPILE_ENCODER*/ #ifdef LODEPNG_COMPILE_CPP namespace lodepng { #ifdef LODEPNG_COMPILE_DECODER /*Same as lodepng_decode_memory, but decodes to an std::vector. The colortype is the format to output the pixels to. Default is RGBA 8-bit per channel.*/ unsigned decode(std::vector& out, unsigned& w, unsigned& h, const unsigned char* in, size_t insize, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); unsigned decode(std::vector& out, unsigned& w, unsigned& h, const std::vector& in, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); #ifdef LODEPNG_COMPILE_DISK /* Converts PNG file from disk to raw pixel data in memory. Same as the other decode functions, but instead takes a filename as input. */ unsigned decode(std::vector& out, unsigned& w, unsigned& h, const std::string& filename, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); #endif //LODEPNG_COMPILE_DISK #endif //LODEPNG_COMPILE_DECODER #ifdef LODEPNG_COMPILE_ENCODER /*Same as lodepng_encode_memory, but encodes to an std::vector. colortype is that of the raw input data. The output PNG color type will be auto chosen.*/ unsigned encode(std::vector& out, const unsigned char* in, unsigned w, unsigned h, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); unsigned encode(std::vector& out, const std::vector& in, unsigned w, unsigned h, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); #ifdef LODEPNG_COMPILE_DISK /* Converts 32-bit RGBA raw pixel data into a PNG file on disk. Same as the other encode functions, but instead takes a filename as output. NOTE: This overwrites existing files without warning! */ unsigned encode(const std::string& filename, const unsigned char* in, unsigned w, unsigned h, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); unsigned encode(const std::string& filename, const std::vector& in, unsigned w, unsigned h, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); #endif //LODEPNG_COMPILE_DISK #endif //LODEPNG_COMPILE_ENCODER } //namespace lodepng #endif /*LODEPNG_COMPILE_CPP*/ #endif /*LODEPNG_COMPILE_PNG*/ #ifdef LODEPNG_COMPILE_ERROR_TEXT /*Returns an English description of the numerical error code.*/ const char* lodepng_error_text(unsigned code); #endif /*LODEPNG_COMPILE_ERROR_TEXT*/ #ifdef LODEPNG_COMPILE_DECODER /*Settings for zlib decompression*/ typedef struct LodePNGDecompressSettings LodePNGDecompressSettings; struct LodePNGDecompressSettings { unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/ /*use custom zlib decoder instead of built in one (default: null)*/ unsigned (*custom_zlib)(unsigned char**, size_t*, const unsigned char*, size_t, const LodePNGDecompressSettings*); /*use custom deflate decoder instead of built in one (default: null) if custom_zlib is used, custom_deflate is ignored since only the built in zlib function will call custom_deflate*/ unsigned (*custom_inflate)(unsigned char**, size_t*, const unsigned char*, size_t, const LodePNGDecompressSettings*); const void* custom_context; /*optional custom settings for custom functions*/ }; extern const LodePNGDecompressSettings lodepng_default_decompress_settings; void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings); #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER /* Settings for zlib compression. Tweaking these settings tweaks the balance between speed and compression ratio. */ typedef struct LodePNGCompressSettings LodePNGCompressSettings; struct LodePNGCompressSettings /*deflate = compress*/ { /*LZ77 related settings*/ unsigned btype; /*the block type for LZ (0, 1, 2 or 3, see zlib standard). Should be 2 for proper compression.*/ unsigned use_lz77; /*whether or not to use LZ77. Should be 1 for proper compression.*/ unsigned windowsize; /*must be a power of two <= 32768. higher compresses more but is slower. Default value: 2048.*/ unsigned minmatch; /*mininum lz77 length. 3 is normally best, 6 can be better for some PNGs. Default: 0*/ unsigned nicematch; /*stop searching if >= this length found. Set to 258 for best compression. Default: 128*/ unsigned lazymatching; /*use lazy matching: better compression but a bit slower. Default: true*/ /*use custom zlib encoder instead of built in one (default: null)*/ unsigned (*custom_zlib)(unsigned char**, size_t*, const unsigned char*, size_t, const LodePNGCompressSettings*); /*use custom deflate encoder instead of built in one (default: null) if custom_zlib is used, custom_deflate is ignored since only the built in zlib function will call custom_deflate*/ unsigned (*custom_deflate)(unsigned char**, size_t*, const unsigned char*, size_t, const LodePNGCompressSettings*); const void* custom_context; /*optional custom settings for custom functions*/ }; extern const LodePNGCompressSettings lodepng_default_compress_settings; void lodepng_compress_settings_init(LodePNGCompressSettings* settings); #endif /*LODEPNG_COMPILE_ENCODER*/ #ifdef LODEPNG_COMPILE_PNG /* Color mode of an image. Contains all information required to decode the pixel bits to RGBA colors. This information is the same as used in the PNG file format, and is used both for PNG and raw image data in LodePNG. */ typedef struct LodePNGColorMode { /*header (IHDR)*/ LodePNGColorType colortype; /*color type, see PNG standard or documentation further in this header file*/ unsigned bitdepth; /*bits per sample, see PNG standard or documentation further in this header file*/ /* palette (PLTE and tRNS) Dynamically allocated with the colors of the palette, including alpha. When encoding a PNG, to store your colors in the palette of the LodePNGColorMode, first use lodepng_palette_clear, then for each color use lodepng_palette_add. If you encode an image without alpha with palette, don't forget to put value 255 in each A byte of the palette. When decoding, by default you can ignore this palette, since LodePNG already fills the palette colors in the pixels of the raw RGBA output. The palette is only supported for color type 3. */ unsigned char* palette; /*palette in RGBARGBA... order. When allocated, must be either 0, or have size 1024*/ size_t palettesize; /*palette size in number of colors (amount of bytes is 4 * palettesize)*/ /* transparent color key (tRNS) This color uses the same bit depth as the bitdepth value in this struct, which can be 1-bit to 16-bit. For greyscale PNGs, r, g and b will all 3 be set to the same. When decoding, by default you can ignore this information, since LodePNG sets pixels with this key to transparent already in the raw RGBA output. The color key is only supported for color types 0 and 2. */ unsigned key_defined; /*is a transparent color key given? 0 = false, 1 = true*/ unsigned key_r; /*red/greyscale component of color key*/ unsigned key_g; /*green component of color key*/ unsigned key_b; /*blue component of color key*/ } LodePNGColorMode; /*init, cleanup and copy functions to use with this struct*/ void lodepng_color_mode_init(LodePNGColorMode* info); void lodepng_color_mode_cleanup(LodePNGColorMode* info); /*return value is error code (0 means no error)*/ unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source); void lodepng_palette_clear(LodePNGColorMode* info); /*add 1 color to the palette*/ unsigned lodepng_palette_add(LodePNGColorMode* info, unsigned char r, unsigned char g, unsigned char b, unsigned char a); /*get the total amount of bits per pixel, based on colortype and bitdepth in the struct*/ unsigned lodepng_get_bpp(const LodePNGColorMode* info); /*get the amount of color channels used, based on colortype in the struct. If a palette is used, it counts as 1 channel.*/ unsigned lodepng_get_channels(const LodePNGColorMode* info); /*is it a greyscale type? (only colortype 0 or 4)*/ unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info); /*has it got an alpha channel? (only colortype 2 or 6)*/ unsigned lodepng_is_alpha_type(const LodePNGColorMode* info); /*has it got a palette? (only colortype 3)*/ unsigned lodepng_is_palette_type(const LodePNGColorMode* info); /*only returns true if there is a palette and there is a value in the palette with alpha < 255. Loops through the palette to check this.*/ unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info); /* Check if the given color info indicates the possibility of having non-opaque pixels in the PNG image. Returns true if the image can have translucent or invisible pixels (it still be opaque if it doesn't use such pixels). Returns false if the image can only have opaque pixels. In detail, it returns true only if it's a color type with alpha, or has a palette with non-opaque values, or if "key_defined" is true. */ unsigned lodepng_can_have_alpha(const LodePNGColorMode* info); /*Returns the byte size of a raw image buffer with given width, height and color mode*/ size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color); #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*The information of a Time chunk in PNG.*/ typedef struct LodePNGTime { unsigned year; /*2 bytes used (0-65535)*/ unsigned month; /*1-12*/ unsigned day; /*1-31*/ unsigned hour; /*0-23*/ unsigned minute; /*0-59*/ unsigned second; /*0-60 (to allow for leap seconds)*/ } LodePNGTime; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /*Information about the PNG image, except pixels, width and height.*/ typedef struct LodePNGInfo { /*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/ unsigned compression_method;/*compression method of the original file. Always 0.*/ unsigned filter_method; /*filter method of the original file*/ unsigned interlace_method; /*interlace method of the original file*/ LodePNGColorMode color; /*color type and bits, palette and transparency of the PNG file*/ #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /* suggested background color chunk (bKGD) This color uses the same color mode as the PNG (except alpha channel), which can be 1-bit to 16-bit. For greyscale PNGs, r, g and b will all 3 be set to the same. When encoding the encoder writes the red one. For palette PNGs: When decoding, the RGB value will be stored, not a palette index. But when encoding, specify the index of the palette in background_r, the other two are then ignored. The decoder does not use this background color to edit the color of pixels. */ unsigned background_defined; /*is a suggested background color given?*/ unsigned background_r; /*red component of suggested background color*/ unsigned background_g; /*green component of suggested background color*/ unsigned background_b; /*blue component of suggested background color*/ /* non-international text chunks (tEXt and zTXt) The char** arrays each contain num strings. The actual messages are in text_strings, while text_keys are keywords that give a short description what the actual text represents, e.g. Title, Author, Description, or anything else. A keyword is minimum 1 character and maximum 79 characters long. It's discouraged to use a single line length longer than 79 characters for texts. Don't allocate these text buffers yourself. Use the init/cleanup functions correctly and use lodepng_add_text and lodepng_clear_text. */ size_t text_num; /*the amount of texts in these char** buffers (there may be more texts in itext)*/ char** text_keys; /*the keyword of a text chunk (e.g. "Comment")*/ char** text_strings; /*the actual text*/ /* international text chunks (iTXt) Similar to the non-international text chunks, but with additional strings "langtags" and "transkeys". */ size_t itext_num; /*the amount of international texts in this PNG*/ char** itext_keys; /*the English keyword of the text chunk (e.g. "Comment")*/ char** itext_langtags; /*language tag for this text's language, ISO/IEC 646 string, e.g. ISO 639 language tag*/ char** itext_transkeys; /*keyword translated to the international language - UTF-8 string*/ char** itext_strings; /*the actual international text - UTF-8 string*/ /*time chunk (tIME)*/ unsigned time_defined; /*set to 1 to make the encoder generate a tIME chunk*/ LodePNGTime time; /*phys chunk (pHYs)*/ unsigned phys_defined; /*if 0, there is no pHYs chunk and the values below are undefined, if 1 else there is one*/ unsigned phys_x; /*pixels per unit in x direction*/ unsigned phys_y; /*pixels per unit in y direction*/ unsigned phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/ /* unknown chunks There are 3 buffers, one for each position in the PNG where unknown chunks can appear each buffer contains all unknown chunks for that position consecutively The 3 buffers are the unknown chunks between certain critical chunks: 0: IHDR-PLTE, 1: PLTE-IDAT, 2: IDAT-IEND Do not allocate or traverse this data yourself. Use the chunk traversing functions declared later, such as lodepng_chunk_next and lodepng_chunk_append, to read/write this struct. */ unsigned char* unknown_chunks_data[3]; size_t unknown_chunks_size[3]; /*size in bytes of the unknown chunks, given for protection*/ #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } LodePNGInfo; /*init, cleanup and copy functions to use with this struct*/ void lodepng_info_init(LodePNGInfo* info); void lodepng_info_cleanup(LodePNGInfo* info); /*return value is error code (0 means no error)*/ unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source); #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS void lodepng_clear_text(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/ unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str); /*push back both texts at once*/ void lodepng_clear_itext(LodePNGInfo* info); /*use this to clear the itexts again after you filled them in*/ unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, const char* transkey, const char* str); /*push back the 4 texts of 1 chunk at once*/ #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /* Converts raw buffer from one color type to another color type, based on LodePNGColorMode structs to describe the input and output color type. See the reference manual at the end of this header file to see which color conversions are supported. return value = LodePNG error code (0 if all went ok, an error if the conversion isn't supported) The out buffer must have size (w * h * bpp + 7) / 8, where bpp is the bits per pixel of the output color type (lodepng_get_bpp). For < 8 bpp images, there should not be padding bits at the end of scanlines. For 16-bit per channel colors, uses big endian format like PNG does. Return value is LodePNG error code */ unsigned lodepng_convert(unsigned char* out, const unsigned char* in, LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, unsigned w, unsigned h); #ifdef LODEPNG_COMPILE_DECODER /* Settings for the decoder. This contains settings for the PNG and the Zlib decoder, but not the Info settings from the Info structs. */ typedef struct LodePNGDecoderSettings { LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/ unsigned ignore_crc; /*ignore CRC checksums*/ unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/ #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS unsigned read_text_chunks; /*if false but remember_unknown_chunks is true, they're stored in the unknown chunks*/ /*store all bytes from unknown chunks in the LodePNGInfo (off by default, useful for a png editor)*/ unsigned remember_unknown_chunks; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } LodePNGDecoderSettings; void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings); #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER /*automatically use color type with less bits per pixel if losslessly possible. Default: AUTO*/ typedef enum LodePNGFilterStrategy { /*every filter at zero*/ LFS_ZERO, /*Use filter that gives minumum sum, as described in the official PNG filter heuristic.*/ LFS_MINSUM, /*Use the filter type that gives smallest Shannon entropy for this scanline. Depending on the image, this is better or worse than minsum.*/ LFS_ENTROPY, /* Brute-force-search PNG filters by compressing each filter for each scanline. Experimental, very slow, and only rarely gives better compression than MINSUM. */ LFS_BRUTE_FORCE, /*use predefined_filters buffer: you specify the filter type for each scanline*/ LFS_PREDEFINED } LodePNGFilterStrategy; /*Gives characteristics about the colors of the image, which helps decide which color model to use for encoding. Used internally by default if "auto_convert" is enabled. Public because it's useful for custom algorithms.*/ typedef struct LodePNGColorProfile { unsigned colored; /*not greyscale*/ unsigned key; /*if true, image is not opaque. Only if true and alpha is false, color key is possible.*/ unsigned short key_r; /*these values are always in 16-bit bitdepth in the profile*/ unsigned short key_g; unsigned short key_b; unsigned alpha; /*alpha channel or alpha palette required*/ unsigned numcolors; /*amount of colors, up to 257. Not valid if bits == 16.*/ unsigned char palette[1024]; /*Remembers up to the first 256 RGBA colors, in no particular order*/ unsigned bits; /*bits per channel (not for palette). 1,2 or 4 for greyscale only. 16 if 16-bit per channel required.*/ } LodePNGColorProfile; void lodepng_color_profile_init(LodePNGColorProfile* profile); /*Get a LodePNGColorProfile of the image.*/ unsigned lodepng_get_color_profile(LodePNGColorProfile* profile, const unsigned char* image, unsigned w, unsigned h, const LodePNGColorMode* mode_in); /*The function LodePNG uses internally to decide the PNG color with auto_convert. Chooses an optimal color model, e.g. grey if only grey pixels, palette if < 256 colors, ...*/ unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out, const unsigned char* image, unsigned w, unsigned h, const LodePNGColorMode* mode_in); /*Settings for the encoder.*/ typedef struct LodePNGEncoderSettings { LodePNGCompressSettings zlibsettings; /*settings for the zlib encoder, such as window size, ...*/ unsigned auto_convert; /*automatically choose output PNG color type. Default: true*/ /*If true, follows the official PNG heuristic: if the PNG uses a palette or lower than 8 bit depth, set all filters to zero. Otherwise use the filter_strategy. Note that to completely follow the official PNG heuristic, filter_palette_zero must be true and filter_strategy must be LFS_MINSUM*/ unsigned filter_palette_zero; /*Which filter strategy to use when not using zeroes due to filter_palette_zero. Set filter_palette_zero to 0 to ensure always using your chosen strategy. Default: LFS_MINSUM*/ LodePNGFilterStrategy filter_strategy; /*used if filter_strategy is LFS_PREDEFINED. In that case, this must point to a buffer with the same length as the amount of scanlines in the image, and each value must <= 5. You have to cleanup this buffer, LodePNG will never free it. Don't forget that filter_palette_zero must be set to 0 to ensure this is also used on palette or low bitdepth images.*/ const unsigned char* predefined_filters; /*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette). If colortype is 3, PLTE is _always_ created.*/ unsigned force_palette; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*add LodePNG identifier and version as a text chunk, for debugging*/ unsigned add_id; /*encode text chunks as zTXt chunks instead of tEXt chunks, and use compression in iTXt chunks*/ unsigned text_compression; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } LodePNGEncoderSettings; void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings); #endif /*LODEPNG_COMPILE_ENCODER*/ #if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) /*The settings, state and information for extended encoding and decoding.*/ typedef struct LodePNGState { #ifdef LODEPNG_COMPILE_DECODER LodePNGDecoderSettings decoder; /*the decoding settings*/ #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER LodePNGEncoderSettings encoder; /*the encoding settings*/ #endif /*LODEPNG_COMPILE_ENCODER*/ LodePNGColorMode info_raw; /*specifies the format in which you would like to get the raw pixel buffer*/ LodePNGInfo info_png; /*info of the PNG image obtained after decoding*/ unsigned error; #ifdef LODEPNG_COMPILE_CPP //For the lodepng::State subclass. virtual ~LodePNGState(){} #endif } LodePNGState; /*init, cleanup and copy functions to use with this struct*/ void lodepng_state_init(LodePNGState* state); void lodepng_state_cleanup(LodePNGState* state); void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source); #endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ #ifdef LODEPNG_COMPILE_DECODER /* Same as lodepng_decode_memory, but uses a LodePNGState to allow custom settings and getting much more information about the PNG image and color mode. */ unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, LodePNGState* state, const unsigned char* in, size_t insize); /* Read the PNG header, but not the actual data. This returns only the information that is in the header chunk of the PNG, such as width, height and color type. The information is placed in the info_png field of the LodePNGState. */ unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state, const unsigned char* in, size_t insize); #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER /*This function allocates the out buffer with standard malloc and stores the size in *outsize.*/ unsigned lodepng_encode(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h, LodePNGState* state); #endif /*LODEPNG_COMPILE_ENCODER*/ /* The lodepng_chunk functions are normally not needed, except to traverse the unknown chunks stored in the LodePNGInfo struct, or add new ones to it. It also allows traversing the chunks of an encoded PNG file yourself. PNG standard chunk naming conventions: First byte: uppercase = critical, lowercase = ancillary Second byte: uppercase = public, lowercase = private Third byte: must be uppercase Fourth byte: uppercase = unsafe to copy, lowercase = safe to copy */ /* Gets the length of the data of the chunk. Total chunk length has 12 bytes more. There must be at least 4 bytes to read from. If the result value is too large, it may be corrupt data. */ unsigned lodepng_chunk_length(const unsigned char* chunk); /*puts the 4-byte type in null terminated string*/ void lodepng_chunk_type(char type[5], const unsigned char* chunk); /*check if the type is the given type*/ unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type); /*0: it's one of the critical chunk types, 1: it's an ancillary chunk (see PNG standard)*/ unsigned char lodepng_chunk_ancillary(const unsigned char* chunk); /*0: public, 1: private (see PNG standard)*/ unsigned char lodepng_chunk_private(const unsigned char* chunk); /*0: the chunk is unsafe to copy, 1: the chunk is safe to copy (see PNG standard)*/ unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk); /*get pointer to the data of the chunk, where the input points to the header of the chunk*/ unsigned char* lodepng_chunk_data(unsigned char* chunk); const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk); /*returns 0 if the crc is correct, 1 if it's incorrect (0 for OK as usual!)*/ unsigned lodepng_chunk_check_crc(const unsigned char* chunk); /*generates the correct CRC from the data and puts it in the last 4 bytes of the chunk*/ void lodepng_chunk_generate_crc(unsigned char* chunk); /*iterate to next chunks. don't use on IEND chunk, as there is no next chunk then*/ unsigned char* lodepng_chunk_next(unsigned char* chunk); const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk); /* Appends chunk to the data in out. The given chunk should already have its chunk header. The out variable and outlength are updated to reflect the new reallocated buffer. Returns error code (0 if it went ok) */ unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk); /* Appends new chunk to out. The chunk to append is given by giving its length, type and data separately. The type is a 4-letter string. The out variable and outlength are updated to reflect the new reallocated buffer. Returne error code (0 if it went ok) */ unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, const char* type, const unsigned char* data); /*Calculate CRC32 of buffer*/ unsigned lodepng_crc32(const unsigned char* buf, size_t len); #endif /*LODEPNG_COMPILE_PNG*/ #ifdef LODEPNG_COMPILE_ZLIB /* This zlib part can be used independently to zlib compress and decompress a buffer. It cannot be used to create gzip files however, and it only supports the part of zlib that is required for PNG, it does not support dictionaries. */ #ifdef LODEPNG_COMPILE_DECODER /*Inflate a buffer. Inflate is the decompression step of deflate. Out buffer must be freed after use.*/ unsigned lodepng_inflate(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings); /* Decompresses Zlib data. Reallocates the out buffer and appends the data. The data must be according to the zlib specification. Either, *out must be NULL and *outsize must be 0, or, *out must be a valid buffer and *outsize its size in bytes. out must be freed by user after usage. */ unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings); #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER /* Compresses data with Zlib. Reallocates the out buffer and appends the data. Zlib adds a small header and trailer around the deflate data. The data is output in the format of the zlib specification. Either, *out must be NULL and *outsize must be 0, or, *out must be a valid buffer and *outsize its size in bytes. out must be freed by user after usage. */ unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGCompressSettings* settings); /* Find length-limited Huffman code for given frequencies. This function is in the public interface only for tests, it's used internally by lodepng_deflate. */ unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, size_t numcodes, unsigned maxbitlen); /*Compress a buffer with deflate. See RFC 1951. Out buffer must be freed after use.*/ unsigned lodepng_deflate(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGCompressSettings* settings); #endif /*LODEPNG_COMPILE_ENCODER*/ #endif /*LODEPNG_COMPILE_ZLIB*/ #ifdef LODEPNG_COMPILE_DISK /* Load a file from disk into buffer. The function allocates the out buffer, and after usage you should free it. out: output parameter, contains pointer to loaded buffer. outsize: output parameter, size of the allocated out buffer filename: the path to the file to load return value: error code (0 means ok) */ unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename); /* Save a file from buffer to disk. Warning, if it exists, this function overwrites the file without warning! buffer: the buffer to write buffersize: size of the buffer to write filename: the path to the file to save to return value: error code (0 means ok) */ unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename); #endif /*LODEPNG_COMPILE_DISK*/ #ifdef LODEPNG_COMPILE_CPP //The LodePNG C++ wrapper uses std::vectors instead of manually allocated memory buffers. namespace lodepng { #ifdef LODEPNG_COMPILE_PNG class State : public LodePNGState { public: State(); State(const State& other); virtual ~State(); State& operator=(const State& other); }; #ifdef LODEPNG_COMPILE_DECODER //Same as other lodepng::decode, but using a State for more settings and information. unsigned decode(std::vector& out, unsigned& w, unsigned& h, State& state, const unsigned char* in, size_t insize); unsigned decode(std::vector& out, unsigned& w, unsigned& h, State& state, const std::vector& in); #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER //Same as other lodepng::encode, but using a State for more settings and information. unsigned encode(std::vector& out, const unsigned char* in, unsigned w, unsigned h, State& state); unsigned encode(std::vector& out, const std::vector& in, unsigned w, unsigned h, State& state); #endif /*LODEPNG_COMPILE_ENCODER*/ #ifdef LODEPNG_COMPILE_DISK /* Load a file from disk into an std::vector. If the vector is empty, then either the file doesn't exist or is an empty file. */ void load_file(std::vector& buffer, const std::string& filename); /* Save the binary data in an std::vector to a file on disk. The file is overwritten without warning. */ void save_file(const std::vector& buffer, const std::string& filename); #endif //LODEPNG_COMPILE_DISK #endif //LODEPNG_COMPILE_PNG #ifdef LODEPNG_COMPILE_ZLIB #ifdef LODEPNG_COMPILE_DECODER //Zlib-decompress an unsigned char buffer unsigned decompress(std::vector& out, const unsigned char* in, size_t insize, const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); //Zlib-decompress an std::vector unsigned decompress(std::vector& out, const std::vector& in, const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); #endif //LODEPNG_COMPILE_DECODER #ifdef LODEPNG_COMPILE_ENCODER //Zlib-compress an unsigned char buffer unsigned compress(std::vector& out, const unsigned char* in, size_t insize, const LodePNGCompressSettings& settings = lodepng_default_compress_settings); //Zlib-compress an std::vector unsigned compress(std::vector& out, const std::vector& in, const LodePNGCompressSettings& settings = lodepng_default_compress_settings); #endif //LODEPNG_COMPILE_ENCODER #endif //LODEPNG_COMPILE_ZLIB } //namespace lodepng #endif /*LODEPNG_COMPILE_CPP*/ /* TODO: [.] test if there are no memory leaks or security exploits - done a lot but needs to be checked often [.] check compatibility with vareous compilers - done but needs to be redone for every newer version [X] converting color to 16-bit per channel types [ ] read all public PNG chunk types (but never let the color profile and gamma ones touch RGB values) [ ] make sure encoder generates no chunks with size > (2^31)-1 [ ] partial decoding (stream processing) [X] let the "isFullyOpaque" function check color keys and transparent palettes too [X] better name for the variables "codes", "codesD", "codelengthcodes", "clcl" and "lldl" [ ] don't stop decoding on errors like 69, 57, 58 (make warnings) [ ] let the C++ wrapper catch exceptions coming from the standard library and return LodePNG error codes [ ] allow user to provide custom color conversion functions, e.g. for premultiplied alpha, padding bits or not, ... */ #endif /*LODEPNG_H inclusion guard*/ /* LodePNG Documentation --------------------- 0. table of contents -------------------- 1. about 1.1. supported features 1.2. features not supported 2. C and C++ version 3. security 4. decoding 5. encoding 6. color conversions 6.1. PNG color types 6.2. color conversions 6.3. padding bits 6.4. A note about 16-bits per channel and endianness 7. error values 8. chunks and PNG editing 9. compiler support 10. examples 10.1. decoder C++ example 10.2. decoder C example 11. changes 12. contact information 1. about -------- PNG is a file format to store raster images losslessly with good compression, supporting different color types and alpha channel. LodePNG is a PNG codec according to the Portable Network Graphics (PNG) Specification (Second Edition) - W3C Recommendation 10 November 2003. The specifications used are: *) Portable Network Graphics (PNG) Specification (Second Edition): http://www.w3.org/TR/2003/REC-PNG-20031110 *) RFC 1950 ZLIB Compressed Data Format version 3.3: http://www.gzip.org/zlib/rfc-zlib.html *) RFC 1951 DEFLATE Compressed Data Format Specification ver 1.3: http://www.gzip.org/zlib/rfc-deflate.html The most recent version of LodePNG can currently be found at http://lodev.org/lodepng/ LodePNG works both in C (ISO C90) and C++, with a C++ wrapper that adds extra functionality. LodePNG exists out of two files: -lodepng.h: the header file for both C and C++ -lodepng.c(pp): give it the name lodepng.c or lodepng.cpp (or .cc) depending on your usage If you want to start using LodePNG right away without reading this doc, get the examples from the LodePNG website to see how to use it in code, or check the smaller examples in chapter 13 here. LodePNG is simple but only supports the basic requirements. To achieve simplicity, the following design choices were made: There are no dependencies on any external library. There are functions to decode and encode a PNG with a single function call, and extended versions of these functions taking a LodePNGState struct allowing to specify or get more information. By default the colors of the raw image are always RGB or RGBA, no matter what color type the PNG file uses. To read and write files, there are simple functions to convert the files to/from buffers in memory. This all makes LodePNG suitable for loading textures in games, demos and small programs, ... It's less suitable for full fledged image editors, loading PNGs over network (it requires all the image data to be available before decoding can begin), life-critical systems, ... 1.1. supported features ----------------------- The following features are supported by the decoder: *) decoding of PNGs with any color type, bit depth and interlace mode, to a 24- or 32-bit color raw image, or the same color type as the PNG *) encoding of PNGs, from any raw image to 24- or 32-bit color, or the same color type as the raw image *) Adam7 interlace and deinterlace for any color type *) loading the image from harddisk or decoding it from a buffer from other sources than harddisk *) support for alpha channels, including RGBA color model, translucent palettes and color keying *) zlib decompression (inflate) *) zlib compression (deflate) *) CRC32 and ADLER32 checksums *) handling of unknown chunks, allowing making a PNG editor that stores custom and unknown chunks. *) the following chunks are supported (generated/interpreted) by both encoder and decoder: IHDR: header information PLTE: color palette IDAT: pixel data IEND: the final chunk tRNS: transparency for palettized images tEXt: textual information zTXt: compressed textual information iTXt: international textual information bKGD: suggested background color pHYs: physical dimensions tIME: modification time 1.2. features not supported --------------------------- The following features are _not_ supported: *) some features needed to make a conformant PNG-Editor might be still missing. *) partial loading/stream processing. All data must be available and is processed in one call. *) The following public chunks are not supported but treated as unknown chunks by LodePNG cHRM, gAMA, iCCP, sRGB, sBIT, hIST, sPLT Some of these are not supported on purpose: LodePNG wants to provide the RGB values stored in the pixels, not values modified by system dependent gamma or color models. 2. C and C++ version -------------------- The C version uses buffers allocated with alloc that you need to free() yourself. You need to use init and cleanup functions for each struct whenever using a struct from the C version to avoid exploits and memory leaks. The C++ version has extra functions with std::vectors in the interface and the lodepng::State class which is a LodePNGState with constructor and destructor. These files work without modification for both C and C++ compilers because all the additional C++ code is in "#ifdef __cplusplus" blocks that make C-compilers ignore it, and the C code is made to compile both with strict ISO C90 and C++. To use the C++ version, you need to rename the source file to lodepng.cpp (instead of lodepng.c), and compile it with a C++ compiler. To use the C version, you need to rename the source file to lodepng.c (instead of lodepng.cpp), and compile it with a C compiler. 3. Security ----------- Even if carefully designed, it's always possible that LodePNG contains possible exploits. If you discover one, please let me know, and it will be fixed. When using LodePNG, care has to be taken with the C version of LodePNG, as well as the C-style structs when working with C++. The following conventions are used for all C-style structs: -if a struct has a corresponding init function, always call the init function when making a new one -if a struct has a corresponding cleanup function, call it before the struct disappears to avoid memory leaks -if a struct has a corresponding copy function, use the copy function instead of "=". The destination must also be inited already. 4. Decoding ----------- Decoding converts a PNG compressed image to a raw pixel buffer. Most documentation on using the decoder is at its declarations in the header above. For C, simple decoding can be done with functions such as lodepng_decode32, and more advanced decoding can be done with the struct LodePNGState and lodepng_decode. For C++, all decoding can be done with the various lodepng::decode functions, and lodepng::State can be used for advanced features. When using the LodePNGState, it uses the following fields for decoding: *) LodePNGInfo info_png: it stores extra information about the PNG (the input) in here *) LodePNGColorMode info_raw: here you can say what color mode of the raw image (the output) you want to get *) LodePNGDecoderSettings decoder: you can specify a few extra settings for the decoder to use LodePNGInfo info_png -------------------- After decoding, this contains extra information of the PNG image, except the actual pixels, width and height because these are already gotten directly from the decoder functions. It contains for example the original color type of the PNG image, text comments, suggested background color, etc... More details about the LodePNGInfo struct are at its declaration documentation. LodePNGColorMode info_raw ------------------------- When decoding, here you can specify which color type you want the resulting raw image to be. If this is different from the colortype of the PNG, then the decoder will automatically convert the result. This conversion always works, except if you want it to convert a color PNG to greyscale or to a palette with missing colors. By default, 32-bit color is used for the result. LodePNGDecoderSettings decoder ------------------------------ The settings can be used to ignore the errors created by invalid CRC and Adler32 chunks, and to disable the decoding of tEXt chunks. There's also a setting color_convert, true by default. If false, no conversion is done, the resulting data will be as it was in the PNG (after decompression) and you'll have to puzzle the colors of the pixels together yourself using the color type information in the LodePNGInfo. 5. Encoding ----------- Encoding converts a raw pixel buffer to a PNG compressed image. Most documentation on using the encoder is at its declarations in the header above. For C, simple encoding can be done with functions such as lodepng_encode32, and more advanced decoding can be done with the struct LodePNGState and lodepng_encode. For C++, all encoding can be done with the various lodepng::encode functions, and lodepng::State can be used for advanced features. Like the decoder, the encoder can also give errors. However it gives less errors since the encoder input is trusted, the decoder input (a PNG image that could be forged by anyone) is not trusted. When using the LodePNGState, it uses the following fields for encoding: *) LodePNGInfo info_png: here you specify how you want the PNG (the output) to be. *) LodePNGColorMode info_raw: here you say what color type of the raw image (the input) has *) LodePNGEncoderSettings encoder: you can specify a few settings for the encoder to use LodePNGInfo info_png -------------------- When encoding, you use this the opposite way as when decoding: for encoding, you fill in the values you want the PNG to have before encoding. By default it's not needed to specify a color type for the PNG since it's automatically chosen, but it's possible to choose it yourself given the right settings. The encoder will not always exactly match the LodePNGInfo struct you give, it tries as close as possible. Some things are ignored by the encoder. The encoder uses, for example, the following settings from it when applicable: colortype and bitdepth, text chunks, time chunk, the color key, the palette, the background color, the interlace method, unknown chunks, ... When encoding to a PNG with colortype 3, the encoder will generate a PLTE chunk. If the palette contains any colors for which the alpha channel is not 255 (so there are translucent colors in the palette), it'll add a tRNS chunk. LodePNGColorMode info_raw ------------------------- You specify the color type of the raw image that you give to the input here, including a possible transparent color key and palette you happen to be using in your raw image data. By default, 32-bit color is assumed, meaning your input has to be in RGBA format with 4 bytes (unsigned chars) per pixel. LodePNGEncoderSettings encoder ------------------------------ The following settings are supported (some are in sub-structs): *) auto_convert: when this option is enabled, the encoder will automatically choose the smallest possible color mode (including color key) that can encode the colors of all pixels without information loss. *) btype: the block type for LZ77. 0 = uncompressed, 1 = fixed huffman tree, 2 = dynamic huffman tree (best compression). Should be 2 for proper compression. *) use_lz77: whether or not to use LZ77 for compressed block types. Should be true for proper compression. *) windowsize: the window size used by the LZ77 encoder (1 - 32768). Has value 2048 by default, but can be set to 32768 for better, but slow, compression. *) force_palette: if colortype is 2 or 6, you can make the encoder write a PLTE chunk if force_palette is true. This can used as suggested palette to convert to by viewers that don't support more than 256 colors (if those still exist) *) add_id: add text chunk "Encoder: LodePNG " to the image. *) text_compression: default 1. If 1, it'll store texts as zTXt instead of tEXt chunks. zTXt chunks use zlib compression on the text. This gives a smaller result on large texts but a larger result on small texts (such as a single program name). It's all tEXt or all zTXt though, there's no separate setting per text yet. 6. color conversions -------------------- An important thing to note about LodePNG, is that the color type of the PNG, and the color type of the raw image, are completely independent. By default, when you decode a PNG, you get the result as a raw image in the color type you want, no matter whether the PNG was encoded with a palette, greyscale or RGBA color. And if you encode an image, by default LodePNG will automatically choose the PNG color type that gives good compression based on the values of colors and amount of colors in the image. It can be configured to let you control it instead as well, though. To be able to do this, LodePNG does conversions from one color mode to another. It can convert from almost any color type to any other color type, except the following conversions: RGB to greyscale is not supported, and converting to a palette when the palette doesn't have a required color is not supported. This is not supported on purpose: this is information loss which requires a color reduction algorithm that is beyong the scope of a PNG encoder (yes, RGB to grey is easy, but there are multiple ways if you want to give some channels more weight). By default, when decoding, you get the raw image in 32-bit RGBA or 24-bit RGB color, no matter what color type the PNG has. And by default when encoding, LodePNG automatically picks the best color model for the output PNG, and expects the input image to be 32-bit RGBA or 24-bit RGB. So, unless you want to control the color format of the images yourself, you can skip this chapter. 6.1. PNG color types -------------------- A PNG image can have many color types, ranging from 1-bit color to 64-bit color, as well as palettized color modes. After the zlib decompression and unfiltering in the PNG image is done, the raw pixel data will have that color type and thus a certain amount of bits per pixel. If you want the output raw image after decoding to have another color type, a conversion is done by LodePNG. The PNG specification gives the following color types: 0: greyscale, bit depths 1, 2, 4, 8, 16 2: RGB, bit depths 8 and 16 3: palette, bit depths 1, 2, 4 and 8 4: greyscale with alpha, bit depths 8 and 16 6: RGBA, bit depths 8 and 16 Bit depth is the amount of bits per pixel per color channel. So the total amount of bits per pixel is: amount of channels * bitdepth. 6.2. color conversions ---------------------- As explained in the sections about the encoder and decoder, you can specify color types and bit depths in info_png and info_raw to change the default behaviour. If, when decoding, you want the raw image to be something else than the default, you need to set the color type and bit depth you want in the LodePNGColorMode, or the parameters colortype and bitdepth of the simple decoding function. If, when encoding, you use another color type than the default in the raw input image, you need to specify its color type and bit depth in the LodePNGColorMode of the raw image, or use the parameters colortype and bitdepth of the simple encoding function. If, when encoding, you don't want LodePNG to choose the output PNG color type but control it yourself, you need to set auto_convert in the encoder settings to false, and specify the color type you want in the LodePNGInfo of the encoder (including palette: it can generate a palette if auto_convert is true, otherwise not). If the input and output color type differ (whether user chosen or auto chosen), LodePNG will do a color conversion, which follows the rules below, and may sometimes result in an error. To avoid some confusion: -the decoder converts from PNG to raw image -the encoder converts from raw image to PNG -the colortype and bitdepth in LodePNGColorMode info_raw, are those of the raw image -the colortype and bitdepth in the color field of LodePNGInfo info_png, are those of the PNG -when encoding, the color type in LodePNGInfo is ignored if auto_convert is enabled, it is automatically generated instead -when decoding, the color type in LodePNGInfo is set by the decoder to that of the original PNG image, but it can be ignored since the raw image has the color type you requested instead -if the color type of the LodePNGColorMode and PNG image aren't the same, a conversion between the color types is done if the color types are supported. If it is not supported, an error is returned. If the types are the same, no conversion is done. -even though some conversions aren't supported, LodePNG supports loading PNGs from any colortype and saving PNGs to any colortype, sometimes it just requires preparing the raw image correctly before encoding. -both encoder and decoder use the same color converter. Non supported color conversions: -color to greyscale: no error is thrown, but the result will look ugly because only the red channel is taken -anything to palette when that palette does not have that color in it: in this case an error is thrown Supported color conversions: -anything to 8-bit RGB, 8-bit RGBA, 16-bit RGB, 16-bit RGBA -any grey or grey+alpha, to grey or grey+alpha -anything to a palette, as long as the palette has the requested colors in it -removing alpha channel -higher to smaller bitdepth, and vice versa If you want no color conversion to be done (e.g. for speed or control): -In the encoder, you can make it save a PNG with any color type by giving the raw color mode and LodePNGInfo the same color mode, and setting auto_convert to false. -In the decoder, you can make it store the pixel data in the same color type as the PNG has, by setting the color_convert setting to false. Settings in info_raw are then ignored. The function lodepng_convert does the color conversion. It is available in the interface but normally isn't needed since the encoder and decoder already call it. 6.3. padding bits ----------------- In the PNG file format, if a less than 8-bit per pixel color type is used and the scanlines have a bit amount that isn't a multiple of 8, then padding bits are used so that each scanline starts at a fresh byte. But that is NOT true for the LodePNG raw input and output. The raw input image you give to the encoder, and the raw output image you get from the decoder will NOT have these padding bits, e.g. in the case of a 1-bit image with a width of 7 pixels, the first pixel of the second scanline will the the 8th bit of the first byte, not the first bit of a new byte. 6.4. A note about 16-bits per channel and endianness ---------------------------------------------------- LodePNG uses unsigned char arrays for 16-bit per channel colors too, just like for any other color format. The 16-bit values are stored in big endian (most significant byte first) in these arrays. This is the opposite order of the little endian used by x86 CPU's. LodePNG always uses big endian because the PNG file format does so internally. Conversions to other formats than PNG uses internally are not supported by LodePNG on purpose, there are myriads of formats, including endianness of 16-bit colors, the order in which you store R, G, B and A, and so on. Supporting and converting to/from all that is outside the scope of LodePNG. This may mean that, depending on your use case, you may want to convert the big endian output of LodePNG to little endian with a for loop. This is certainly not always needed, many applications and libraries support big endian 16-bit colors anyway, but it means you cannot simply cast the unsigned char* buffer to an unsigned short* buffer on x86 CPUs. 7. error values --------------- All functions in LodePNG that return an error code, return 0 if everything went OK, or a non-zero code if there was an error. The meaning of the LodePNG error values can be retrieved with the function lodepng_error_text: given the numerical error code, it returns a description of the error in English as a string. Check the implementation of lodepng_error_text to see the meaning of each code. 8. chunks and PNG editing ------------------------- If you want to add extra chunks to a PNG you encode, or use LodePNG for a PNG editor that should follow the rules about handling of unknown chunks, or if your program is able to read other types of chunks than the ones handled by LodePNG, then that's possible with the chunk functions of LodePNG. A PNG chunk has the following layout: 4 bytes length 4 bytes type name length bytes data 4 bytes CRC 8.1. iterating through chunks ----------------------------- If you have a buffer containing the PNG image data, then the first chunk (the IHDR chunk) starts at byte number 8 of that buffer. The first 8 bytes are the signature of the PNG and are not part of a chunk. But if you start at byte 8 then you have a chunk, and can check the following things of it. NOTE: none of these functions check for memory buffer boundaries. To avoid exploits, always make sure the buffer contains all the data of the chunks. When using lodepng_chunk_next, make sure the returned value is within the allocated memory. unsigned lodepng_chunk_length(const unsigned char* chunk): Get the length of the chunk's data. The total chunk length is this length + 12. void lodepng_chunk_type(char type[5], const unsigned char* chunk): unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type): Get the type of the chunk or compare if it's a certain type unsigned char lodepng_chunk_critical(const unsigned char* chunk): unsigned char lodepng_chunk_private(const unsigned char* chunk): unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk): Check if the chunk is critical in the PNG standard (only IHDR, PLTE, IDAT and IEND are). Check if the chunk is private (public chunks are part of the standard, private ones not). Check if the chunk is safe to copy. If it's not, then, when modifying data in a critical chunk, unsafe to copy chunks of the old image may NOT be saved in the new one if your program doesn't handle that type of unknown chunk. unsigned char* lodepng_chunk_data(unsigned char* chunk): const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk): Get a pointer to the start of the data of the chunk. unsigned lodepng_chunk_check_crc(const unsigned char* chunk): void lodepng_chunk_generate_crc(unsigned char* chunk): Check if the crc is correct or generate a correct one. unsigned char* lodepng_chunk_next(unsigned char* chunk): const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk): Iterate to the next chunk. This works if you have a buffer with consecutive chunks. Note that these functions do no boundary checking of the allocated data whatsoever, so make sure there is enough data available in the buffer to be able to go to the next chunk. unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk): unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, const char* type, const unsigned char* data): These functions are used to create new chunks that are appended to the data in *out that has length *outlength. The append function appends an existing chunk to the new data. The create function creates a new chunk with the given parameters and appends it. Type is the 4-letter name of the chunk. 8.2. chunks in info_png ----------------------- The LodePNGInfo struct contains fields with the unknown chunk in it. It has 3 buffers (each with size) to contain 3 types of unknown chunks: the ones that come before the PLTE chunk, the ones that come between the PLTE and the IDAT chunks, and the ones that come after the IDAT chunks. It's necessary to make the distionction between these 3 cases because the PNG standard forces to keep the ordering of unknown chunks compared to the critical chunks, but does not force any other ordering rules. info_png.unknown_chunks_data[0] is the chunks before PLTE info_png.unknown_chunks_data[1] is the chunks after PLTE, before IDAT info_png.unknown_chunks_data[2] is the chunks after IDAT The chunks in these 3 buffers can be iterated through and read by using the same way described in the previous subchapter. When using the decoder to decode a PNG, you can make it store all unknown chunks if you set the option settings.remember_unknown_chunks to 1. By default, this option is off (0). The encoder will always encode unknown chunks that are stored in the info_png. If you need it to add a particular chunk that isn't known by LodePNG, you can use lodepng_chunk_append or lodepng_chunk_create to the chunk data in info_png.unknown_chunks_data[x]. Chunks that are known by LodePNG should not be added in that way. E.g. to make LodePNG add a bKGD chunk, set background_defined to true and add the correct parameters there instead. 9. compiler support ------------------- No libraries other than the current standard C library are needed to compile LodePNG. For the C++ version, only the standard C++ library is needed on top. Add the files lodepng.c(pp) and lodepng.h to your project, include lodepng.h where needed, and your program can read/write PNG files. It is compatible with C90 and up, and C++03 and up. If performance is important, use optimization when compiling! For both the encoder and decoder, this makes a large difference. Make sure that LodePNG is compiled with the same compiler of the same version and with the same settings as the rest of the program, or the interfaces with std::vectors and std::strings in C++ can be incompatible. CHAR_BITS must be 8 or higher, because LodePNG uses unsigned chars for octets. *) gcc and g++ LodePNG is developed in gcc so this compiler is natively supported. It gives no warnings with compiler options "-Wall -Wextra -pedantic -ansi", with gcc and g++ version 4.7.1 on Linux, 32-bit and 64-bit. *) Clang Fully supported and warning-free. *) Mingw The Mingw compiler (a port of gcc for Windows) should be fully supported by LodePNG. *) Visual Studio and Visual C++ Express Edition LodePNG should be warning-free with warning level W4. Two warnings were disabled with pragmas though: warning 4244 about implicit conversions, and warning 4996 where it wants to use a non-standard function fopen_s instead of the standard C fopen. Visual Studio may want "stdafx.h" files to be included in each source file and give an error "unexpected end of file while looking for precompiled header". This is not standard C++ and will not be added to the stock LodePNG. You can disable it for lodepng.cpp only by right clicking it, Properties, C/C++, Precompiled Headers, and set it to Not Using Precompiled Headers there. NOTE: Modern versions of VS should be fully supported, but old versions, e.g. VS6, are not guaranteed to work. *) Compilers on Macintosh LodePNG has been reported to work both with gcc and LLVM for Macintosh, both for C and C++. *) Other Compilers If you encounter problems on any compilers, feel free to let me know and I may try to fix it if the compiler is modern and standards complient. 10. examples ------------ This decoder example shows the most basic usage of LodePNG. More complex examples can be found on the LodePNG website. 10.1. decoder C++ example ------------------------- #include "lodepng.h" #include int main(int argc, char *argv[]) { const char* filename = argc > 1 ? argv[1] : "test.png"; //load and decode std::vector image; unsigned width, height; unsigned error = lodepng::decode(image, width, height, filename); //if there's an error, display it if(error) std::cout << "decoder error " << error << ": " << lodepng_error_text(error) << std::endl; //the pixels are now in the vector "image", 4 bytes per pixel, ordered RGBARGBA..., use it as texture, draw it, ... } 10.2. decoder C example ----------------------- #include "lodepng.h" int main(int argc, char *argv[]) { unsigned error; unsigned char* image; size_t width, height; const char* filename = argc > 1 ? argv[1] : "test.png"; error = lodepng_decode32_file(&image, &width, &height, filename); if(error) printf("decoder error %u: %s\n", error, lodepng_error_text(error)); / * use image here * / free(image); return 0; } 11. changes ----------- The version number of LodePNG is the date of the change given in the format yyyymmdd. Some changes aren't backwards compatible. Those are indicated with a (!) symbol. *) 23 aug 2014: Reduced needless memory usage of decoder. *) 28 jun 2014: Removed fix_png setting, always support palette OOB for simplicity. Made ColorProfile public. *) 09 jun 2014: Faster encoder by fixing hash bug and more zeros optimization. *) 22 dec 2013: Power of two windowsize required for optimization. *) 15 apr 2013: Fixed bug with LAC_ALPHA and color key. *) 25 mar 2013: Added an optional feature to ignore some PNG errors (fix_png). *) 11 mar 2013 (!): Bugfix with custom free. Changed from "my" to "lodepng_" prefix for the custom allocators and made it possible with a new #define to use custom ones in your project without needing to change lodepng's code. *) 28 jan 2013: Bugfix with color key. *) 27 okt 2012: Tweaks in text chunk keyword length error handling. *) 8 okt 2012 (!): Added new filter strategy (entropy) and new auto color mode. (no palette). Better deflate tree encoding. New compression tweak settings. Faster color conversions while decoding. Some internal cleanups. *) 23 sep 2012: Reduced warnings in Visual Studio a little bit. *) 1 sep 2012 (!): Removed #define's for giving custom (de)compression functions and made it work with function pointers instead. *) 23 jun 2012: Added more filter strategies. Made it easier to use custom alloc and free functions and toggle #defines from compiler flags. Small fixes. *) 6 may 2012 (!): Made plugging in custom zlib/deflate functions more flexible. *) 22 apr 2012 (!): Made interface more consistent, renaming a lot. Removed redundant C++ codec classes. Reduced amount of structs. Everything changed, but it is cleaner now imho and functionality remains the same. Also fixed several bugs and shrinked the implementation code. Made new samples. *) 6 nov 2011 (!): By default, the encoder now automatically chooses the best PNG color model and bit depth, based on the amount and type of colors of the raw image. For this, autoLeaveOutAlphaChannel replaced by auto_choose_color. *) 9 okt 2011: simpler hash chain implementation for the encoder. *) 8 sep 2011: lz77 encoder lazy matching instead of greedy matching. *) 23 aug 2011: tweaked the zlib compression parameters after benchmarking. A bug with the PNG filtertype heuristic was fixed, so that it chooses much better ones (it's quite significant). A setting to do an experimental, slow, brute force search for PNG filter types is added. *) 17 aug 2011 (!): changed some C zlib related function names. *) 16 aug 2011: made the code less wide (max 120 characters per line). *) 17 apr 2011: code cleanup. Bugfixes. Convert low to 16-bit per sample colors. *) 21 feb 2011: fixed compiling for C90. Fixed compiling with sections disabled. *) 11 dec 2010: encoding is made faster, based on suggestion by Peter Eastman to optimize long sequences of zeros. *) 13 nov 2010: added LodePNG_InfoColor_hasPaletteAlpha and LodePNG_InfoColor_canHaveAlpha functions for convenience. *) 7 nov 2010: added LodePNG_error_text function to get error code description. *) 30 okt 2010: made decoding slightly faster *) 26 okt 2010: (!) changed some C function and struct names (more consistent). Reorganized the documentation and the declaration order in the header. *) 08 aug 2010: only changed some comments and external samples. *) 05 jul 2010: fixed bug thanks to warnings in the new gcc version. *) 14 mar 2010: fixed bug where too much memory was allocated for char buffers. *) 02 sep 2008: fixed bug where it could create empty tree that linux apps could read by ignoring the problem but windows apps couldn't. *) 06 jun 2008: added more error checks for out of memory cases. *) 26 apr 2008: added a few more checks here and there to ensure more safety. *) 06 mar 2008: crash with encoding of strings fixed *) 02 feb 2008: support for international text chunks added (iTXt) *) 23 jan 2008: small cleanups, and #defines to divide code in sections *) 20 jan 2008: support for unknown chunks allowing using LodePNG for an editor. *) 18 jan 2008: support for tIME and pHYs chunks added to encoder and decoder. *) 17 jan 2008: ability to encode and decode compressed zTXt chunks added Also vareous fixes, such as in the deflate and the padding bits code. *) 13 jan 2008: Added ability to encode Adam7-interlaced images. Improved filtering code of encoder. *) 07 jan 2008: (!) changed LodePNG to use ISO C90 instead of C++. A C++ wrapper around this provides an interface almost identical to before. Having LodePNG be pure ISO C90 makes it more portable. The C and C++ code are together in these files but it works both for C and C++ compilers. *) 29 dec 2007: (!) changed most integer types to unsigned int + other tweaks *) 30 aug 2007: bug fixed which makes this Borland C++ compatible *) 09 aug 2007: some VS2005 warnings removed again *) 21 jul 2007: deflate code placed in new namespace separate from zlib code *) 08 jun 2007: fixed bug with 2- and 4-bit color, and small interlaced images *) 04 jun 2007: improved support for Visual Studio 2005: crash with accessing invalid std::vector element [0] fixed, and level 3 and 4 warnings removed *) 02 jun 2007: made the encoder add a tag with version by default *) 27 may 2007: zlib and png code separated (but still in the same file), simple encoder/decoder functions added for more simple usage cases *) 19 may 2007: minor fixes, some code cleaning, new error added (error 69), moved some examples from here to lodepng_examples.cpp *) 12 may 2007: palette decoding bug fixed *) 24 apr 2007: changed the license from BSD to the zlib license *) 11 mar 2007: very simple addition: ability to encode bKGD chunks. *) 04 mar 2007: (!) tEXt chunk related fixes, and support for encoding palettized PNG images. Plus little interface change with palette and texts. *) 03 mar 2007: Made it encode dynamic Huffman shorter with repeat codes. Fixed a bug where the end code of a block had length 0 in the Huffman tree. *) 26 feb 2007: Huffman compression with dynamic trees (BTYPE 2) now implemented and supported by the encoder, resulting in smaller PNGs at the output. *) 27 jan 2007: Made the Adler-32 test faster so that a timewaste is gone. *) 24 jan 2007: gave encoder an error interface. Added color conversion from any greyscale type to 8-bit greyscale with or without alpha. *) 21 jan 2007: (!) Totally changed the interface. It allows more color types to convert to and is more uniform. See the manual for how it works now. *) 07 jan 2007: Some cleanup & fixes, and a few changes over the last days: encode/decode custom tEXt chunks, separate classes for zlib & deflate, and at last made the decoder give errors for incorrect Adler32 or Crc. *) 01 jan 2007: Fixed bug with encoding PNGs with less than 8 bits per channel. *) 29 dec 2006: Added support for encoding images without alpha channel, and cleaned out code as well as making certain parts faster. *) 28 dec 2006: Added "Settings" to the encoder. *) 26 dec 2006: The encoder now does LZ77 encoding and produces much smaller files now. Removed some code duplication in the decoder. Fixed little bug in an example. *) 09 dec 2006: (!) Placed output parameters of public functions as first parameter. Fixed a bug of the decoder with 16-bit per color. *) 15 okt 2006: Changed documentation structure *) 09 okt 2006: Encoder class added. It encodes a valid PNG image from the given image buffer, however for now it's not compressed. *) 08 sep 2006: (!) Changed to interface with a Decoder class *) 30 jul 2006: (!) LodePNG_InfoPng , width and height are now retrieved in different way. Renamed decodePNG to decodePNGGeneric. *) 29 jul 2006: (!) Changed the interface: image info is now returned as a struct of type LodePNG::LodePNG_Info, instead of a vector, which was a bit clumsy. *) 28 jul 2006: Cleaned the code and added new error checks. Corrected terminology "deflate" into "inflate". *) 23 jun 2006: Added SDL example in the documentation in the header, this example allows easy debugging by displaying the PNG and its transparency. *) 22 jun 2006: (!) Changed way to obtain error value. Added loadFile function for convenience. Made decodePNG32 faster. *) 21 jun 2006: (!) Changed type of info vector to unsigned. Changed position of palette in info vector. Fixed an important bug that happened on PNGs with an uncompressed block. *) 16 jun 2006: Internally changed unsigned into unsigned where needed, and performed some optimizations. *) 07 jun 2006: (!) Renamed functions to decodePNG and placed them in LodePNG namespace. Changed the order of the parameters. Rewrote the documentation in the header. Renamed files to lodepng.cpp and lodepng.h *) 22 apr 2006: Optimized and improved some code *) 07 sep 2005: (!) Changed to std::vector interface *) 12 aug 2005: Initial release (C++, decoder only) 12. contact information ----------------------- Feel free to contact me with suggestions, problems, comments, ... concerning LodePNG. If you encounter a PNG image that doesn't work properly with this decoder, feel free to send it and I'll use it to find and fix the problem. My email address is (puzzle the account and domain together with an @ symbol): Domain: gmail dot com. Account: lode dot vandevenne. Copyright (c) 2005-2014 Lode Vandevenne */ nestopia-1.51.1/source/fltkui/samples.cpp000066400000000000000000000104651411157722000203750ustar00rootroot00000000000000/* * Nestopia UE * * Copyright (C) 2012-2018 R. Danbrook * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include #include #include #include #include #include #include "nstcommon.h" #include "samples.h" static uint8_t* wavfile; extern nstpaths_t nstpaths; int nst_sample_load_file(const char* filepath) { // Load a sample file into memory FILE *file; long filesize; // File size in bytes size_t result; file = fopen(filepath, "rb"); if (!file) { return 0; } fseek(file, 0, SEEK_END); filesize = ftell(file); fseek(file, 0, SEEK_SET); wavfile = (uint8_t*)malloc(filesize * sizeof(uint8_t)); if (wavfile == NULL) { return 0; } result = fread(wavfile, sizeof(uint8_t), filesize, file); if (result != filesize) { return 0; } fclose(file); return 1; } int nst_sample_load_archive(const char* filename, const char* reqfile) { #ifndef _MINGW struct archive *a; struct archive_entry *entry; int r; int64_t entrysize; a = archive_read_new(); archive_read_support_filter_all(a); archive_read_support_format_all(a); r = archive_read_open_filename(a, filename, 10240); // Test if it's actually an archive if (r != ARCHIVE_OK) { r = archive_read_free(a); return 0; } // Scan through the archive for files while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { const char *currentfile = archive_entry_pathname(entry); int len = strlen(currentfile); if ((!strcasecmp(¤tfile[len-4], ".wav"))) { // Load the specified file if (!strcmp(currentfile, reqfile)) { entrysize = archive_entry_size(entry); wavfile = (uint8_t*)malloc(entrysize); archive_read_data(a, wavfile, entrysize); archive_read_data_skip(a); r = archive_read_free(a); return 1; } } } #endif return 0; } int nst_sample_unload_file() { // Free the file if (wavfile) { free(wavfile); } return 1; } void nst_sample_setcontent(User::File& file) { // Parse the .WAV header and load the sample into the emulator // Check to see if it has a valid header uint8_t fmt[4] = { 0x66, 0x6d, 0x74, 0x20}; uint8_t subchunk2id[4] = { 0x64, 0x61, 0x74, 0x61}; if (memcmp(&wavfile[0x00], "RIFF", 4) != 0) { return; } if (memcmp(&wavfile[0x08], "WAVE", 4) != 0) { return; } if (memcmp(&wavfile[0x0c], &fmt, 4) != 0) { return; } if (memcmp(&wavfile[0x24], &subchunk2id, 4) != 0) { return; } // Load the sample into the emulator uint8_t *dataptr = &wavfile[0x2c]; uint32_t datasize = wavfile[0x2b] << 24 | wavfile[0x2a] << 16 | wavfile[0x29] << 8 | wavfile[0x28]; uint16_t blockalign = wavfile[0x21] << 8 | wavfile[0x20]; uint16_t numchannels = wavfile[0x17] << 8 | wavfile[0x16]; uint16_t bitspersample = wavfile[0x23] << 8 | wavfile[0x22]; uint32_t samplerate = wavfile[0x1b] << 24 | wavfile[0x1a] << 16 | wavfile[0x19] << 8 | wavfile[0x18]; file.SetSampleContent(dataptr, datasize / blockalign, numchannels == 2, bitspersample, samplerate); } void nst_sample_load_samples(User::File& file, const char* sampgame) { // Load samples for the specific game char reqfile[16]; char samppath[576]; // Requested sample .wav file snprintf(reqfile, sizeof(reqfile), "%02d.wav", file.GetId()); // Check if there's a MAME-style zip archive snprintf(samppath, sizeof(samppath), "%s%s.zip", nstpaths.sampdir, sampgame); if (nst_sample_load_archive(samppath, reqfile)) { nst_sample_setcontent(file); nst_sample_unload_file(); } else { // Otherwise load .wav files from an extracted directory snprintf(samppath, sizeof(samppath), "%s%s/%s", nstpaths.sampdir, sampgame, reqfile); if (nst_sample_load_file(samppath)) { nst_sample_setcontent(file); nst_sample_unload_file(); } } } nestopia-1.51.1/source/fltkui/samples.h000066400000000000000000000005721411157722000200400ustar00rootroot00000000000000#ifndef _SAMPLES_H_ #define _SAMPLES_H_ #include "core/api/NstApiUser.hpp" using namespace Nes::Api; int nst_sample_load_file(const char* filepath); int nst_sample_load_archive(const char* filename, const char* reqfile); int nst_sample_unload_file(); void nst_sample_setcontent(User::File& file); void nst_sample_load_samples(User::File& file, const char* sampgame); #endif nestopia-1.51.1/source/fltkui/video.cpp000066400000000000000000000504401411157722000200340ustar00rootroot00000000000000/* * Nestopia UE * * Copyright (C) 2007-2008 R. Belmont * Copyright (C) 2012-2021 R. Danbrook * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include #include #include #include #include "core/api/NstApiEmulator.hpp" #include "core/api/NstApiInput.hpp" #include "core/api/NstApiVideo.hpp" #include "core/api/NstApiNsf.hpp" #include #include "nstcommon.h" #include "video.h" #include "config.h" #include "font.h" #include "png.h" using namespace Nes::Api; static int overscan_offset, overscan_height; static uint32_t videobuf[VIDBUF_MAXSIZE]; // Maximum possible internal size static Video::RenderState::Filter filter; static Video::RenderState renderstate; static dimensions_t basesize, rendersize, screensize; static osdtext_t osdtext; extern void *custompalette; extern nstpaths_t nstpaths; extern Emulator emulator; GLuint gl_texture_id = 0; void nst_ogl_init() { // Initialize OpenGL glEnable(GL_TEXTURE_2D); glGenTextures(1, &gl_texture_id); glBindTexture(GL_TEXTURE_2D, gl_texture_id); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, conf.video_linear_filter ? GL_LINEAR : GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); conf.video_fullscreen ? glViewport(screensize.w / 2.0f - rendersize.w / 2.0f, 0, rendersize.w, rendersize.h) : glViewport(0, 0, rendersize.w, rendersize.h); glDisable(GL_DEPTH_TEST); glDisable(GL_ALPHA_TEST); glDisable(GL_BLEND); glDisable(GL_LIGHTING); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, rendersize.w * conf.video_scale_factor, rendersize.h * conf.video_scale_factor, 0.0, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void nst_ogl_deinit() { // Deinitialize OpenGL if (gl_texture_id) { glDeleteTextures(1, &gl_texture_id); } } void nst_ogl_render() { // Render the scene glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, basesize.w, overscan_height, 0, GL_BGRA, GL_UNSIGNED_BYTE, videobuf + overscan_offset); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_QUADS); glTexCoord2f(1.0f, 1.0f); glVertex2f(rendersize.w * conf.video_scale_factor, rendersize.h * conf.video_scale_factor); glTexCoord2f(1.0f, 0.0f); glVertex2f(rendersize.w * conf.video_scale_factor, 0.0); glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0, 0.0); glTexCoord2f(0.0f, 1.0f); glVertex2f(0, rendersize.h * conf.video_scale_factor); glEnd(); } void nst_video_refresh() { // Refresh the video settings nst_ogl_deinit(); nst_ogl_init(); } void video_init() { // Initialize video nst_ogl_deinit(); video_set_dimensions(); video_set_filter(); nst_ogl_init(); if (nst_nsf()) { video_clear_buffer(); video_disp_nsf(); } } void video_toggle_filterupdate() { // Clear the filter update flag Video video(emulator); video.ClearFilterUpdateFlag(); } void video_set_filter() { // Set the filter Video video(emulator); int scalefactor = conf.video_scale_factor; if (conf.video_scale_factor > 4) { scalefactor = 4; } if ((conf.video_scale_factor > 3) && (conf.video_filter == 5)) { scalefactor = 3; } switch(conf.video_filter) { case 0: // None filter = Video::RenderState::FILTER_NONE; break; case 1: // NTSC filter = Video::RenderState::FILTER_NTSC; break; case 2: // xBR switch (scalefactor) { case 2: filter = Video::RenderState::FILTER_2XBR; break; case 3: filter = Video::RenderState::FILTER_3XBR; break; case 4: filter = Video::RenderState::FILTER_4XBR; break; default: filter = Video::RenderState::FILTER_NONE; break; } break; case 3: // scale HQx switch (scalefactor) { case 2: filter = Video::RenderState::FILTER_HQ2X; break; case 3: filter = Video::RenderState::FILTER_HQ3X; break; case 4: filter = Video::RenderState::FILTER_HQ4X; break; default: filter = Video::RenderState::FILTER_NONE; break; } break; case 4: // 2xSaI filter = Video::RenderState::FILTER_2XSAI; break; case 5: // scale x switch (scalefactor) { case 2: filter = Video::RenderState::FILTER_SCALE2X; break; case 3: filter = Video::RenderState::FILTER_SCALE3X; break; default: filter = Video::RenderState::FILTER_NONE; break; } break; break; } // Set the sprite limit: false = enable sprite limit, true = disable sprite limit video.EnableUnlimSprites(conf.video_unlimited_sprites ? true : false); // Set Palette options switch (conf.video_palette_mode) { case 0: // YUV video.GetPalette().SetMode(Video::Palette::MODE_YUV); break; case 1: // RGB video.GetPalette().SetMode(Video::Palette::MODE_RGB); break; case 2: // Custom video.GetPalette().SetMode(Video::Palette::MODE_CUSTOM); video.GetPalette().SetCustom((const unsigned char (*)[3])custompalette, Video::Palette::EXT_PALETTE); break; default: break; } // Set YUV Decoder/Picture options if (video.GetPalette().GetMode() == Video::Palette::MODE_YUV) { switch (conf.video_decoder) { case 0: // Consumer video.SetDecoder(Video::DECODER_CONSUMER); break; case 1: // Canonical video.SetDecoder(Video::DECODER_CANONICAL); break; case 2: // Alternative (Canonical with yellow boost) video.SetDecoder(Video::DECODER_ALTERNATIVE); break; default: break; } } video.SetBrightness(conf.video_brightness); video.SetSaturation(conf.video_saturation); video.SetContrast(conf.video_contrast); video.SetHue(conf.video_hue); // Set NTSC options if (conf.video_filter == 1) { switch (conf.video_ntsc_mode) { case 0: // Composite video.SetSaturation(Video::DEFAULT_SATURATION_COMP); video.SetSharpness(Video::DEFAULT_SHARPNESS_COMP); video.SetColorResolution(Video::DEFAULT_COLOR_RESOLUTION_COMP); video.SetColorBleed(Video::DEFAULT_COLOR_BLEED_COMP); video.SetColorArtifacts(Video::DEFAULT_COLOR_ARTIFACTS_COMP); video.SetColorFringing(Video::DEFAULT_COLOR_FRINGING_COMP); break; case 1: // S-Video video.SetSaturation(Video::DEFAULT_SATURATION_SVIDEO); video.SetSharpness(Video::DEFAULT_SHARPNESS_SVIDEO); video.SetColorResolution(Video::DEFAULT_COLOR_RESOLUTION_SVIDEO); video.SetColorBleed(Video::DEFAULT_COLOR_BLEED_SVIDEO); video.SetColorArtifacts(Video::DEFAULT_COLOR_ARTIFACTS_SVIDEO); video.SetColorFringing(Video::DEFAULT_COLOR_FRINGING_SVIDEO); break; case 2: // RGB video.SetSaturation(Video::DEFAULT_SATURATION_RGB); video.SetSharpness(Video::DEFAULT_SHARPNESS_RGB); video.SetColorResolution(Video::DEFAULT_COLOR_RESOLUTION_RGB); video.SetColorBleed(Video::DEFAULT_COLOR_BLEED_RGB); video.SetColorArtifacts(Video::DEFAULT_COLOR_ARTIFACTS_RGB); video.SetColorFringing(Video::DEFAULT_COLOR_FRINGING_RGB); break; case 3: // Monochrome video.SetSaturation(Video::DEFAULT_SATURATION_MONO); video.SetSharpness(Video::DEFAULT_SHARPNESS_MONO); video.SetColorResolution(Video::DEFAULT_COLOR_RESOLUTION_MONO); video.SetColorBleed(Video::DEFAULT_COLOR_BLEED_MONO); video.SetColorArtifacts(Video::DEFAULT_COLOR_ARTIFACTS_MONO); video.SetColorFringing(Video::DEFAULT_COLOR_FRINGING_MONO); break; case 4: // Custom video.SetSaturation(conf.video_saturation); video.SetSharpness(conf.video_ntsc_sharpness); video.SetColorResolution(conf.video_ntsc_resolution); video.SetColorBleed(conf.video_ntsc_bleed); video.SetColorArtifacts(conf.video_ntsc_artifacts); video.SetColorFringing(conf.video_ntsc_fringing); break; default: break; } } // Set xBR options if (conf.video_filter == 2) { video.SetCornerRounding(conf.video_xbr_corner_rounding); video.SetBlend(conf.video_xbr_pixel_blending); } // Set up the render state parameters renderstate.filter = filter; renderstate.width = basesize.w; renderstate.height = basesize.h; renderstate.bits.count = 32; int e = 1; // Check Endianness if ((int)*((unsigned char *)&e) == 1) { // Little Endian renderstate.bits.mask.r = 0x00ff0000; renderstate.bits.mask.g = 0x0000ff00; renderstate.bits.mask.b = 0x000000ff; } else { // Big Endian renderstate.bits.mask.r = 0x0000ff00; renderstate.bits.mask.g = 0x00ff0000; renderstate.bits.mask.b = 0xff000000; } if (NES_FAILED(video.SetRenderState(renderstate))) { fprintf(stderr, "Nestopia core rejected render state\n"); exit(1); } } dimensions_t nst_video_get_dimensions_render() { // Return the dimensions of the rendered video return rendersize; } dimensions_t nst_video_get_dimensions_screen() { // Return the dimensions of the screen return screensize; } void nst_video_set_dimensions_screen(dimensions_t scrsize) { screensize = scrsize; } void video_set_dimensions() { // Set up the video dimensions int scalefactor = conf.video_scale_factor; if (conf.video_scale_factor > 4) { scalefactor = 4; } if ((conf.video_scale_factor > 3) && (conf.video_filter == 5)) { scalefactor = 3; } int wscalefactor = conf.video_scale_factor; int tvwidth = nst_pal() ? PAL_TV_WIDTH : TV_WIDTH; switch(conf.video_filter) { case 0: // None basesize.w = Video::Output::WIDTH; basesize.h = Video::Output::HEIGHT; conf.video_tv_aspect == true ? rendersize.w = tvwidth * wscalefactor : rendersize.w = basesize.w * wscalefactor; rendersize.h = basesize.h * wscalefactor; overscan_offset = basesize.w * OVERSCAN_TOP; overscan_height = basesize.h - OVERSCAN_TOP - OVERSCAN_BOTTOM; break; case 1: // NTSC basesize.w = Video::Output::NTSC_WIDTH; rendersize.w = (basesize.w / 2) * wscalefactor; basesize.h = Video::Output::HEIGHT; rendersize.h = basesize.h * wscalefactor; overscan_offset = basesize.w * OVERSCAN_TOP; overscan_height = basesize.h - OVERSCAN_TOP - OVERSCAN_BOTTOM; break; case 2: // xBR case 3: // HqX case 5: // ScaleX basesize.w = Video::Output::WIDTH * scalefactor; basesize.h = Video::Output::HEIGHT * scalefactor; conf.video_tv_aspect == true ? rendersize.w = tvwidth * wscalefactor : rendersize.w = Video::Output::WIDTH * wscalefactor; rendersize.h = Video::Output::HEIGHT * wscalefactor; overscan_offset = basesize.w * OVERSCAN_TOP * scalefactor; overscan_height = basesize.h - (OVERSCAN_TOP + OVERSCAN_BOTTOM) * scalefactor; break; case 4: // 2xSaI basesize.w = Video::Output::WIDTH * 2; basesize.h = Video::Output::HEIGHT * 2; conf.video_tv_aspect == true ? rendersize.w = tvwidth * wscalefactor : rendersize.w = Video::Output::WIDTH * wscalefactor; rendersize.h = Video::Output::HEIGHT * wscalefactor; overscan_offset = basesize.w * OVERSCAN_TOP * 2; overscan_height = basesize.h - (OVERSCAN_TOP + OVERSCAN_BOTTOM) * 2; break; } if (!conf.video_unmask_overscan) { rendersize.h -= (OVERSCAN_TOP + OVERSCAN_BOTTOM) * scalefactor; } else { overscan_offset = 0; overscan_height = basesize.h; } // Calculate the aspect from the height because it's smaller if (conf.video_fullscreen) { float aspect = (float)screensize.h / (float)rendersize.h; rendersize.w *= aspect; rendersize.h *= aspect; } } long video_lock_screen(void*& ptr) { ptr = videobuf; return basesize.w * 4; } void video_unlock_screen(void*) { int xscale = renderstate.width / Video::Output::WIDTH;; int yscale = renderstate.height / Video::Output::HEIGHT; if (osdtext.drawtext) { nst_video_text_draw(osdtext.textbuf, osdtext.xpos * xscale, osdtext.ypos * yscale, osdtext.bg); osdtext.drawtext--; } if (osdtext.drawtime) { nst_video_text_draw(osdtext.timebuf, 208 * xscale, 218 * yscale, false); } } void video_screenshot_flip(unsigned char *pixels, int width, int height, int bytes) { // Flip the pixels int rowsize = width * bytes; unsigned char *row = (unsigned char*)malloc(rowsize); unsigned char *low = pixels; unsigned char *high = &pixels[(height - 1) * rowsize]; for (; low < high; low += rowsize, high -= rowsize) { memcpy(row, low, rowsize); memcpy(low, high, rowsize); memcpy(high, row, rowsize); } free(row); } void video_screenshot(const char* filename) { // Take a screenshot in .png format unsigned char *pixels; pixels = (unsigned char*)malloc(sizeof(unsigned char) * rendersize.w * rendersize.h * 4); // Read the pixels and flip them vertically glReadPixels(0, 0, rendersize.w, rendersize.h, GL_RGBA, GL_UNSIGNED_BYTE, pixels); video_screenshot_flip(pixels, rendersize.w, rendersize.h, 4); if (filename == NULL) { // Set the filename char sshotpath[512]; snprintf(sshotpath, sizeof(sshotpath), "%sscreenshots/%s-%ld-%d.png", nstpaths.nstdir, nstpaths.gamename, time(NULL), rand() % 899 + 100); // Save the file lodepng_encode32_file(sshotpath, (const unsigned char*)pixels, rendersize.w, rendersize.h); fprintf(stderr, "Screenshot: %s\n", sshotpath); } else { lodepng_encode32_file(filename, (const unsigned char*)pixels, rendersize.w, rendersize.h); } free(pixels); } void video_clear_buffer() { // Write black to the video buffer memset(videobuf, 0x00000000, VIDBUF_MAXSIZE); } void video_disp_nsf() { // Display NSF text Nsf nsf(emulator); int xscale = renderstate.width / Video::Output::WIDTH;; int yscale = renderstate.height / Video::Output::HEIGHT;; nst_video_text_draw(nsf.GetName(), 4 * xscale, 16 * yscale, false); nst_video_text_draw(nsf.GetArtist(), 4 * xscale, 28 * yscale, false); nst_video_text_draw(nsf.GetCopyright(), 4 * xscale, 40 * yscale, false); char currentsong[10]; snprintf(currentsong, sizeof(currentsong), "%d / %d", nsf.GetCurrentSong() +1, nsf.GetNumSongs()); nst_video_text_draw(currentsong, 4 * xscale, 52 * yscale, false); nst_ogl_render(); } void nst_video_print(const char *text, int xpos, int ypos, int seconds, bool bg) { snprintf(osdtext.textbuf, sizeof(osdtext.textbuf), "%s", text); osdtext.xpos = xpos; osdtext.ypos = ypos; osdtext.drawtext = seconds * nst_pal() ? 50 : 60; osdtext.bg = bg; } void nst_video_print_time(const char *timebuf, bool drawtime) { snprintf(osdtext.timebuf, sizeof(osdtext.timebuf), "%s", timebuf); osdtext.drawtime = drawtime; } void nst_video_text_draw(const char *text, int xpos, int ypos, bool bg) { // Draw text on screen uint32_t w = 0xc0c0c0c0; // "White", actually Grey uint32_t b = 0x00000000; // Black uint32_t g = 0x00358570; // Nestopia UE Green uint32_t d = 0x00255f65; // Nestopia UE Dark Green int numchars = strlen(text); int letterypos; int letterxpos; int letternum = 0; if (bg) { // Draw background borders for (int i = 0; i < numchars * 8; i++) { // Rows above and below videobuf[(xpos + i) + ((ypos - 1) * renderstate.width)] = g; videobuf[(xpos + i) + ((ypos + 8) * renderstate.width)] = g; } for (int i = 0; i < 8; i++) { // Columns on both sides videobuf[(xpos - 1) + ((ypos + i) * renderstate.width)] = g; videobuf[(xpos + (numchars * 8)) + ((ypos + i) * renderstate.width)] = g; } } for (int tpos = 0; tpos < (8 * numchars); tpos+=8) { nst_video_text_match(text, &letterxpos, &letterypos, letternum); for (int row = 0; row < 8; row++) { // Draw Rows for (int col = 0; col < 8; col++) { // Draw Columns switch (nesfont[row + letterypos][col + letterxpos]) { case '.': videobuf[xpos + ((ypos + row) * renderstate.width) + (col + tpos)] = w; break; case '+': videobuf[xpos + ((ypos + row) * renderstate.width) + (col + tpos)] = g; break; default: if (bg) { videobuf[xpos + ((ypos + row) * renderstate.width) + (col + tpos)] = d; } break; } } } letternum++; } } void nst_video_text_match(const char *text, int *xpos, int *ypos, int strpos) { // Match letters to draw on screen switch (text[strpos]) { case ' ': *xpos = 0; *ypos = 0; break; case '!': *xpos = 8; *ypos = 0; break; case '"': *xpos = 16; *ypos = 0; break; case '#': *xpos = 24; *ypos = 0; break; case '$': *xpos = 32; *ypos = 0; break; case '%': *xpos = 40; *ypos = 0; break; case '&': *xpos = 48; *ypos = 0; break; case '\'': *xpos = 56; *ypos = 0; break; case '(': *xpos = 64; *ypos = 0; break; case ')': *xpos = 72; *ypos = 0; break; case '*': *xpos = 80; *ypos = 0; break; case '+': *xpos = 88; *ypos = 0; break; case ',': *xpos = 96; *ypos = 0; break; case '-': *xpos = 104; *ypos = 0; break; case '.': *xpos = 112; *ypos = 0; break; case '/': *xpos = 120; *ypos = 0; break; case '0': *xpos = 0; *ypos = 8; break; case '1': *xpos = 8; *ypos = 8; break; case '2': *xpos = 16; *ypos = 8; break; case '3': *xpos = 24; *ypos = 8; break; case '4': *xpos = 32; *ypos = 8; break; case '5': *xpos = 40; *ypos = 8; break; case '6': *xpos = 48; *ypos = 8; break; case '7': *xpos = 56; *ypos = 8; break; case '8': *xpos = 64; *ypos = 8; break; case '9': *xpos = 72; *ypos = 8; break; case ':': *xpos = 80; *ypos = 8; break; case ';': *xpos = 88; *ypos = 8; break; case '<': *xpos = 96; *ypos = 8; break; case '=': *xpos = 104; *ypos = 8; break; case '>': *xpos = 112; *ypos = 8; break; case '?': *xpos = 120; *ypos = 8; break; case '@': *xpos = 0; *ypos = 16; break; case 'A': *xpos = 8; *ypos = 16; break; case 'B': *xpos = 16; *ypos = 16; break; case 'C': *xpos = 24; *ypos = 16; break; case 'D': *xpos = 32; *ypos = 16; break; case 'E': *xpos = 40; *ypos = 16; break; case 'F': *xpos = 48; *ypos = 16; break; case 'G': *xpos = 56; *ypos = 16; break; case 'H': *xpos = 64; *ypos = 16; break; case 'I': *xpos = 72; *ypos = 16; break; case 'J': *xpos = 80; *ypos = 16; break; case 'K': *xpos = 88; *ypos = 16; break; case 'L': *xpos = 96; *ypos = 16; break; case 'M': *xpos = 104; *ypos = 16; break; case 'N': *xpos = 112; *ypos = 16; break; case 'O': *xpos = 120; *ypos = 16; break; case 'P': *xpos = 0; *ypos = 24; break; case 'Q': *xpos = 8; *ypos = 24; break; case 'R': *xpos = 16; *ypos = 24; break; case 'S': *xpos = 24; *ypos = 24; break; case 'T': *xpos = 32; *ypos = 24; break; case 'U': *xpos = 40; *ypos = 24; break; case 'V': *xpos = 48; *ypos = 24; break; case 'W': *xpos = 56; *ypos = 24; break; case 'X': *xpos = 64; *ypos = 24; break; case 'Y': *xpos = 72; *ypos = 24; break; case 'Z': *xpos = 80; *ypos = 24; break; case '[': *xpos = 88; *ypos = 24; break; case '\\': *xpos = 96; *ypos = 24; break; case ']': *xpos = 104; *ypos = 24; break; case '^': *xpos = 112; *ypos = 24; break; case '_': *xpos = 120; *ypos = 24; break; case '`': *xpos = 0; *ypos = 32; break; case 'a': *xpos = 8; *ypos = 32; break; case 'b': *xpos = 16; *ypos = 32; break; case 'c': *xpos = 24; *ypos = 32; break; case 'd': *xpos = 32; *ypos = 32; break; case 'e': *xpos = 40; *ypos = 32; break; case 'f': *xpos = 48; *ypos = 32; break; case 'g': *xpos = 56; *ypos = 32; break; case 'h': *xpos = 64; *ypos = 32; break; case 'i': *xpos = 72; *ypos = 32; break; case 'j': *xpos = 80; *ypos = 32; break; case 'k': *xpos = 88; *ypos = 32; break; case 'l': *xpos = 96; *ypos = 32; break; case 'm': *xpos = 104; *ypos = 32; break; case 'n': *xpos = 112; *ypos = 32; break; case 'o': *xpos = 120; *ypos = 32; break; case 'p': *xpos = 0; *ypos = 40; break; case 'q': *xpos = 8; *ypos = 40; break; case 'r': *xpos = 16; *ypos = 40; break; case 's': *xpos = 24; *ypos = 40; break; case 't': *xpos = 32; *ypos = 40; break; case 'u': *xpos = 40; *ypos = 40; break; case 'v': *xpos = 48; *ypos = 40; break; case 'w': *xpos = 56; *ypos = 40; break; case 'x': *xpos = 64; *ypos = 40; break; case 'y': *xpos = 72; *ypos = 40; break; case 'z': *xpos = 80; *ypos = 40; break; case '{': *xpos = 88; *ypos = 40; break; case '|': *xpos = 96; *ypos = 40; break; case '}': *xpos = 104; *ypos = 40; break; case '~': *xpos = 112; *ypos = 40; break; //case ' ': *xpos = 120; *ypos = 40; break; // Triangle default: *xpos = 0; *ypos = 0; break; } } nestopia-1.51.1/source/fltkui/video.h000066400000000000000000000022561411157722000175030ustar00rootroot00000000000000#ifndef _VIDEO_H_ #define _VIDEO_H_ #define TV_WIDTH 292 #define PAL_TV_WIDTH 320 #define OVERSCAN_LEFT 0 #define OVERSCAN_RIGHT 0 #define OVERSCAN_BOTTOM 8 #define OVERSCAN_TOP 8 #define VIDBUF_MAXSIZE 31457280 typedef struct { int w; int h; } dimensions_t; typedef struct { int xpos; int ypos; char textbuf[32]; char timebuf[6]; int drawtext; bool drawtime; bool bg; } osdtext_t; void nst_ogl_init(); void nst_ogl_deinit(); void nst_ogl_render(); void video_init(); void video_toggle_filterupdate(); void video_set_filter(); dimensions_t nst_video_get_dimensions_render(); dimensions_t nst_video_get_dimensions_screen(); void nst_video_set_dimensions_screen(dimensions_t scrsize); void video_set_dimensions(); long video_lock_screen(void*& ptr); void video_unlock_screen(void*); void video_screenshot(const char* filename); void video_clear_buffer(); void video_disp_nsf(); void nst_video_print(const char *text, int xpos, int ypos, int seconds, bool bg); void nst_video_print_time(const char *timebuf, bool drawtime); void nst_video_text_draw(const char *text, int xpos, int ypos, bool bg); void nst_video_text_match(const char *text, int *xpos, int *ypos, int strpos); #endif nestopia-1.51.1/source/kaillera/000077500000000000000000000000001411157722000165055ustar00rootroot00000000000000nestopia-1.51.1/source/kaillera/kailleraclient.h000066400000000000000000000110251411157722000216400ustar00rootroot00000000000000/* Kaillera client API v0.84 (c) 2001 Christophe Thibault History: 0.84: added moreInfos callback 0.83: added clientDropped callback 0.8 : added in-game chat function/callback 0.72: added kailleraEndGame() method added kailleraGetVersion() method 0.7: modified kailleraModifyPlayValues behaviour */ ////////////////////////////////////////////////////////////////////////////////////// // // Nestopia changes: // // - added 'int' as return type in DLLEXP macros to suppress compiler warning messages // // 2004-07-28 / Martin Freij // ////////////////////////////////////////////////////////////////////////////////////// #ifndef KAILLERA_CLIENT_H #define KAILLERA_CLIENT_H #ifdef _WIN32 #include #endif #define KAILLERA_CLIENT_API_VERSION "0.8" #ifdef KAILLERA_DLL #define DLLEXP __declspec(dllexport) int WINAPI #else #define DLLEXP __declspec(dllimport) int WINAPI #endif #ifdef __cplusplus extern "C" { #endif typedef struct { char *appName; char *gameList; int (WINAPI *gameCallback)(char *game, int player, int numplayers); void (WINAPI *chatReceivedCallback)(char *nick, char *text); void (WINAPI *clientDroppedCallback)(char *nick, int playernb); void (WINAPI *moreInfosCallback)(char *gamename); } kailleraInfos; /* kailleraGetVersion Call this method to retrieve kailleraclient.dll's version - version must point to a char[16] buffer */ DLLEXP kailleraGetVersion(char *version); /* kailleraInit: Call this method when your program starts */ DLLEXP kailleraInit(); /* kailleraShutdown: Call this method when your program ends */ DLLEXP kailleraShutdown(); /* kailleraSetInfos: Use this method for setting up various infos: Required: - appName must be 128 chars max. - gameList is composed of all the game names separated by a NULL char (\0). The list ends with 2 NULL chars (\0\0). Be sure to only put available games there. - gameCallback will be the function called when a new game starts game -> name of the selected game player -> player number (1-8). 0 for spectator. numplayers -> number of players in the game (1-8) Optional: - chatReceivedCallback will be the function called when a chat line text has been received. Set it to NULL if you don't need/want this callback. - clientDroppedCallback will be the function called when a client drops from the current game. Set it to NULL if you don't need/want this callback. - moreInfosCallback will be the function called when the user selects "More infos about this game..." in the game list context menu. Set it to NULL if you don't need/want this feature. */ DLLEXP kailleraSetInfos(kailleraInfos *infos); /* kailleraSelectServerDialog: Use this method for launching the Kaillera server dialog */ DLLEXP kailleraSelectServerDialog(HWND parent); /* kailleraModifyPlayValues: You must call this method at every frame after you retrieved values from your input devices. This method will record/bufferize the values you send in and will manage to mix them with the other players. Basically, each players sends his values and receive all players values concatened. e.g: t - player 1 sends "867F" - player 2 sends "964F" t+1 - player 1 receives "867F964F" - player 2 receives "867F964F" you may want to look at the modified MAME source code available on kaillera's home page to have a working example out of this (look in inptport.c) Ideally, your input values should be defined like 1 bit for a given key, which has to be unset when the key is not pressed and set when the key is pressed. The size of the values you pass to this function is the size for ONE player's values. Also, it must be the SAME for a given game and should be kept to a minimum (for network speed and latency issues). Be sure that the values parameters has enough space for receiving all inputs from all players (8 players max.) returns: length received or -1 on network error (player no more in the game) */ DLLEXP kailleraModifyPlayValues(void *values, int size); /* kailleraChatSend Use this function to send a line of chat text during a game */ DLLEXP kailleraChatSend(char *text); /* kailleraEndGame: Your emulation thread must call this method when the user stops the emulation */ DLLEXP kailleraEndGame(); #ifdef __cplusplus } #endif #endif nestopia-1.51.1/source/kaillera/sdk-readme.txt000066400000000000000000000005441411157722000212650ustar00rootroot00000000000000well, everything should be self explained in kailleraclient.h. if you need a sample, go look at the Kaillera implementation in the Mame32 source code, available on Kaillera's home page (http://www.kaillera.com/) if you still have troubles/problems implementing the Kaillera client into your application, go look into the Kaillera SDK forums. -christophenestopia-1.51.1/source/nes_ntsc/000077500000000000000000000000001411157722000165355ustar00rootroot00000000000000nestopia-1.51.1/source/nes_ntsc/benchmark.c000066400000000000000000000035201411157722000206330ustar00rootroot00000000000000/* Measures performance of blitter, useful for improving a custom blitter. NOTE: This assumes that the process is getting 100% CPU time; you might need to arrange for this or else the performance will be reported lower than it really is. */ #include "nes_ntsc.h" #include #include #include enum { in_width = 256 }; enum { in_height = 240 }; enum { out_width = NES_NTSC_OUT_WIDTH( in_width ) }; enum { out_height = in_height }; struct data_t { nes_ntsc_t ntsc; unsigned char in [ in_height] [ in_width]; unsigned short out [out_height] [out_width]; }; static int time_blitter( void ); int main() { struct data_t* data = (struct data_t*) malloc( sizeof *data ); if ( data ) { /* fill with random pixel data */ int y; for ( y = 0; y < in_height; y++ ) { int x; for ( x = 0; x < in_width; x++ ) data->in [y] [x] = rand() >> 4 & 0x1F; } printf( "Timing nes_ntsc...\n" ); fflush( stdout ); nes_ntsc_init( &data->ntsc, 0 ); /* measure frame rate */ while ( time_blitter() ) { nes_ntsc_blit( &data->ntsc, data->in [0], in_width, 0, in_width, in_height, data->out [0], sizeof data->out [0] ); } free( data ); } getchar(); return 0; } static int time_blitter( void ) { int const duration = 4; /* seconds */ static clock_t end_time; static int count; if ( !count ) { clock_t time = clock(); while ( clock() == time ) { } if ( clock() - time > CLOCKS_PER_SEC ) { /* clock increments less-often than once every second */ printf( "Insufficient time resolution\n" ); return 0; } end_time = clock() + CLOCKS_PER_SEC * duration; } else if ( clock() >= end_time ) { int rate = count / duration; printf( "Performance: %d frames per second, which would use %d%% CPU at 60 FPS\n", rate, 60 * 100 / rate ); return 0; } count++; return 1; } nestopia-1.51.1/source/nes_ntsc/changes.txt000066400000000000000000000112221411157722000207040ustar00rootroot00000000000000nes_ntsc Change Log ------------------- nes_ntsc 0.2.2 -------------- - Added ability to use a custom RGB palette in place of the NES color circuitry (with the option of being before color emphasis). When using this palette with otherwise default settings, RGB colors appear on screen exactly as in custom palette. - Moved configuration options to nes_ntsc_config.h, making it easier to manage - Made color emphasis support configurable in nes_ntsc_config.h (off by default). Previously, there were separate functions; now there is only one set of functions and whether they support color emphasis is configurable. If color emphasis support is OFF, then nes_ntsc_init() and related behave as before, and the nes_ntsc_init_emph() functionality is not available. If color emphasis support is ON, then nes_ntsc_init() and related behave as nes_ntsc_init_emph() and related did before, and nes_ntsc_init() and related functionality is not available (so you would need to update any code that uses palette_out and expects only 64 colors to be written; see the end of demo.c for example). - Removed hue_warping for now, due to its obscurity - Greatly clarified and improved demo to read any uncompressed BMP image and write filtered image when done - Improved gamma to be properly applied to each RGB channel, and changed default to compensate for difference between PC monitor and TV gamma - Improved contrast to be properly applied to each RGB channel rather than just luma - Improved floating point calculations in library to be more stable and not need double precision, which was causing problems with the sharpness control on Windows when the DirectX libraries changed the FPU to single precision mode - Eliminated slight artifacts still visible when using the RGB preset with field merging off - Added extern "C" to header, allowing use in C++ without having to rename the source file - Made internal changes to factor out code common from all my NTSC filter libraries, greatly simplifying things for me nes_ntsc 0.2.0 -------------- - Significantly improved NTSC signal processing to give clearer image and better sharpness control - Added parameters for gamma, resolution, color bleed, artifacts, and color fringing - Added presets for composite video, S-video, RGB, and monochrome - Added NES_NTSC_OUT_WIDTH() and NES_NTSC_IN_WIDTH() for calculating input/output widths - Improved default blitter to support emphasis and allow specification of RGB output bit depth - Improved demo with more controls and interpolation and darkening of scanlines rather than duplicating them - Improved documentation - Interface changes: nes_ntsc_blit() now takes *input* size rather than output size. NES_NTSC_BEGIN_ROW now takes two additional pixels. - Deprecated: nes_ntsc_x_in/out_width, NES_NTSC_RGBnn_OUT, and NES_NTSC_RAW_OUT nes_ntsc 0.1.7 -------------- - Fixed color emphasis to affect xD colors instead of incorrectly leaving them as always gray - Added ability to generate a 64- or 512-color RGB palette for use when full NTSC emulation isn't desired - Documented more accurate burst_phase handling and included three test ROMs for verifying proper implementation - Moved color emphasis support to new nes_ntsc_emph_t structure, eliminating the ugly global NES_NTSC_DISABLE_EMPHASIS configuration macro - Extended demo to use optional Sony decoder matrix and write standard 192-byte NES .PAL file using current settings - Improved documentation slightly - Lowered maximum saturation to avoid overflow of blue when blue color emphasis is enabled nes_ntsc 0.1.6 -------------- - Cleaned up hue, decoder matrix, and hue warping to do transformations in the proper order and direction nes_ntsc 0.1.5 -------------- - Added support for color emphasis/tint bits (can be turned off to reduce memory usage) - Added ability to specify optional decoder matrix - Improved documentation - Added constants for overscan borders nes_ntsc 0.1.0 -------------- - First official version - Completely rewrote algorithm to do all NTSC signal processing at initialization time, putting results into a table for use during blitting. This increased performance by over 300% and allowed many improvements in quality and image options. - Eliminated multiple output formats and options. Now you can define a custom blitter for this. - Added sharpness and "hue warping" controls - Added option to merge even and odd artifacts to reduce flicker when host monitor's refresh rate doesn't match emulator's frame rate. - Added built-in horizontal rescaling. I never realized the old one was way too wide. nestopia-1.51.1/source/nes_ntsc/demo.c000066400000000000000000000066531411157722000176370ustar00rootroot00000000000000/* Displays and saves NTSC filtered image. Mouse controls sharpness and gamma. Defaults to using "test.bmp" for input and "filtered.bmp" for output. Input image must be an uncompressed BMP. Also writes "nes.pal" RGB color file on exit. Usage: demo [in.bmp [out.bmp]] Space Toggle field merging C Composite video quality S S-video quality R RGB video quality M Monochrome video quality D Toggle between standard and Sony decoder matrix */ #include "nes_ntsc.h" #include "demo_impl.h" /* only used to convert input image to native palette format */ static SDL_Color palette [256] = { {102,102,102},{ 0, 42,136},{ 20, 18,168},{ 59, 0,164}, { 92, 0,126},{110, 0, 64},{108, 7, 0},{ 87, 29, 0}, { 52, 53, 0},{ 12, 73, 0},{ 0, 82, 0},{ 0, 79, 8}, { 0, 64, 78},{ 0, 0, 0},{ 0, 0, 0},{ 0, 0, 0}, {174,174,174},{ 21, 95,218},{ 66, 64,254},{118, 39,255}, {161, 27,205},{184, 30,124},{181, 50, 32},{153, 79, 0}, {108,110, 0},{ 56,135, 0},{ 13,148, 0},{ 0,144, 50}, { 0,124,142},{ 0, 0, 0},{ 0, 0, 0},{ 0, 0, 0}, {254,254,254},{100,176,254},{147,144,254},{199,119,254}, {243,106,254},{254,110,205},{254,130,112},{235,159, 35}, {189,191, 0},{137,217, 0},{ 93,229, 48},{ 69,225,130}, { 72,206,223},{ 79, 79, 79},{ 0, 0, 0},{ 0, 0, 0}, {254,254,254},{193,224,254},{212,211,254},{233,200,254}, {251,195,254},{254,197,235},{254,205,198},{247,217,166}, {229,230,149},{208,240,151},{190,245,171},{180,243,205}, {181,236,243},{184,184,184},{ 0, 0, 0},{ 0, 0, 0} }; int main( int argc, char** argv ) { image_t image; int sony_decoder = 0; int merge_fields = 1; int burst_phase = 0; nes_ntsc_setup_t setup = nes_ntsc_composite; nes_ntsc_t* ntsc = (nes_ntsc_t*) malloc( sizeof (nes_ntsc_t) ); if ( !ntsc ) fatal_error( "Out of memory" ); nes_ntsc_init( ntsc, &setup ); load_bmp( &image, (argc > 1 ? argv [1] : "test.bmp"), palette ); init_window( NES_NTSC_OUT_WIDTH( image.width ), image.height * 2 ); while ( read_input() ) { lock_pixels(); burst_phase ^= 1; if ( setup.merge_fields ) burst_phase = 0; nes_ntsc_blit( ntsc, image.byte_pixels, image.row_width, burst_phase, image.width, image.height, output_pixels, output_pitch ); double_output_height(); display_output(); switch ( key_pressed ) { case ' ': merge_fields = !merge_fields; break; case 'c': setup = nes_ntsc_composite; break; case 's': setup = nes_ntsc_svideo; break; case 'r': setup = nes_ntsc_rgb; break; case 'm': setup = nes_ntsc_monochrome; break; case 'd': sony_decoder = !sony_decoder; break; } if ( key_pressed || mouse_moved ) { setup.merge_fields = merge_fields; /* available parameters: hue, saturation, contrast, brightness, sharpness, gamma, bleed, resolution, artifacts, fringing */ setup.sharpness = mouse_x; setup.gamma = mouse_y; setup.decoder_matrix = 0; if ( sony_decoder ) { /* Sony CXA2025AS US */ static float matrix [6] = { 1.630, 0.317, -0.378, -0.466, -1.089, 1.677 }; setup.decoder_matrix = matrix; } nes_ntsc_init( ntsc, &setup ); } } save_bmp( argc > 2 ? argv [2] : "filtered.bmp" ); free( ntsc ); /* write standard 192-byte NES palette */ { FILE* out = fopen( "nes.pal", "wb" ); if ( out ) { unsigned char palette [nes_ntsc_palette_size * 3]; setup.palette_out = palette; nes_ntsc_init( 0, &setup ); fwrite( palette, 192, 1, out ); } } return 0; } nestopia-1.51.1/source/nes_ntsc/demo_impl.h000066400000000000000000000110731411157722000206550ustar00rootroot00000000000000/* Simple shell used by demos. Uses SDL multimedia library. */ #include #include #include #include "SDL.h" /* Image loader */ typedef struct image_t { unsigned char const* byte_pixels;/* 8-bit pixels */ unsigned short const* rgb_16; /* 16-bit pixels */ int width; int height; int row_width; /* number of pixels to get to next row (may be greater than width) */ } image_t; /* if no palette, loads as 16-bit RGB */ void load_bmp( image_t* out, const char* path, SDL_Color palette [256] ); void save_bmp( const char* path ); void init_window( int width, int height ); int read_input( void ); void lock_pixels( void ); void double_output_height( void ); void display_output( void ); void fatal_error( const char* str ); static unsigned char* output_pixels; /* 16-bit RGB */ static long output_pitch; static float mouse_x, mouse_y; /* -1.0 to 1.0 */ static int mouse_moved; static int key_pressed; /* implementation */ static SDL_Rect rect; static SDL_Surface* screen; static SDL_Surface* surface; static unsigned long next_time; void fatal_error( const char* str ) { fprintf( stderr, "Error: %s\n", str ); exit( EXIT_FAILURE ); } static void init_sdl_( void ) { static int initialized; if ( !initialized ) { if ( SDL_Init( SDL_INIT_VIDEO ) < 0 ) fatal_error( "SDL initialization failed" ); atexit( SDL_Quit ); } } void init_window( int width, int height ) { rect.w = width; rect.h = height; init_sdl_(); screen = SDL_SetVideoMode( width, height, 0, 0 ); surface = SDL_CreateRGBSurface( SDL_SWSURFACE, width, height, 16, 0, 0, 0, 0 ); if ( !screen || !surface ) fatal_error( "SDL initialization failed" ); SDL_WM_SetCaption( "NTSC Filter Demo", "NTSC Filter Demo" ); } int read_input( void ) { SDL_Event e; /* limit to 60 calls per second */ unsigned long start = SDL_GetTicks(); if ( start < next_time && next_time - start > 10 ) SDL_Delay( next_time - start ); while ( SDL_GetTicks() < next_time ) { } next_time = start + 1000 / 60; mouse_moved = 0; key_pressed = 0; while ( SDL_PollEvent( &e ) ) { if ( e.type == SDL_MOUSEBUTTONDOWN || e.type == SDL_QUIT ) return 0; if ( e.type == SDL_KEYDOWN ) { if ( e.key.keysym.sym == SDLK_ESCAPE || e.key.keysym.sym == SDLK_q ) return 0; key_pressed = e.key.keysym.sym; } if ( e.type == SDL_MOUSEMOTION ) { int x, y; SDL_GetMouseState( &x, &y ); mouse_moved = 1; mouse_x = x / (float) (SDL_GetVideoSurface()->w - 1) * 2 - 1; mouse_y = (1 - y / (float) (SDL_GetVideoSurface()->h - 1)) * 2 - 1; } } return 1; } void lock_pixels( void ) { if ( SDL_LockSurface( surface ) < 0 ) fatal_error( "Couldn't lock surface" ); SDL_FillRect( surface, 0, 0 ); output_pitch = surface->pitch; output_pixels = (unsigned char*) surface->pixels; } void double_output_height( void ) { int y; for ( y = surface->h / 2; --y >= 0; ) { unsigned char const* in = output_pixels + y * output_pitch; unsigned char* out = output_pixels + y * 2 * output_pitch; int n; for ( n = surface->w; n; --n ) { unsigned prev = *(unsigned short*) in; unsigned next = *(unsigned short*) (in + output_pitch); /* mix 16-bit rgb without losing low bits */ unsigned mixed = prev + next + ((prev ^ next) & 0x0821); /* darken by 12% */ *(unsigned short*) out = prev; *(unsigned short*) (out + output_pitch) = (mixed >> 1) - (mixed >> 4 & 0x18E3); in += 2; out += 2; } } } void display_output( void ) { SDL_UnlockSurface( surface ); if ( SDL_BlitSurface( surface, &rect, screen, &rect ) < 0 || SDL_Flip( screen ) < 0 ) fatal_error( "SDL blit failed" ); } void load_bmp( image_t* out, const char* path, SDL_Color palette [256] ) { SDL_PixelFormat fmt = { 0 }; /* clear fields */ SDL_Palette pal = { 0 }; SDL_Surface* bmp; SDL_Surface* conv; init_sdl_(); bmp = SDL_LoadBMP( path ); if ( !bmp ) fatal_error( "Couldn't load BMP" ); fmt.BitsPerPixel = 16; fmt.BytesPerPixel = 2; if ( palette ) { pal.ncolors = 256; pal.colors = palette; fmt.palette = &pal; fmt.BitsPerPixel = 8; fmt.BytesPerPixel = 1; } conv = SDL_ConvertSurface( bmp, &fmt, SDL_SWSURFACE ); if ( !conv ) fatal_error( "Couldn't convert BMP" ); SDL_FreeSurface( bmp ); if ( SDL_LockSurface( conv ) < 0 ) fatal_error( "Couldn't lock surface" ); out->byte_pixels = (unsigned char *) conv->pixels; out->rgb_16 = (unsigned short*) conv->pixels; out->width = conv->w; out->height = conv->h; out->row_width = conv->pitch / fmt.BytesPerPixel; } void save_bmp( const char* path ) { if ( SDL_SaveBMP( surface, path ) ) fatal_error( "Couldn't save BMP" ); } nestopia-1.51.1/source/nes_ntsc/license.txt000066400000000000000000000644741411157722000207370ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! nestopia-1.51.1/source/nes_ntsc/nes_ntsc.h000066400000000000000000000177661411157722000205430ustar00rootroot00000000000000/* NES NTSC video filter */ /* nes_ntsc 0.2.2 */ #ifndef NES_NTSC_H #define NES_NTSC_H #include "nes_ntsc_config.h" #ifdef __cplusplus extern "C" { #endif /* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown in parenthesis and should remain fairly stable in future versions. */ typedef struct nes_ntsc_setup_t { /* Basic parameters */ double hue; /* -1 = -180 degrees +1 = +180 degrees */ double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */ double contrast; /* -1 = dark (0.5) +1 = light (1.5) */ double brightness; /* -1 = dark (0.5) +1 = light (1.5) */ double sharpness; /* edge contrast enhancement/blurring */ /* Advanced parameters */ double gamma; /* -1 = dark (1.5) +1 = light (0.5) */ double resolution; /* image resolution */ double artifacts; /* artifacts caused by color changes */ double fringing; /* color artifacts caused by brightness changes */ double bleed; /* color bleed (color resolution reduction) */ int merge_fields; /* if 1, merges even and odd fields together to reduce flicker */ float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */ unsigned char* palette_out; /* optional RGB palette out, 3 bytes per color */ /* You can replace the standard NES color generation with an RGB palette. The first replaces all color generation, while the second replaces only the core 64-color generation and does standard color emphasis calculations on it. */ unsigned char const* palette;/* optional 512-entry RGB palette in, 3 bytes per color */ unsigned char const* base_palette;/* optional 64-entry RGB palette in, 3 bytes per color */ } nes_ntsc_setup_t; /* Video format presets */ extern nes_ntsc_setup_t const nes_ntsc_composite; /* color bleeding + artifacts */ extern nes_ntsc_setup_t const nes_ntsc_svideo; /* color bleeding only */ extern nes_ntsc_setup_t const nes_ntsc_rgb; /* crisp image */ extern nes_ntsc_setup_t const nes_ntsc_monochrome;/* desaturated + artifacts */ #ifdef NES_NTSC_EMPHASIS enum { nes_ntsc_palette_size = 64 * 8 }; #else enum { nes_ntsc_palette_size = 64 }; #endif /* Initializes and adjusts parameters. Can be called multiple times on the same nes_ntsc_t object. Can pass NULL for either parameter. */ typedef struct nes_ntsc_t nes_ntsc_t; void nes_ntsc_init( nes_ntsc_t* ntsc, nes_ntsc_setup_t const* setup ); /* Filters one or more rows of pixels. Input pixels are 6/9-bit palette indicies. In_row_width is the number of pixels to get to the next input row. Out_pitch is the number of *bytes* to get to the next output row. Output pixel format is set by NES_NTSC_OUT_DEPTH (defaults to 16-bit RGB). */ void nes_ntsc_blit( nes_ntsc_t const* ntsc, NES_NTSC_IN_T const* nes_in, long in_row_width, int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch ); /* Number of output pixels written by blitter for given input width. Width might be rounded down slightly; use NES_NTSC_IN_WIDTH() on result to find rounded value. Guaranteed not to round 256 down at all. */ #define NES_NTSC_OUT_WIDTH( in_width ) \ ((((in_width) - 1) / nes_ntsc_in_chunk + 1) * nes_ntsc_out_chunk) /* Number of input pixels that will fit within given output width. Might be rounded down slightly; use NES_NTSC_OUT_WIDTH() on result to find rounded value. */ #define NES_NTSC_IN_WIDTH( out_width ) \ (((out_width) / nes_ntsc_out_chunk - 1) * nes_ntsc_in_chunk + 1) /* Interface for user-defined custom blitters */ enum { nes_ntsc_in_chunk = 3 }; /* number of input pixels read per chunk */ enum { nes_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */ enum { nes_ntsc_black = 15 }; /* palette index for black */ enum { nes_ntsc_burst_count = 3 }; /* burst phase cycles through 0, 1, and 2 */ /* Begins outputting row and starts three pixels. First pixel will be cut off a bit. Use nes_ntsc_black for unused pixels. Declares variables, so must be before first statement in a block (unless you're using C++). */ #define NES_NTSC_BEGIN_ROW( ntsc, burst, pixel0, pixel1, pixel2 ) \ char const* const ktable = \ (char const*) (ntsc)->table [0] + burst * (nes_ntsc_burst_size * sizeof (nes_ntsc_rgb_t));\ NES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, NES_NTSC_ENTRY_, ktable ) /* Begins input pixel */ #define NES_NTSC_COLOR_IN( in_index, color_in ) \ NES_NTSC_COLOR_IN_( in_index, color_in, NES_NTSC_ENTRY_, ktable ) /* Generates output pixel. Bits can be 24, 16, 15, 32 (treated as 24), or 0: 24: RRRRRRRR GGGGGGGG BBBBBBBB (8-8-8 RGB) 16: RRRRRGGG GGGBBBBB (5-6-5 RGB) 15: RRRRRGG GGGBBBBB (5-5-5 RGB) 0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format; x = junk bits) */ #define NES_NTSC_RGB_OUT( index, rgb_out, bits ) \ NES_NTSC_RGB_OUT_14_( index, rgb_out, bits, 0 ) /* private */ enum { nes_ntsc_entry_size = 128 }; typedef unsigned long nes_ntsc_rgb_t; struct nes_ntsc_t { nes_ntsc_rgb_t table [nes_ntsc_palette_size] [nes_ntsc_entry_size]; }; enum { nes_ntsc_burst_size = nes_ntsc_entry_size / nes_ntsc_burst_count }; #define NES_NTSC_ENTRY_( ktable, n ) \ (nes_ntsc_rgb_t const*) (ktable + (n) * (nes_ntsc_entry_size * sizeof (nes_ntsc_rgb_t))) /* deprecated */ #define NES_NTSC_RGB24_OUT( x, out ) NES_NTSC_RGB_OUT( x, out, 24 ) #define NES_NTSC_RGB16_OUT( x, out ) NES_NTSC_RGB_OUT( x, out, 16 ) #define NES_NTSC_RGB15_OUT( x, out ) NES_NTSC_RGB_OUT( x, out, 15 ) #define NES_NTSC_RAW_OUT( x, out ) NES_NTSC_RGB_OUT( x, out, 0 ) enum { nes_ntsc_min_in_width = 256 }; enum { nes_ntsc_min_out_width = NES_NTSC_OUT_WIDTH( nes_ntsc_min_in_width ) }; enum { nes_ntsc_640_in_width = 271 }; enum { nes_ntsc_640_out_width = NES_NTSC_OUT_WIDTH( nes_ntsc_640_in_width ) }; enum { nes_ntsc_640_overscan_left = 8 }; enum { nes_ntsc_640_overscan_right = nes_ntsc_640_in_width - 256 - nes_ntsc_640_overscan_left }; enum { nes_ntsc_full_in_width = 283 }; enum { nes_ntsc_full_out_width = NES_NTSC_OUT_WIDTH( nes_ntsc_full_in_width ) }; enum { nes_ntsc_full_overscan_left = 16 }; enum { nes_ntsc_full_overscan_right = nes_ntsc_full_in_width - 256 - nes_ntsc_full_overscan_left }; /* common 3->7 ntsc macros */ #define NES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, ENTRY, table ) \ unsigned const nes_ntsc_pixel0_ = (pixel0);\ nes_ntsc_rgb_t const* kernel0 = ENTRY( table, nes_ntsc_pixel0_ );\ unsigned const nes_ntsc_pixel1_ = (pixel1);\ nes_ntsc_rgb_t const* kernel1 = ENTRY( table, nes_ntsc_pixel1_ );\ unsigned const nes_ntsc_pixel2_ = (pixel2);\ nes_ntsc_rgb_t const* kernel2 = ENTRY( table, nes_ntsc_pixel2_ );\ nes_ntsc_rgb_t const* kernelx0;\ nes_ntsc_rgb_t const* kernelx1 = kernel0;\ nes_ntsc_rgb_t const* kernelx2 = kernel0 #define NES_NTSC_RGB_OUT_14_( x, rgb_out, bits, shift ) {\ nes_ntsc_rgb_t raw_ =\ kernel0 [x ] + kernel1 [(x+12)%7+14] + kernel2 [(x+10)%7+28] +\ kernelx0 [(x+7)%14] + kernelx1 [(x+ 5)%7+21] + kernelx2 [(x+ 3)%7+35];\ NES_NTSC_CLAMP_( raw_, shift );\ NES_NTSC_RGB_OUT_( rgb_out, bits, shift );\ } /* common ntsc macros */ #define nes_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1)) #define nes_ntsc_clamp_mask (nes_ntsc_rgb_builder * 3 / 2) #define nes_ntsc_clamp_add (nes_ntsc_rgb_builder * 0x101) #define NES_NTSC_CLAMP_( io, shift ) {\ nes_ntsc_rgb_t sub = (io) >> (9-(shift)) & nes_ntsc_clamp_mask;\ nes_ntsc_rgb_t clamp = nes_ntsc_clamp_add - sub;\ io |= clamp;\ clamp -= sub;\ io &= clamp;\ } #define NES_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\ unsigned color_;\ kernelx##index = kernel##index;\ kernel##index = (color_ = (color), ENTRY( table, color_ ));\ } /* x is always zero except in snes_ntsc library */ #define NES_NTSC_RGB_OUT_( rgb_out, bits, x ) {\ if ( bits == 16 )\ rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\ if ( bits == 24 || bits == 32 )\ rgb_out = (raw_>>(5-x)&0xFF0000)|(raw_>>(3-x)&0xFF00)|(raw_>>(1-x)&0xFF);\ if ( bits == 15 )\ rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\ if ( bits == 0 )\ rgb_out = raw_ << x;\ } #ifdef __cplusplus } #endif #endif nestopia-1.51.1/source/nes_ntsc/nes_ntsc.inl000066400000000000000000000215551411157722000210650ustar00rootroot00000000000000/* nes_ntsc 0.2.2. http://www.slack.net/~ant/ */ #include "nes_ntsc.h" /* Copyright (C) 2006-2007 Shay Green. This module is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This module 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this module; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ nes_ntsc_setup_t const nes_ntsc_monochrome = { 0,-1, 0, 0,.2, 0,.2,-.2,-.2,-1, 1, 0, 0, 0, 0 }; nes_ntsc_setup_t const nes_ntsc_composite = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 }; nes_ntsc_setup_t const nes_ntsc_svideo = { 0, 0, 0, 0,.2, 0,.2, -1, -1, 0, 1, 0, 0, 0, 0 }; nes_ntsc_setup_t const nes_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.7, -1, -1,-1, 1, 0, 0, 0, 0 }; #define alignment_count 3 #define burst_count 3 #define rescale_in 8 #define rescale_out 7 #define artifacts_mid 1.0f #define fringing_mid 1.0f #define std_decoder_hue -15 #define STD_HUE_CONDITION( setup ) !(setup->base_palette || setup->palette) #include "nes_ntsc_impl.h" /* 3 input pixels -> 8 composite samples */ pixel_info_t const nes_ntsc_pixels [alignment_count] = { { PIXEL_OFFSET( -4, -9 ), { 1, 1, .6667f, 0 } }, { PIXEL_OFFSET( -2, -7 ), { .3333f, 1, 1, .3333f } }, { PIXEL_OFFSET( 0, -5 ), { 0, .6667f, 1, 1 } }, }; static void merge_kernel_fields( nes_ntsc_rgb_t* io ) { int n; for ( n = burst_size; n; --n ) { nes_ntsc_rgb_t p0 = io [burst_size * 0] + rgb_bias; nes_ntsc_rgb_t p1 = io [burst_size * 1] + rgb_bias; nes_ntsc_rgb_t p2 = io [burst_size * 2] + rgb_bias; /* merge colors without losing precision */ io [burst_size * 0] = ((p0 + p1 - ((p0 ^ p1) & nes_ntsc_rgb_builder)) >> 1) - rgb_bias; io [burst_size * 1] = ((p1 + p2 - ((p1 ^ p2) & nes_ntsc_rgb_builder)) >> 1) - rgb_bias; io [burst_size * 2] = ((p2 + p0 - ((p2 ^ p0) & nes_ntsc_rgb_builder)) >> 1) - rgb_bias; ++io; } } static void correct_errors( nes_ntsc_rgb_t color, nes_ntsc_rgb_t* out ) { int n; for ( n = burst_count; n; --n ) { unsigned i; for ( i = 0; i < rgb_kernel_size / 2; i++ ) { nes_ntsc_rgb_t error = color - out [i ] - out [(i+12)%14+14] - out [(i+10)%14+28] - out [i + 7] - out [i + 5 +14] - out [i + 3 +28]; DISTRIBUTE_ERROR( i+3+28, i+5+14, i+7 ); } out += alignment_count * rgb_kernel_size; } } void nes_ntsc_init( nes_ntsc_t* ntsc, nes_ntsc_setup_t const* setup ) { int merge_fields; int entry; init_t impl; float gamma_factor; if ( !setup ) setup = &nes_ntsc_composite; init( &impl, setup ); /* setup fast gamma */ { float gamma = (float) setup->gamma * -0.5f; if ( STD_HUE_CONDITION( setup ) ) gamma += 0.1333f; gamma_factor = (float) pow( (float) fabs( gamma ), 0.73f ); if ( gamma < 0 ) gamma_factor = -gamma_factor; } merge_fields = setup->merge_fields; if ( setup->artifacts <= -1 && setup->fringing <= -1 ) merge_fields = 1; for ( entry = 0; entry < nes_ntsc_palette_size; entry++ ) { /* Base 64-color generation */ static float const lo_levels [4] = { -0.12f, 0.00f, 0.31f, 0.72f }; static float const hi_levels [4] = { 0.40f, 0.68f, 1.00f, 1.00f }; int level = entry >> 4 & 0x03; float lo = lo_levels [level]; float hi = hi_levels [level]; int color = entry & 0x0F; if ( color == 0 ) lo = hi; if ( color == 0x0D ) hi = lo; if ( color > 0x0D ) hi = lo = 0.0f; { /* phases [i] = cos( i * PI / 6 ) */ static float const phases [0x10 + 3] = { -1.0f, -0.866025f, -0.5f, 0.0f, 0.5f, 0.866025f, 1.0f, 0.866025f, 0.5f, 0.0f, -0.5f, -0.866025f, -1.0f, -0.866025f, -0.5f, 0.0f, 0.5f, 0.866025f, 1.0f }; #define TO_ANGLE_SIN( color ) phases [color] #define TO_ANGLE_COS( color ) phases [(color) + 3] /* Convert raw waveform to YIQ */ float sat = (hi - lo) * 0.5f; float i = TO_ANGLE_SIN( color ) * sat; float q = TO_ANGLE_COS( color ) * sat; float y = (hi + lo) * 0.5f; /* Optionally use base palette instead */ if ( setup->base_palette ) { unsigned char const* in = &setup->base_palette [(entry & 0x3F) * 3]; static float const to_float = 1.0f / 0xFF; float r = to_float * in [0]; float g = to_float * in [1]; float b = to_float * in [2]; q = RGB_TO_YIQ( r, g, b, y, i ); } /* Apply color emphasis */ #ifdef NES_NTSC_EMPHASIS { int tint = entry >> 6 & 7; if ( tint && color <= 0x0D ) { static float const atten_mul = 0.79399f; static float const atten_sub = 0.0782838f; if ( tint == 7 ) { y = y * (atten_mul * 1.13f) - (atten_sub * 1.13f); } else { static unsigned char const tints [8] = { 0, 6, 10, 8, 2, 4, 0, 0 }; int const tint_color = tints [tint]; float sat = hi * (0.5f - atten_mul * 0.5f) + atten_sub * 0.5f; y -= sat * 0.5f; if ( tint >= 3 && tint != 4 ) { /* combined tint bits */ sat *= 0.6f; y -= sat; } i += TO_ANGLE_SIN( tint_color ) * sat; q += TO_ANGLE_COS( tint_color ) * sat; } } } #endif /* Optionally use palette instead */ if ( setup->palette ) { unsigned char const* in = &setup->palette [entry * 3]; static float const to_float = 1.0f / 0xFF; float r = to_float * in [0]; float g = to_float * in [1]; float b = to_float * in [2]; q = RGB_TO_YIQ( r, g, b, y, i ); } /* Apply brightness, contrast, and gamma */ y *= (float) setup->contrast * 0.5f + 1; /* adjustment reduces error when using input palette */ y += (float) setup->brightness * 0.5f - 0.5f / 256; { float r, g, b = YIQ_TO_RGB( y, i, q, default_decoder, float, r, g ); /* fast approximation of n = pow( n, gamma ) */ r = (r * gamma_factor - gamma_factor) * r + r; g = (g * gamma_factor - gamma_factor) * g + g; b = (b * gamma_factor - gamma_factor) * b + b; q = RGB_TO_YIQ( r, g, b, y, i ); } i *= rgb_unit; q *= rgb_unit; y *= rgb_unit; y += rgb_offset; /* Generate kernel */ { int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g ); /* blue tends to overflow, so clamp it */ nes_ntsc_rgb_t rgb = PACK_RGB( r, g, (b < 0x3E0 ? b: 0x3E0) ); if ( setup->palette_out ) RGB_PALETTE_OUT( rgb, &setup->palette_out [entry * 3] ); if ( ntsc ) { nes_ntsc_rgb_t* kernel = ntsc->table [entry]; gen_kernel( &impl, y, i, q, kernel ); if ( merge_fields ) merge_kernel_fields( kernel ); correct_errors( rgb, kernel ); } } } } } #ifndef NES_NTSC_NO_BLITTERS void nes_ntsc_blit( nes_ntsc_t const* ntsc, NES_NTSC_IN_T const* input, long in_row_width, int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch ) { int chunk_count = (in_width - 1) / nes_ntsc_in_chunk; for ( ; in_height; --in_height ) { NES_NTSC_IN_T const* line_in = input; NES_NTSC_BEGIN_ROW( ntsc, burst_phase, nes_ntsc_black, nes_ntsc_black, NES_NTSC_ADJ_IN( *line_in ) ); nes_ntsc_out_t* restrict line_out = (nes_ntsc_out_t*) rgb_out; int n; ++line_in; for ( n = chunk_count; n; --n ) { /* order of input and output pixels must not be altered */ NES_NTSC_COLOR_IN( 0, NES_NTSC_ADJ_IN( line_in [0] ) ); NES_NTSC_RGB_OUT( 0, line_out [0], NES_NTSC_OUT_DEPTH ); NES_NTSC_RGB_OUT( 1, line_out [1], NES_NTSC_OUT_DEPTH ); NES_NTSC_COLOR_IN( 1, NES_NTSC_ADJ_IN( line_in [1] ) ); NES_NTSC_RGB_OUT( 2, line_out [2], NES_NTSC_OUT_DEPTH ); NES_NTSC_RGB_OUT( 3, line_out [3], NES_NTSC_OUT_DEPTH ); NES_NTSC_COLOR_IN( 2, NES_NTSC_ADJ_IN( line_in [2] ) ); NES_NTSC_RGB_OUT( 4, line_out [4], NES_NTSC_OUT_DEPTH ); NES_NTSC_RGB_OUT( 5, line_out [5], NES_NTSC_OUT_DEPTH ); NES_NTSC_RGB_OUT( 6, line_out [6], NES_NTSC_OUT_DEPTH ); line_in += 3; line_out += 7; } /* finish final pixels */ NES_NTSC_COLOR_IN( 0, nes_ntsc_black ); NES_NTSC_RGB_OUT( 0, line_out [0], NES_NTSC_OUT_DEPTH ); NES_NTSC_RGB_OUT( 1, line_out [1], NES_NTSC_OUT_DEPTH ); NES_NTSC_COLOR_IN( 1, nes_ntsc_black ); NES_NTSC_RGB_OUT( 2, line_out [2], NES_NTSC_OUT_DEPTH ); NES_NTSC_RGB_OUT( 3, line_out [3], NES_NTSC_OUT_DEPTH ); NES_NTSC_COLOR_IN( 2, nes_ntsc_black ); NES_NTSC_RGB_OUT( 4, line_out [4], NES_NTSC_OUT_DEPTH ); NES_NTSC_RGB_OUT( 5, line_out [5], NES_NTSC_OUT_DEPTH ); NES_NTSC_RGB_OUT( 6, line_out [6], NES_NTSC_OUT_DEPTH ); burst_phase = (burst_phase + 1) % nes_ntsc_burst_count; input += in_row_width; rgb_out = (char*) rgb_out + out_pitch; } } #endif nestopia-1.51.1/source/nes_ntsc/nes_ntsc.txt000066400000000000000000000241441411157722000211170ustar00rootroot00000000000000nes_ntsc 0.2.2: NES NTSC Video Filter ------------------------------------- Author : Shay Green Website : http://www.slack.net/~ant/ Forum : http://groups.google.com/group/blargg-sound-libs License : GNU Lesser General Public License (LGPL) Language: C or C++ Overview -------- To perform NTSC filtering, first allocate memory for a nes_ntsc_t object and call nes_ntsc_init(), then call nes_ntsc_blit() to perform filtering. You can call nes_ntsc_init() at any time to change image parameters. nes_ntsc_blit() reads NES pixels and writes RGB pixels (16-bit by default). The NES pixels are 6-bit raw palette values (0 to 0x3F). Edit nes_ntsc_config.h to change this. Color Emphasis Support ---------------------- Support for the three color emphasis bits in PPU register $2001 can be enabled in nes_ntsc_config.h. By default, support is disabled and a 64-color palette is used. If enabled, a 512-color palette is used and the three color emphasis bits from PPU $2001 are stored in bits 6-8 (bit mask 0x1C0) of the input pixels to the blitter. Form the index as follows: index = (ppu_2001 << 1 & 0x1C0) | (palette_index & 0x3F). RGB Palettes ------------ An RGB palette can be generated for use in a normal blitter. If color emphasis is disabled, it's 64 colors (192 bytes); if enabled, it's 512 colors (1536 bytes). In your nes_ntsc_setup_t structure, point palette_out to a buffer to hold the palette, then call nes_ntsc_init(). If you only need the palette and aren't going to be using the NTSC filter, pass 0 for the first parameter. A custom source RGB palette can also be used to replace the standard NES color generation hardware. See the palette and base_palette members of nes_ntsc_setup_t in nes_ntsc.h for more. Image Parameters ---------------- Many image parameters can be adjusted and presets are provided for composite video, S-video, RGB, and monochrome. Most are floating-point values with a general range of -1.0 to 1.0, where 0 is normal. The ranges are adjusted so that one parameter at an extreme (-1 or +1) and the rest at zero shouldn't result in any internal overflow (garbage pixels). Setting multiple parameters to their extreme can produce garbage. Put another way, the state space defined by all parameters within the range -1 to +1 is not fully usable, but some extreme corners are very useful so I don't want to reduce the parameter ranges. The sharpness and resolution parameters have similar effects. Resolution affects how crisp pixels are. Sharpness merely enhances the edges by increasing contrast, which makes things brighter at the edges. Artifacts sets how much "junk" is around the edges where colors and brightness change in the image, where -1 completely eliminates them. (Color) bleed affects how much colors blend together and the artifact colors at the edges of pixels surrounded by black. (Color) fringing affects how much color fringing occurs around the edges of bright objects, especially white text on a black background. When using custom settings, initialize your nes_ntsc_setup_t using one of the standard setups before customizing it. This will ensure that all fields are properly initialized, including any added in future releases of the library that your current code can't even know about. nes_ntsc_setup_t setup; setup = nes_ntsc_composite; /* do this first */ setup.sharpness = custom_sharpness; nes_ntsc_init( ntsc, &setup ); Image Size ---------- For proper aspect ratio, the image generated by the library must be doubled vertically. Use the NES_NTSC_OUT_WIDTH() and NES_NTSC_IN_WIDTH() macros to convert between input and output widths that the blitter uses. For example, if you are blitting an image 256 pixels wide, use NES_NTSC_OUT_WIDTH( 256 ) to find out how many output pixels are written per row. Another example, use NES_NTSC_IN_WIDTH( 640 ) to find how many input pixels will fit within 640 output pixels. The blitter rounds the input width down in some cases, so the requested width might not be possible. Use NES_NTSC_IN_WIDTH( NES_NTSC_OUT_WIDTH( in_width ) ) to find what a given in_width would be rounded down to. Burst Phase ----------- The burst_phase parameter to nes_ntsc_blit() should generally toggle values between frames, i.e. 0 on first call to nes_ntsc_blit(), 1 on second call, 0 on third call, 1 on fourth, etc. If merge_fields is enabled (see below), you should always pass 0. Read further for more detailed operation. If you're using nes_ntsc_blit() to do partial screen updates, burst_phase should be calculated as (burst_phase + row) % 3, where row is the starting row (0 through 239). For example, if burst_phase is 1 for the current frame and you make two calls to nes_ntsc_blit() to blit rows 0 to 100, then rows 101 to 239, for the first call you should pass 1 for burst_phase, and for the second call you should pass 0 for burst_phase: (1 + 101) % 3 = 0. Do the same regardless of the merge_fields setting. For more accurate burst_phase operation, it should be adjusted at the beginning of a frame based on the length of scanline 20: if 341 clocks (normal), burst_phase = (burst_phase + 1) % 3, otherwise burst_phase = (burst_phase + 2) % 3 (for shorter 340 clock scanline). The included test ROMs verify proper burst_phase implementation. They must pass in order; an earlier failing test means that later tests will give meaningless results. The first two tests will pass with either method of burst_phase handling described above; the third will only pass with the more accurate handling. The tests flash sets of dots quickly with the dot color being the only important aspect. 1.line_phase.nes - Tests for proper burst_phase on each scanline. All dots on screen should be the same color. 2.frame_phase.nes - Tests for proper burst_phase toggling between frames. Each row of dots should alternate between the same two colors (if merge_fields is set to 1, they should all be the same color). 3.special_frame_phase.nes - Tests for proper burst_phase incrementing between frames when $2001 rendering is enabled late in the frame. Each rectangle of dots should be one color, and there should be three different colors of rectangles (if merge_fields is set to 1, each rectangle should be made of three colors of dots). There is a visual glitch near the top of the screen for the first line of dots; this is unrelated the test and should be ignored. Flickering ---------- The displayed image toggles between two different pixel artifact patterns at a steady rate, making it appear stable. For an emulator to duplicate this effect, its frame rate must match the host monitor's refresh rate, it must be synchronizing to the refresh (vsync), and it must not be skipping any frames. If any of these don't hold, the image will probably flicker much more than it would on a TV. It is important that you play around with these factors to get a good feel for the issue, and document it clearly for end-users, otherwise they will have difficulty getting an authentic image. The library includes a partial workaround for this issue, for the cases where all the conditions can't be met. When merge_fields is set to 1, nes_ntsc_blit() does the equivalent of blitting the image twice with the two different phases and then mixes them together, but without any performance impact. The result is similar to what you'd see if the monitor's refresh rate were the same as the emulator's. It does reduce the shimmer effect when scrolling, so it's not a complete solution to the refresh rate issue. The merge_fields option is also useful when taking a screenshot. If you capture without merge_fields set to 1, you'll only get the even or odd artifacts, which will make the image look more grainy than when the emulator is running. Again, play around with this to get an idea of the difference. It might be best to simply allow the user to choose when to enable this option. Note that when you have merge_fields set to 1, you should always pass 0 for the burst_phase parameter to nes_ntsc_blit() (unless doing partial screen updates). If you don't, you'll still get some flicker. Custom Blitter -------------- You can write your own blitter, allowing customization of how input pixels are obtained, the format of output pixels (15, 16, or 32-bit RGB), optimizations for your platform, and additional effects like efficient scanline doubling during blitting. Macros are included in nes_ntsc.h for writing your blitter so that your code can be carried over without changes to improved versions of the library. The default blitter at the end of nes_ntsc.c shows how to use the macros. Contact me for further assistance. The NES_NTSC_BEGIN_ROW macro allows starting up to three pixels. The first pixel is cut off; its use is in specifying a background color other than black for the sliver on the left edge. The next two pixels can be used to handle the extra one or two pixels not handled by the main chunks of three pixels. For example if you want to blit 257 input pixels on a row (for whatever odd reason), you would start the first two with NES_NTSC_BEGIN_ROW( ... nes_ntsc_black, line_in [0], line_in [1] ), then do the remaining 255 in chunks of three (255 is divisible by 3). Limitations ----------- The library's horizontal rescaling is too wide by about 3% in order to allow a much more optimal implementation. This means that a 256 pixel wide input image should appear as 581 output pixels, but with this library appears as 602 output pixels. TV aspect ratios probably vary by this much anyway. If you really need unscaled output, contact me and I'll see about adding it. Thanks ------ Thanks to NewRisingSun for his original code and explanations of NTSC, which was a starting point for me learning about NTSC video and decoding. Thanks to the Nesdev forum for feedback and encouragement. Thanks to Martin Freij (Nestopia author) and Charles MacDonald (SMS Plus author) for significant ongoing testing and feedback as the library has improved. Thanks to byuu (bsnes author) and pagefault (ZSNES team) for feedback about the SNES version. -- Shay Green nestopia-1.51.1/source/nes_ntsc/nes_ntsc_config.h000066400000000000000000000015561411157722000220560ustar00rootroot00000000000000/* Configure library by modifying this file */ #ifndef NES_NTSC_CONFIG_H #define NES_NTSC_CONFIG_H /* Uncomment to enable emphasis support and use a 512 color palette instead of the base 64 color palette. */ #define NES_NTSC_EMPHASIS 1 /* The following affect the built-in blitter only; a custom blitter can handle things however it wants. */ /* Bits per pixel of output. Can be 15, 16, 32, or 24 (same as 32). */ #define NES_NTSC_OUT_DEPTH 16 /* Type of input pixel values. You'll probably use unsigned short if you enable emphasis above. */ #define NES_NTSC_IN_T unsigned char /* Each raw pixel input value is passed through this. You might want to mask the pixel index if you use the high bits as flags, etc. */ #define NES_NTSC_ADJ_IN( in ) in /* For each pixel, this is the basic operation: output_color = color_palette [NES_NTSC_ADJ_IN( NES_NTSC_IN_T )] */ #endif nestopia-1.51.1/source/nes_ntsc/nes_ntsc_impl.h000066400000000000000000000300271411157722000215450ustar00rootroot00000000000000/* nes_ntsc 0.2.2. http://www.slack.net/~ant/ */ /* Common implementation of NTSC filters */ #include #include /* Copyright (C) 2006 Shay Green. This module is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This module 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this module; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #define DISABLE_CORRECTION 0 #undef PI #define PI 3.14159265358979323846f #ifndef LUMA_CUTOFF #define LUMA_CUTOFF 0.20 #endif #ifndef gamma_size #define gamma_size 1 #endif #ifndef rgb_bits #define rgb_bits 8 #endif #ifndef artifacts_max #define artifacts_max (artifacts_mid * 1.5f) #endif #ifndef fringing_max #define fringing_max (fringing_mid * 2) #endif #ifndef STD_HUE_CONDITION #define STD_HUE_CONDITION( setup ) 1 #endif #define ext_decoder_hue (std_decoder_hue + 15) #define rgb_unit (1 << rgb_bits) #define rgb_offset (rgb_unit * 2 + 0.5f) enum { burst_size = nes_ntsc_entry_size / burst_count }; enum { kernel_half = 16 }; enum { kernel_size = kernel_half * 2 + 1 }; typedef struct init_t { float to_rgb [burst_count * 6]; float to_float [gamma_size]; float contrast; float brightness; float artifacts; float fringing; float kernel [rescale_out * kernel_size * 2]; } init_t; #define ROTATE_IQ( i, q, sin_b, cos_b ) {\ float t;\ t = i * cos_b - q * sin_b;\ q = i * sin_b + q * cos_b;\ i = t;\ } static void init_filters( init_t* impl, nes_ntsc_setup_t const* setup ) { #if rescale_out > 1 float kernels [kernel_size * 2]; #else float* const kernels = impl->kernel; #endif /* generate luma (y) filter using sinc kernel */ { /* sinc with rolloff (dsf) */ float const rolloff = 1 + (float) setup->sharpness * (float) 0.032; float const maxh = 32; float const pow_a_n = (float) pow( rolloff, maxh ); float sum; int i; /* quadratic mapping to reduce negative (blurring) range */ float to_angle = (float) setup->resolution + 1; to_angle = PI / maxh * (float) LUMA_CUTOFF * (to_angle * to_angle + 1); kernels [kernel_size * 3 / 2] = maxh; /* default center value */ for ( i = 0; i < kernel_half * 2 + 1; i++ ) { int x = i - kernel_half; float angle = x * to_angle; /* instability occurs at center point with rolloff very close to 1.0 */ if ( x || pow_a_n > (float) 1.056 || pow_a_n < (float) 0.981 ) { float rolloff_cos_a = rolloff * (float) cos( angle ); float num = 1 - rolloff_cos_a - pow_a_n * (float) cos( maxh * angle ) + pow_a_n * rolloff * (float) cos( (maxh - 1) * angle ); float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff; float dsf = num / den; kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - (float) 0.5; } } /* apply blackman window and find sum */ sum = 0; for ( i = 0; i < kernel_half * 2 + 1; i++ ) { float x = PI * 2 / (kernel_half * 2) * i; float blackman = 0.42f - 0.5f * (float) cos( x ) + 0.08f * (float) cos( x * 2 ); sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman); } /* normalize kernel */ sum = 1.0f / sum; for ( i = 0; i < kernel_half * 2 + 1; i++ ) { int x = kernel_size * 3 / 2 - kernel_half + i; kernels [x] *= sum; assert( kernels [x] == kernels [x] ); /* catch numerical instability */ } } /* generate chroma (iq) filter using gaussian kernel */ { float const cutoff_factor = -0.03125f; float cutoff = (float) setup->bleed; int i; if ( cutoff < 0 ) { /* keep extreme value accessible only near upper end of scale (1.0) */ cutoff *= cutoff; cutoff *= cutoff; cutoff *= cutoff; cutoff *= -30.0f / 0.65f; } cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff; for ( i = -kernel_half; i <= kernel_half; i++ ) kernels [kernel_size / 2 + i] = (float) exp( i * i * cutoff ); /* normalize even and odd phases separately */ for ( i = 0; i < 2; i++ ) { float sum = 0; int x; for ( x = i; x < kernel_size; x += 2 ) sum += kernels [x]; sum = 1.0f / sum; for ( x = i; x < kernel_size; x += 2 ) { kernels [x] *= sum; assert( kernels [x] == kernels [x] ); /* catch numerical instability */ } } } /* printf( "luma:\n" ); for ( i = kernel_size; i < kernel_size * 2; i++ ) printf( "%f\n", kernels [i] ); printf( "chroma:\n" ); for ( i = 0; i < kernel_size; i++ ) printf( "%f\n", kernels [i] ); */ /* generate linear rescale kernels */ #if rescale_out > 1 { float weight = 1.0f; float* out = impl->kernel; int n = rescale_out; do { float remain = 0; int i; weight -= 1.0f / rescale_in; for ( i = 0; i < kernel_size * 2; i++ ) { float cur = kernels [i]; float m = cur * weight; *out++ = m + remain; remain = cur - m; } } while ( --n ); } #endif } static float const default_decoder [6] = { 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f }; static void init( init_t* impl, nes_ntsc_setup_t const* setup ) { impl->brightness = (float) setup->brightness * (0.5f * rgb_unit) + rgb_offset; impl->contrast = (float) setup->contrast * (0.5f * rgb_unit) + rgb_unit; #ifdef default_palette_contrast if ( !setup->palette ) impl->contrast *= default_palette_contrast; #endif impl->artifacts = (float) setup->artifacts; if ( impl->artifacts > 0 ) impl->artifacts *= artifacts_max - artifacts_mid; impl->artifacts = impl->artifacts * artifacts_mid + artifacts_mid; impl->fringing = (float) setup->fringing; if ( impl->fringing > 0 ) impl->fringing *= fringing_max - fringing_mid; impl->fringing = impl->fringing * fringing_mid + fringing_mid; init_filters( impl, setup ); /* generate gamma table */ if ( gamma_size > 1 ) { float const to_float = 1.0f / (gamma_size - (gamma_size > 1)); float const gamma = 1.1333f - (float) setup->gamma * 0.5f; /* match common PC's 2.2 gamma to TV's 2.65 gamma */ int i; for ( i = 0; i < gamma_size; i++ ) impl->to_float [i] = (float) pow( i * to_float, gamma ) * impl->contrast + impl->brightness; } /* setup decoder matricies */ { float hue = (float) setup->hue * PI + PI / 180 * ext_decoder_hue; float sat = (float) setup->saturation + 1; float const* decoder = setup->decoder_matrix; if ( !decoder ) { decoder = default_decoder; if ( STD_HUE_CONDITION( setup ) ) hue += PI / 180 * (std_decoder_hue - ext_decoder_hue); } { float s = (float) sin( hue ) * sat; float c = (float) cos( hue ) * sat; float* out = impl->to_rgb; int n; n = burst_count; do { float const* in = decoder; int n = 3; do { float i = *in++; float q = *in++; *out++ = i * c - q * s; *out++ = i * s + q * c; } while ( --n ); if ( burst_count <= 1 ) break; ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */ } while ( --n ); } } } /* kernel generation */ #define RGB_TO_YIQ( r, g, b, y, i ) (\ (y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\ (i = (r) * 0.596f - (g) * 0.275f - (b) * 0.321f),\ ((r) * 0.212f - (g) * 0.523f + (b) * 0.311f)\ ) #define YIQ_TO_RGB( y, i, q, to_rgb, type, r, g ) (\ r = (type) (y + to_rgb [0] * i + to_rgb [1] * q),\ g = (type) (y + to_rgb [2] * i + to_rgb [3] * q),\ (type) (y + to_rgb [4] * i + to_rgb [5] * q)\ ) #define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1) enum { rgb_kernel_size = burst_size / alignment_count }; enum { rgb_bias = rgb_unit * 2 * nes_ntsc_rgb_builder }; typedef struct pixel_info_t { int offset; float negate; float kernel [4]; } pixel_info_t; #if rescale_in > 1 #define PIXEL_OFFSET_( ntsc, scaled ) \ (kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \ (kernel_size * 2 * scaled)) #define PIXEL_OFFSET( ntsc, scaled ) \ PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\ (((scaled) + rescale_out * 10) % rescale_out) ),\ (1.0f - (((ntsc) + 100) & 2)) #else #define PIXEL_OFFSET( ntsc, scaled ) \ (kernel_size / 2 + (ntsc) - (scaled)),\ (1.0f - (((ntsc) + 100) & 2)) #endif extern pixel_info_t const nes_ntsc_pixels [alignment_count]; /* Generate pixel at all burst phases and column alignments */ static void gen_kernel( init_t* impl, float y, float i, float q, nes_ntsc_rgb_t* out ) { /* generate for each scanline burst phase */ float const* to_rgb = impl->to_rgb; int burst_remain = burst_count; y -= rgb_offset; do { /* Encode yiq into *two* composite signals (to allow control over artifacting). Convolve these with kernels which: filter respective components, apply sharpening, and rescale horizontally. Convert resulting yiq to rgb and pack into integer. Based on algorithm by NewRisingSun. */ pixel_info_t const* pixel = nes_ntsc_pixels; int alignment_remain = alignment_count; do { /* negate is -1 when composite starts at odd multiple of 2 */ float const yy = y * impl->fringing * pixel->negate; float const ic0 = (i + yy) * pixel->kernel [0]; float const qc1 = (q + yy) * pixel->kernel [1]; float const ic2 = (i - yy) * pixel->kernel [2]; float const qc3 = (q - yy) * pixel->kernel [3]; float const factor = impl->artifacts * pixel->negate; float const ii = i * factor; float const yc0 = (y + ii) * pixel->kernel [0]; float const yc2 = (y - ii) * pixel->kernel [2]; float const qq = q * factor; float const yc1 = (y + qq) * pixel->kernel [1]; float const yc3 = (y - qq) * pixel->kernel [3]; float const* k = &impl->kernel [pixel->offset]; int n; ++pixel; for ( n = rgb_kernel_size; n; --n ) { float i = k[0]*ic0 + k[2]*ic2; float q = k[1]*qc1 + k[3]*qc3; float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 + k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset; if ( rescale_out <= 1 ) k--; else if ( k < &impl->kernel [kernel_size * 2 * (rescale_out - 1)] ) k += kernel_size * 2 - 1; else k -= kernel_size * 2 * (rescale_out - 1) + 2; { int r, g, b = YIQ_TO_RGB( y, i, q, to_rgb, int, r, g ); *out++ = PACK_RGB( r, g, b ) - rgb_bias; } } } while ( alignment_count > 1 && --alignment_remain ); if ( burst_count <= 1 ) break; to_rgb += 6; ROTATE_IQ( i, q, -0.866025f, -0.5f ); /* -120 degrees */ } while ( --burst_remain ); } static void correct_errors( nes_ntsc_rgb_t color, nes_ntsc_rgb_t* out ); #if DISABLE_CORRECTION #define CORRECT_ERROR( a ) { out [i] += rgb_bias; } #define DISTRIBUTE_ERROR( a, b, c ) { out [i] += rgb_bias; } #else #define CORRECT_ERROR( a ) { out [a] += error; } #define DISTRIBUTE_ERROR( a, b, c ) {\ nes_ntsc_rgb_t fourth = (error + 2 * nes_ntsc_rgb_builder) >> 2;\ fourth &= (rgb_bias >> 1) - nes_ntsc_rgb_builder;\ fourth -= rgb_bias >> 2;\ out [a] += fourth;\ out [b] += fourth;\ out [c] += fourth;\ out [i] += error - (fourth * 3);\ } #endif #define RGB_PALETTE_OUT( rgb, out_ )\ {\ unsigned char* out = (out_);\ nes_ntsc_rgb_t clamped = (rgb);\ NES_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\ out [0] = (unsigned char) (clamped >> 21);\ out [1] = (unsigned char) (clamped >> 11);\ out [2] = (unsigned char) (clamped >> 1);\ } /* blitter related */ #ifndef restrict #if defined (__GNUC__) #define restrict __restrict__ #elif defined (_MSC_VER) && _MSC_VER > 1300 #define restrict __restrict #else /* no support for restricted pointers */ #define restrict #endif #endif #include #if NES_NTSC_OUT_DEPTH <= 16 #if USHRT_MAX == 0xFFFF typedef unsigned short nes_ntsc_out_t; #else #error "Need 16-bit int type" #endif #else #if UINT_MAX == 0xFFFFFFFF typedef unsigned int nes_ntsc_out_t; #elif ULONG_MAX == 0xFFFFFFFF typedef unsigned long nes_ntsc_out_t; #else #error "Need 32-bit int type" #endif #endif nestopia-1.51.1/source/nes_ntsc/readme.txt000066400000000000000000000047751411157722000205500ustar00rootroot00000000000000nes_ntsc 0.2.2: NES NTSC Video Filter ------------------------------------- This library filters a NES image to match what a TV would show, allowing an authentic image in an emulator. It uses a highly optimized algorithm to perform the same signal processing as an NTSC decoder in a TV, giving very similar pixel artifacts and color bleeding. The usual picture controls can be adjusted: hue, saturation, contrast, brightness, and sharpness. Additionally, the amount of NTSC chroma and luma artifacts can be reduced, allowing an image that corresponds to composite video (artifacts), S-video (color bleeding only), RGB (clean pixels), or anywhere inbetween. The output is scaled to the proper horizontal width, leaving it up the emulator to simply double the height. An optional even/odd field merging feature is provided to reduce flicker when the host display's refresh rate isn't 60 Hz. Specialized blitters can be easily written using a special interface, allowing customization of input and output pixel formats, optimization for the host platform, and efficient scanline doubling. Blitting a 256x240 source image to a 602x240 pixel 16-bit RGB memory buffer at 60 frames per second uses 8% CPU on a 2.0 GHz Athlon 3500+ and 40% CPU on a 10-year-old 400 MHz G3 PowerMac. Author : Shay Green Website : http://www.slack.net/~ant/ Forum : http://groups.google.com/group/blargg-sound-libs License : GNU Lesser General Public License (LGPL) Language: C or C++ Getting Started --------------- Build a program from demo.c, nes_ntsc.c, and the SDL multimedia library (see http://libsdl.org/). Run it with "test.bmp" in the same directory and it should show the filtered image. See demo.c for more. See nes_ntsc.txt for documentation and nes_ntsc.h for reference. Post to the discussion forum for assistance. Files ----- readme.txt Essential information nes_ntsc.txt Library documentation changes.txt Changes made since previous releases license.txt GNU Lesser General Public License benchmark.c Measures frame rate and processor usage of library demo.c Displays and saves NTSC filtered image demo_impl.h Internal routines used by demo test.bmp Test image for demo tests/ Test ROMs to verify burst phase operation nes_ntsc_config.h Library configuration (modify as needed) nes_ntsc.h Library header and source nes_ntsc.c nes_ntsc_impl.h -- Shay Green nestopia-1.51.1/source/nes_ntsc/test.bmp000066400000000000000000001720661411157722000202300ustar00rootroot00000000000000BM6ô6(ððfffˆ*¨¤;~\@nlW54I RON@®®®Ú_þ@Bÿ'vÍ¡|¸ 2µO™nl‡8” 2Ž|þþþþ°dþ“þwÇþjóÍnþp‚þ#Ÿë¿½Ù‰0å]‚áEßÎHOOOþþþþàÁþÓÔþÈéþÃûëÅþÆÍþ¦Ù÷•æå—ðЫõ¾Íó´ó쵸¸¸%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'''''''%%''77'''%''''7''%'''7777''%''77'''%77'''%%77'''%%%%'''%%''''77'77777777777''''''''7%%%%%%%'''''7%%%%%%%'''''777'7777%%%'7'%7777%%777%%%777%%%%77%%%%%%%7777%%%%%%%%%%%%%77%%%%%%%%%%%%777777777777770000000000000000000000&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&7770000000000000000000000000&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&777000000000000000000000000000&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&770000000000000000000000000000000000000000000000&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&777777777000000000000000000000000000000000000000&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&7700000000000000000000000000000&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&777770000000000000000000000000000000000777000000000000000777777700000000000000000000000000000007000000000000000000000000000007000000000000000000000000000000007770000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000nestopia-1.51.1/source/nes_ntsc/tests/000077500000000000000000000000001411157722000176775ustar00rootroot00000000000000nestopia-1.51.1/source/nes_ntsc/tests/1.line_phase.nes000066400000000000000000000400201411157722000226500ustar00rootroot00000000000000NESÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ,@@ `ã© iã ¹bà ÈÀ@Ðõ`©? iã ¹Bà ÈÀ Ðõ` `ã©  à à uã`0’’’’’’ -à `ã`©€ ¥Åðü`æ@ ‚à© iã  ¢ © ©  ÊÐðˆÐë©…©…©d… `ã©    ©  LÃã `ãH­ó îò­ò ©  h `H­ò)ài!ò­óióh`©ò© ó `ã©  ©? iã©¢0  Ž Ž Ž ˆÐñ© i㩈…ð©á…ñ ©;…ò¢© ÊÐú¢±ðÈ ÊÐ÷˜ÐæñÆòÐâ© wã `ã©  ©  `(((((þ(þ((|Ð|üD D0HP TH4 T88T|0<8LÎÆæd88~|Æ`ÀüÆÆ|þÆ 000|ÆÆ|ÆÆ||ÆÆ~ x0 @ <<8D8Dšª”@<8lÆÆþÆÆüÆÆüÆÆüÆÆÆþÆÆÆ~~ÆÆ|ÆÌØðøÜÎ``````~ÆîþþÖÆÆÆæöþÞÎÆ|ÆÆÆÆÆ|üÆÆÆüÀÀ|ÆÆÆÞÌzüÆÆÎøÜÎxÌÀ|Æ|~ÆÆÆÆÆÆ|ÆÆÆî|8ÆÆÖþþîÆÆî|8|îÆfff<þ8pàþ, , û`,  © `©H© iãh¢ð    ÊÐñ©¢@ ÊÐú`H©¥ÍñðñŠH˜H áh¨hªhLÜà üàLüàLßà©ñ`x© ½ãLÏãLÏãÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ•à˜àànestopia-1.51.1/source/nes_ntsc/tests/2.frame_phase.nes000066400000000000000000000400201411157722000230140ustar00rootroot00000000000000NESÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ,@@ Nä© Wä ¹bà ÈÀ@Ðõ`©? Wä ¹Bà ÈÀ Ðõ` Nä©  à à cä`0’’’’’’ -à Nä`©€ ¥Åðü`æ@ ‚à© Wä  ¢ © ©  ÊÐð¢B ÊÐúˆÐã©…©…©d… Nä©    ©  ©…©d… ‰à¥Iô… © Æ LQáL±ä NäH­ó îò­ò ©  h `H­ò)ài!ò­óióh`©ò© ó Nä©  ©? Wä©¢0  Ž Ž Ž ˆÐñ© Wä©v…ð©â…ñ ©;…ò¢© ÊÐú¢±ðÈ ÊÐ÷˜ÐæñÆòÐâ© eä Nä©  ©  `(((((þ(þ((|Ð|üD D0HP TH4 T88T|0<8LÎÆæd88~|Æ`ÀüÆÆ|þÆ 000|ÆÆ|ÆÆ||ÆÆ~ x0 @ <<8D8Dšª”@<8lÆÆþÆÆüÆÆüÆÆüÆÆÆþÆÆÆ~~ÆÆ|ÆÌØðøÜÎ``````~ÆîþþÖÆÆÆæöþÞÎÆ|ÆÆÆÆÆ|üÆÆÆüÀÀ|ÆÆÆÞÌzüÆÆÎøÜÎxÌÀ|Æ|~ÆÆÆÆÆÆ|ÆÆÆî|8ÆÆÖþþîÆÆî|8|îÆfff<þ8pàþ, , û`,  © `©H© Wäh¢ð    ÊÐñ©¢@ ÊÐú`H©¥ÍñðñŠH˜H âh¨hªhLjá ŠáLŠáLmá©ñ`x© «äL½äL½äÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ•àáànestopia-1.51.1/source/nes_ntsc/tests/3.special_frame_phase.nes000066400000000000000000000400201411157722000245150ustar00rootroot00000000000000NESÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ,@@ Nä© Wä ¹bà ÈÀ@Ðõ`©? Wä ¹Bà ÈÀ Ðõ` Nä©  à à cä`0’’’’’’ -à Nä`©€ ¥Åðü`æ@ ‚à© Wä ¢© ©   ÊÐí¢  ÊÐúˆÐà©…©…©d… Nä©    ©  ©…©…©d… ‰à© ©  ¦Ê¢†½á ©  © á© Æ LXáL±äøð¢¢¢¢¢¢¢¢¢¢¦êªÊÐýˆÐù` NäH­ó îò­ò ©  h `H­ò)ài!ò­óióh`©ò© ó Nä©  ©? Wä©¢0  Ž Ž Ž ˆÐñ© Wä©v…ð©â…ñ ©;…ò¢© ÊÐú¢±ðÈ ÊÐ÷˜ÐæñÆòÐâ© eä Nä©  ©  `(((((þ(þ((|Ð|üD D0HP TH4 T88T|0<8LÎÆæd88~|Æ`ÀüÆÆ|þÆ 000|ÆÆ|ÆÆ||ÆÆ~ x0 @ <<8D8Dšª”@<8lÆÆþÆÆüÆÆüÆÆüÆÆÆþÆÆÆ~~ÆÆ|ÆÌØðøÜÎ``````~ÆîþþÖÆÆÆæöþÞÎÆ|ÆÆÆÆÆ|üÆÆÆüÀÀ|ÆÆÆÞÌzüÆÆÎøÜÎxÌÀ|Æ|~ÆÆÆÆÆÆ|ÆÆÆî|8ÆÆÖþþîÆÆî|8|îÆfff<þ8pàþ, , û`,  © `©H© Wäh¢ð    ÊÐñ©¢@ ÊÐú`H©¥ÍñðñŠH˜H âh¨hªhL§á ÇáLÇáLªá©ñ`x© «äL½äL½äÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ•àáànestopia-1.51.1/source/unrar/000077500000000000000000000000001411157722000160505ustar00rootroot00000000000000nestopia-1.51.1/source/unrar/license.txt000066400000000000000000000013161411157722000202340ustar00rootroot00000000000000 The unrar.dll library is freeware. This means: 1. All copyrights to RAR and the unrar.dll are exclusively owned by the author - Alexander Roshal. 2. The unrar.dll library may be used in any software to handle RAR archives without limitations free of charge. 3. THE RAR ARCHIVER AND THE UNRAR.DLL LIBRARY ARE DISTRIBUTED "AS IS". NO WARRANTY OF ANY KIND IS EXPRESSED OR IMPLIED. YOU USE AT YOUR OWN RISK. THE AUTHOR WILL NOT BE LIABLE FOR DATA LOSS, DAMAGES, LOSS OF PROFITS OR ANY OTHER KIND OF LOSS WHILE USING OR MISUSING THIS SOFTWARE. Thank you for your interest in RAR and unrar.dll. Alexander L. Roshalnestopia-1.51.1/source/unrar/unrar.h000066400000000000000000000065131411157722000173550ustar00rootroot00000000000000#ifndef _UNRAR_DLL_ #define _UNRAR_DLL_ #define ERAR_END_ARCHIVE 10 #define ERAR_NO_MEMORY 11 #define ERAR_BAD_DATA 12 #define ERAR_BAD_ARCHIVE 13 #define ERAR_UNKNOWN_FORMAT 14 #define ERAR_EOPEN 15 #define ERAR_ECREATE 16 #define ERAR_ECLOSE 17 #define ERAR_EREAD 18 #define ERAR_EWRITE 19 #define ERAR_SMALL_BUF 20 #define ERAR_UNKNOWN 21 #define RAR_OM_LIST 0 #define RAR_OM_EXTRACT 1 #define RAR_SKIP 0 #define RAR_TEST 1 #define RAR_EXTRACT 2 #define RAR_VOL_ASK 0 #define RAR_VOL_NOTIFY 1 #define RAR_DLL_VERSION 4 struct RARHeaderData { char ArcName[260]; char FileName[260]; unsigned int Flags; unsigned int PackSize; unsigned int UnpSize; unsigned int HostOS; unsigned int FileCRC; unsigned int FileTime; unsigned int UnpVer; unsigned int Method; unsigned int FileAttr; char *CmtBuf; unsigned int CmtBufSize; unsigned int CmtSize; unsigned int CmtState; }; struct RARHeaderDataEx { char ArcName[1024]; wchar_t ArcNameW[1024]; char FileName[1024]; wchar_t FileNameW[1024]; unsigned int Flags; unsigned int PackSize; unsigned int PackSizeHigh; unsigned int UnpSize; unsigned int UnpSizeHigh; unsigned int HostOS; unsigned int FileCRC; unsigned int FileTime; unsigned int UnpVer; unsigned int Method; unsigned int FileAttr; char *CmtBuf; unsigned int CmtBufSize; unsigned int CmtSize; unsigned int CmtState; unsigned int Reserved[1024]; }; struct RAROpenArchiveData { char *ArcName; unsigned int OpenMode; unsigned int OpenResult; char *CmtBuf; unsigned int CmtBufSize; unsigned int CmtSize; unsigned int CmtState; }; struct RAROpenArchiveDataEx { char *ArcName; wchar_t *ArcNameW; unsigned int OpenMode; unsigned int OpenResult; char *CmtBuf; unsigned int CmtBufSize; unsigned int CmtSize; unsigned int CmtState; unsigned int Flags; unsigned int Reserved[32]; }; enum UNRARCALLBACK_MESSAGES { UCM_CHANGEVOLUME,UCM_PROCESSDATA,UCM_NEEDPASSWORD }; typedef int (CALLBACK *UNRARCALLBACK)(UINT msg,LONG UserData,LONG P1,LONG P2); typedef int (PASCAL *CHANGEVOLPROC)(char *ArcName,int Mode); typedef int (PASCAL *PROCESSDATAPROC)(unsigned char *Addr,int Size); #ifdef __cplusplus extern "C" { #endif HANDLE PASCAL RAROpenArchive(struct RAROpenArchiveData *ArchiveData); HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *ArchiveData); int PASCAL RARCloseArchive(HANDLE hArcData); int PASCAL RARReadHeader(HANDLE hArcData,struct RARHeaderData *HeaderData); int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *HeaderData); int PASCAL RARProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestName); int PASCAL RARProcessFileW(HANDLE hArcData,int Operation,wchar_t *DestPath,wchar_t *DestName); void PASCAL RARSetCallback(HANDLE hArcData,UNRARCALLBACK Callback,LONG UserData); void PASCAL RARSetChangeVolProc(HANDLE hArcData,CHANGEVOLPROC ChangeVolProc); void PASCAL RARSetProcessDataProc(HANDLE hArcData,PROCESSDATAPROC ProcessDataProc); void PASCAL RARSetPassword(HANDLE hArcData,char *Password); int PASCAL RARGetDllVersion(); #ifdef __cplusplus } #endif #endif nestopia-1.51.1/source/unrar/unrardll.txt000066400000000000000000000417751411157722000204520ustar00rootroot00000000000000 unRAR.dll Manual ~~~~~~~~~~~~~~~~ UNRAR.DLL is a 32-bit Windows dynamic-link library which provides file extraction from RAR archives. Exported functions ==================================================================== HANDLE PASCAL RAROpenArchive(struct RAROpenArchiveData *ArchiveData) ==================================================================== Description ~~~~~~~~~~~ Open RAR archive and allocate memory structures Parameters ~~~~~~~~~~ ArchiveData Points to RAROpenArchiveData structure struct RAROpenArchiveData { char *ArcName; UINT OpenMode; UINT OpenResult; char *CmtBuf; UINT CmtBufSize; UINT CmtSize; UINT CmtState; }; Structure fields: ArcName Input parameter which should point to zero terminated string containing the archive name. OpenMode Input parameter. Possible values RAR_OM_LIST Open archive for reading file headers only RAR_OM_EXTRACT Open archive for testing and extracting files OpenResult Output parameter. Possible values 0 Success ERAR_NO_MEMORY Not enough memory to initialize data structures ERAR_BAD_DATA Archive header broken ERAR_BAD_ARCHIVE File is not valid RAR archive ERAR_UNKNOWN_FORMAT Unknown encryption used for archive headers ERAR_EOPEN File open error CmtBuf Input parameter which should point to the buffer for archive comments. Maximum comment size is limited to 64Kb. Comment text is zero terminated. If the comment text is larger than the buffer size, the comment text will be truncated. If CmtBuf is set to NULL, comments will not be read. CmtBufSize Input parameter which should contain size of buffer for archive comments. CmtSize Output parameter containing size of comments actually read into the buffer, cannot exceed CmtBufSize. CmtState Output parameter. Possible values 0 comments not present 1 Comments read completely ERAR_NO_MEMORY Not enough memory to extract comments ERAR_BAD_DATA Broken comment ERAR_UNKNOWN_FORMAT Unknown comment format ERAR_SMALL_BUF Buffer too small, comments not completely read Return values ~~~~~~~~~~~~~ Archive handle or NULL in case of error ======================================================================== HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *ArchiveData) ======================================================================== Description ~~~~~~~~~~~ Similar to RAROpenArchive, but uses RAROpenArchiveDataEx structure allowing to specify Unicode archive name and returning information about archive flags. Parameters ~~~~~~~~~~ ArchiveData Points to RAROpenArchiveDataEx structure struct RAROpenArchiveDataEx { char *ArcName; wchar_t *ArcNameW; unsigned int OpenMode; unsigned int OpenResult; char *CmtBuf; unsigned int CmtBufSize; unsigned int CmtSize; unsigned int CmtState; unsigned int Flags; unsigned int Reserved[32]; }; Structure fields: ArcNameW Input parameter which should point to zero terminated Unicode string containing the archive name or NULL if Unicode name is not specified. Flags Output parameter. Combination of bit flags. Possible values 0x0001 - Volume attribute (archive volume) 0x0002 - Archive comment present 0x0004 - Archive lock attribute 0x0008 - Solid attribute (solid archive) 0x0010 - New volume naming scheme ('volname.partN.rar') 0x0020 - Authenticity information present 0x0040 - Recovery record present 0x0080 - Block headers are encrypted 0x0100 - First volume (set only by RAR 3.0 and later) Reserved[32] Reserved for future use. Must be zero. Information on other structure fields and function return values is available above, in RAROpenArchive function description. ==================================================================== int PASCAL RARCloseArchive(HANDLE hArcData) ==================================================================== Description ~~~~~~~~~~~ Close RAR archive and release allocated memory. It must be called when archive processing is finished, even if the archive processing was stopped due to an error. Parameters ~~~~~~~~~~ hArcData This parameter should contain the archive handle obtained from the RAROpenArchive function call. Return values ~~~~~~~~~~~~~ 0 Success ERAR_ECLOSE Archive close error ==================================================================== int PASCAL RARReadHeader(HANDLE hArcData, struct RARHeaderData *HeaderData) ==================================================================== Description ~~~~~~~~~~~ Read header of file in archive. Parameters ~~~~~~~~~~ hArcData This parameter should contain the archive handle obtained from the RAROpenArchive function call. HeaderData It should point to RARHeaderData structure: struct RARHeaderData { char ArcName[260]; char FileName[260]; UINT Flags; UINT PackSize; UINT UnpSize; UINT HostOS; UINT FileCRC; UINT FileTime; UINT UnpVer; UINT Method; UINT FileAttr; char *CmtBuf; UINT CmtBufSize; UINT CmtSize; UINT CmtState; }; Structure fields: ArcName Output parameter which contains a zero terminated string of the current archive name. May be used to determine the current volume name. FileName Output parameter which contains a zero terminated string of the file name in OEM (DOS) encoding. Flags Output parameter which contains file flags: 0x01 - file continued from previous volume 0x02 - file continued on next volume 0x04 - file encrypted with password 0x08 - file comment present 0x10 - compression of previous files is used (solid flag) bits 7 6 5 0 0 0 - dictionary size 64 Kb 0 0 1 - dictionary size 128 Kb 0 1 0 - dictionary size 256 Kb 0 1 1 - dictionary size 512 Kb 1 0 0 - dictionary size 1024 Kb 1 0 1 - dictionary size 2048 KB 1 1 0 - dictionary size 4096 KB 1 1 1 - file is directory Other bits are reserved. PackSize Output parameter means packed file size or size of the file part if file was split between volumes. UnpSize Output parameter - unpacked file size. HostOS Output parameter - operating system used for archiving: 0 - MS DOS; 1 - OS/2. 2 - Win32 3 - Unix FileCRC Output parameter which contains unpacked file CRC. It should not be used for file parts which were split between volumes. FileTime Output parameter - contains date and time in standard MS DOS format. UnpVer Output parameter - RAR version needed to extract file. It is encoded as 10 * Major version + minor version. Method Output parameter - packing method. FileAttr Output parameter - file attributes. CmtBuf File comments support is not implemented in the new DLL version yet. Now CmtState is always 0. /* * Input parameter which should point to the buffer for file * comments. Maximum comment size is limited to 64Kb. Comment text is * a zero terminated string in OEM encoding. If the comment text is * larger than the buffer size, the comment text will be truncated. * If CmtBuf is set to NULL, comments will not be read. */ CmtBufSize Input parameter which should contain size of buffer for archive comments. CmtSize Output parameter containing size of comments actually read into the buffer, should not exceed CmtBufSize. CmtState Output parameter. Possible values 0 Absent comments 1 Comments read completely ERAR_NO_MEMORY Not enough memory to extract comments ERAR_BAD_DATA Broken comment ERAR_UNKNOWN_FORMAT Unknown comment format ERAR_SMALL_BUF Buffer too small, comments not completely read Return values ~~~~~~~~~~~~~ 0 Success ERAR_END_ARCHIVE End of archive ERAR_BAD_DATA File header broken ==================================================================== int PASCAL RARReadHeaderEx(HANDLE hArcData, struct RARHeaderDataEx *HeaderData) ==================================================================== Description ~~~~~~~~~~~ Similar to RARReadHeader, but uses RARHeaderDataEx structure, containing information about Unicode file names and 64 bit file sizes. struct RARHeaderDataEx { char ArcName[1024]; wchar_t ArcNameW[1024]; char FileName[1024]; wchar_t FileNameW[1024]; unsigned int Flags; unsigned int PackSize; unsigned int PackSizeHigh; unsigned int UnpSize; unsigned int UnpSizeHigh; unsigned int HostOS; unsigned int FileCRC; unsigned int FileTime; unsigned int UnpVer; unsigned int Method; unsigned int FileAttr; char *CmtBuf; unsigned int CmtBufSize; unsigned int CmtSize; unsigned int CmtState; unsigned int Reserved[1024]; }; ==================================================================== int PASCAL RARProcessFile(HANDLE hArcData, int Operation, char *DestPath, char *DestName) ==================================================================== Description ~~~~~~~~~~~ Performs action and moves the current position in the archive to the next file. Extract or test the current file from the archive opened in RAR_OM_EXTRACT mode. If the mode RAR_OM_LIST is set, then a call to this function will simply skip the archive position to the next file. Parameters ~~~~~~~~~~ hArcData This parameter should contain the archive handle obtained from the RAROpenArchive function call. Operation File operation. Possible values RAR_SKIP Move to the next file in the archive. If the archive is solid and RAR_OM_EXTRACT mode was set when the archive was opened, the current file will be processed - the operation will be performed slower than a simple seek. RAR_TEST Test the current file and move to the next file in the archive. If the archive was opened with RAR_OM_LIST mode, the operation is equal to RAR_SKIP. RAR_EXTRACT Extract the current file and move to the next file. If the archive was opened with RAR_OM_LIST mode, the operation is equal to RAR_SKIP. DestPath This parameter should point to a zero terminated string containing the destination directory to which to extract files to. If DestPath is equal to NULL, it means extract to the current directory. This parameter has meaning only if DestName is NULL. DestName This parameter should point to a string containing the full path and name of the file to be extracted or NULL as default. If DestName is defined (not NULL) it overrides the original file name saved in the archive and DestPath setting. Both DestPath and DestName must be in OEM encoding. If necessary, use CharToOem to convert text to OEM before passing to this function. Return values ~~~~~~~~~~~~~ 0 Success ERAR_BAD_DATA File CRC error ERAR_BAD_ARCHIVE Volume is not valid RAR archive ERAR_UNKNOWN_FORMAT Unknown archive format ERAR_EOPEN Volume open error ERAR_ECREATE File create error ERAR_ECLOSE File close error ERAR_EREAD Read error ERAR_EWRITE Write error Note: if you wish to cancel extraction, return -1 when processing UCM_PROCESSDATA callback message. ==================================================================== int PASCAL RARProcessFileW(HANDLE hArcData, int Operation, wchar_t *DestPath, wchar_t *DestName) ==================================================================== Description ~~~~~~~~~~~ Unicode version of RARProcessFile. It uses Unicode DestPath and DestName parameters, other parameters and return values are the same as in RARProcessFile. ==================================================================== void PASCAL RARSetCallback(HANDLE hArcData, int PASCAL (*CallbackProc)(UINT msg,LONG UserData,LONG P1,LONG P2), LONG UserData); ==================================================================== Description ~~~~~~~~~~~ Set a user-defined callback function to process Unrar events. Parameters ~~~~~~~~~~ hArcData This parameter should contain the archive handle obtained from the RAROpenArchive function call. CallbackProc It should point to a user-defined callback function. The function will be passed four parameters: msg Type of event. Described below. UserData User defined value passed to RARSetCallback. P1 and P2 Event dependent parameters. Described below. Possible events UCM_CHANGEVOLUME Process volume change. P1 Points to the zero terminated name of the next volume. P2 The function call mode: RAR_VOL_ASK Required volume is absent. The function should prompt user and return a positive value to retry or return -1 value to terminate operation. The function may also specify a new volume name, placing it to the address specified by P1 parameter. RAR_VOL_NOTIFY Required volume is successfully opened. This is a notification call and volume name modification is not allowed. The function should return a positive value to continue or -1 to terminate operation. UCM_PROCESSDATA Process unpacked data. It may be used to read a file while it is being extracted or tested without actual extracting file to disk. Return a positive value to continue process or -1 to cancel the archive operation P1 Address pointing to the unpacked data. Function may refer to the data but must not change it. P2 Size of the unpacked data. It is guaranteed only that the size will not exceed the maximum dictionary size (4 Mb in RAR 3.0). UCM_NEEDPASSWORD DLL needs a password to process archive. This message must be processed if you wish to be able to handle archives with encrypted file names. It can be also used as replacement of RARSetPassword function even for usual encrypted files with non-encrypted names. P1 Address pointing to the buffer for a password. You need to copy a password here. P2 Size of the password buffer. UserData User data passed to callback function. Other functions of UNRAR.DLL should not be called from the callback function. Return values ~~~~~~~~~~~~~ None ==================================================================== void PASCAL RARSetChangeVolProc(HANDLE hArcData, int PASCAL (*ChangeVolProc)(char *ArcName,int Mode)); ==================================================================== Obsoleted, use RARSetCallback instead. ==================================================================== void PASCAL RARSetProcessDataProc(HANDLE hArcData, int PASCAL (*ProcessDataProc)(unsigned char *Addr,int Size)) ==================================================================== Obsoleted, use RARSetCallback instead. ==================================================================== void PASCAL RARSetPassword(HANDLE hArcData, char *Password); ==================================================================== Description ~~~~~~~~~~~ Set a password to decrypt files. Parameters ~~~~~~~~~~ hArcData This parameter should contain the archive handle obtained from the RAROpenArchive function call. Password It should point to a string containing a zero terminated password. Return values ~~~~~~~~~~~~~ None ==================================================================== void PASCAL RARGetDllVersion(); ==================================================================== Description ~~~~~~~~~~~ Returns unrar.dll version. Parameters ~~~~~~~~~~ None. Return values ~~~~~~~~~~~~~ Returns an integer value denoting DLL version. The current version value is defined in unrar.h as RAR_DLL_VERSION This function is absent in old versions of unrar.dll, so it may be wise to use LoadLibrary and GetProcAddress to access this function. nestopia-1.51.1/source/win32/000077500000000000000000000000001411157722000156635ustar00rootroot00000000000000nestopia-1.51.1/source/win32/NstApplicationConfiguration.cpp000066400000000000000000000201541411157722000240510ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstIoLog.hpp" #include "NstIoStream.hpp" #include "NstWindowUser.hpp" #include "NstApplicationInstance.hpp" #include "../core/NstXml.hpp" namespace Nestopia { namespace Application { struct Configuration::Node { Node(); typedef Nes::Core::Xml Xml; Node& Get(const HeapString&); const Node* Find(cstring) const; void Load(Xml::Node); void Save(Xml::Node,wcstring=NULL) const; void CheckReference(wcstring) const; typedef HeapString Key; typedef std::multimap Map; Map map; HeapString string; struct { Map* map; Map::iterator item; } parent; mutable bool referenced; }; Configuration::Configuration() : root(*new Node), save(false) { //const Path path( Instance::GetExePath(L"nestopia.xml") ); const Path path( Instance::GetConfigPath(L"nestopia.xml") ); //bg if (path.FileExists()) { try { Nes::Core::Xml xml; { Io::Stream::In file( path ); xml.Read( file ); } if (!xml.GetRoot().IsType( L"configuration" )) throw 1; if (HeapString(Instance::GetVersion()) != xml.GetRoot().GetAttribute(L"version").GetValue()) Window::User::Warn( L"The configuration file is old and may not work reliably with this version of Nestopia!", L"Configuration file version conflict!" ); root.Load( xml.GetRoot().GetFirstChild() ); } catch (...) { Reset( false ); Window::User::Warn( L"Configuration file load error! Default settings will be used!" ); } } if (wcstring ptr = ::GetCommandLine()) { for (uint quote=0; (*ptr > ' ') || (*ptr && quote); ++ptr) { if (*ptr == '\"') quote ^= 1; } while (*ptr && *ptr <= ' ') ++ptr; if (*ptr) { if (*ptr != '-') { wcstring const offset = ptr; for (uint quote=0; (*ptr > ' ') || (*ptr && quote); ++ptr) { if (*ptr == '\"') quote ^= 1; } startupFile.Assign( offset, ptr - offset ); startupFile.Remove( '\"' ); startupFile.Trim(); // Win98/ME/2k fix if (startupFile.Length()) startupFile = Instance::GetLongPath( startupFile.Ptr() ); } } } } Configuration::~Configuration() { if (save) { try { Nes::Core::Xml xml; xml.Create( L"configuration" ).AddAttribute( L"version", HeapString(Instance::GetVersion()).Ptr() ); root.Save( xml.GetRoot() ); //Io::Stream::Out file( Instance::GetExePath(L"nestopia.xml") ); Io::Stream::Out file( Instance::GetConfigPath(L"nestopia.xml") );//bg xml.Write( xml.GetRoot(), file ); } catch (...) { Window::User::Warn( L"Couldn't save the configuration!" ); } } delete &root; } void Configuration::Reset(bool notify) { if (notify) root.CheckReference( L"" ); root.map.clear(); } void Configuration::EnableSaving(bool enable) { save = enable; } const Path& Configuration::GetStartupFile() const { return startupFile; } Configuration::ConstSection Configuration::operator [] (cstring key) const { return root.Find( key ); } Configuration::Section Configuration::operator [] (cstring key) { return &root.Get( key ); } Configuration::ConstSection Configuration::ConstSection::operator [] (cstring key) const { return node ? node->Find( key ) : NULL; } Configuration::ConstSection Configuration::ConstSection::operator [] (uint i) const { if (node) { if (i) { Node::Map::iterator it( node->parent.item ); while (++it != node->parent.map->end() && it->first == node->parent.item->first) { if (!--i) { it->second.referenced = true; return &it->second; } } } else { return *this; } } return NULL; } Configuration::Section Configuration::Section::operator [] (cstring key) { return &node->Get( key ); } Configuration::Section Configuration::Section::operator [] (uint i) { if (i) { Node::Map::iterator it( node->parent.item ); while (++it != node->parent.map->end() && it->first == node->parent.item->first) { if (!--i) return &it->second; } const Node::Map::value_type item( node->parent.item->first,Node() ); do { it = node->parent.map->insert( it, item ); it->second.parent.map = node->parent.map; it->second.parent.item = it; } while (--i); return &it->second; } else { return *this; } } HeapString& Configuration::Section::Str() { return node->string; } GenericString Configuration::ConstSection::Str() const { return node ? GenericString(node->string) : GenericString(); } ulong Configuration::ConstSection::Int() const { ulong i; return node && (node->string >> i) ? i : 0; } ulong Configuration::ConstSection::Int(ulong d) const { ulong i; return node && (node->string >> i) ? i : d; } void Configuration::Section::IntProxy::operator = (ulong i) { node.string << i; } void Configuration::Section::YesNoProxy::operator = (bool yes) { node.string.Assign( yes ? L"yes" : L"no", yes ? 3 : 2 ); } bool Configuration::ConstSection::Yes() const { return node && node->string == L"yes"; } bool Configuration::ConstSection::No() const { return node && node->string == L"no"; } Configuration::Node::Node() : referenced(false) {} Configuration::Node& Configuration::Node::Get(const HeapString& key) { Map::iterator it(map.lower_bound( key )); if (it == map.end() || it->first != key) { it = map.insert( it, Map::value_type(key,Node()) ); it->second.parent.map = ↦ it->second.parent.item = it; } return it->second; } const Configuration::Node* Configuration::Node::Find(cstring key) const { Map::const_iterator it(map.find( key )); if (it != map.end()) { it->second.referenced = true; return &it->second; } return NULL; } void Configuration::Node::Load(Xml::Node xmlNode) { do { Map::iterator it(map.insert( Map::value_type(xmlNode.GetType(),Node()) )); it->second.parent.map = ↦ it->second.parent.item = it; if (const Xml::Node xmlChild=xmlNode.GetFirstChild()) it->second.Load( xmlChild ); else it->second.string = xmlNode.GetValue(); xmlNode = xmlNode.GetNextSibling(); } while (xmlNode); } void Configuration::Node::Save(Xml::Node node,wcstring const key) const { NST_ASSERT( node && (!key || *key) ); if (map.empty()) { if (key) node.AddChild( key, string.Ptr() ); } else { if (key) node = node.AddChild( key ); for (Map::const_iterator it(map.begin()), end(map.end()); it != end; ++it) it->second.Save( node, it->first.Ptr() ); } } void Configuration::Node::CheckReference(wcstring const key) const { NST_ASSERT( key ); if (map.empty()) { if (*key && !referenced) Io::Log() << "Configuration: warning, unused/invalid parameter: \"" << key << "\"\r\n"; } else for (Map::const_iterator it(map.begin()), end(map.end()); it != end; ++it) { it->second.CheckReference( it->first.Ptr() ); } } } } nestopia-1.51.1/source/win32/NstApplicationConfiguration.hpp000066400000000000000000000050421411157722000240550ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_APPLICATION_CONFIGURATION_H #define NST_APPLICATION_CONFIGURATION_H #pragma once #include "NstString.hpp" namespace Nestopia { namespace Application { class Configuration { struct Node; public: Configuration(); ~Configuration(); void Reset(bool=true); void EnableSaving(bool=true); const Path& GetStartupFile() const; class ConstSection : public ImplicitBool { public: ConstSection operator [] (cstring) const; ConstSection operator [] (uint) const; GenericString Str() const; ulong Int() const; ulong Int(ulong) const; bool Yes() const; bool No() const; private: const Node* node; public: ConstSection(const Node* n) : node(n) {} bool operator ! () const { return !node; } }; class Section { public: Section operator [] (cstring); Section operator [] (uint); HeapString& Str(); private: Node* node; class IntProxy { Node& node; public: IntProxy(Node& n) : node(n) {} void operator = (ulong); }; class YesNoProxy { Node& node; public: YesNoProxy(Node& n) : node(n) {} void operator = (bool); }; public: Section(Node* n) : node(n) {} IntProxy Int() { return *node; } YesNoProxy YesNo() { return *node; } }; Section operator [] (cstring); ConstSection operator [] (cstring) const; private: Node& root; bool save; Path startupFile; }; } } #endif nestopia-1.51.1/source/win32/NstApplicationException.cpp000066400000000000000000000033011411157722000231730ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstString.hpp" #include "NstResourceString.hpp" #include "NstWindowUser.hpp" #include "NstApplicationException.hpp" namespace Nestopia { namespace Application { int Exception::Issue() const { try { if (id) { Resource::String string( id ); if (string.Length()) { if (msg) string.Invoke( msg ); Window::User::Fail( string.Ptr() ); } else { throw 1; } } else if (msg) { Window::User::Fail( msg ); } else { return EXIT_SUCCESS; } } catch (...) { Window::User::Fail( L"Unhandled error! Call the Ghostbusters!" ); } return EXIT_FAILURE; } } } nestopia-1.51.1/source/win32/NstApplicationException.hpp000066400000000000000000000027261411157722000232120ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_APPLICATION_EXCEPTION_H #define NST_APPLICATION_EXCEPTION_H #pragma once #include "NstMain.hpp" namespace Nestopia { namespace Application { class Exception { wcstring const msg; const uint id; public: explicit Exception(wcstring string) : msg(string), id(0) {} explicit Exception(uint i=0,wcstring string=NULL) : msg(string), id(i) {} wcstring GetMsg() const { return msg; } int Issue() const; }; } } #endif nestopia-1.51.1/source/win32/NstApplicationInstance.cpp000066400000000000000000000300561411157722000230100ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "language/resource.h" #include "NstResourceCursor.hpp" #include "NstResourceVersion.hpp" #include "NstApplicationException.hpp" #include "NstApplicationLanguage.hpp" #include #include #include #include #if NST_MSVC #pragma comment(lib,"comctl32") #endif namespace Nestopia { namespace Application { const wchar_t Instance::appClassName[] = L"Nestopia"; struct Instance::Global { Global(); struct Paths { explicit Paths(HINSTANCE); Path exePath; Path wrkPath; Path configPath;//bg configuration files path }; struct Hooks { explicit Hooks(HINSTANCE); ~Hooks(); void OnCreate(const CREATESTRUCT&,HWND); void OnDestroy(HWND); static LRESULT CALLBACK CBTProc(int,WPARAM,LPARAM); enum { CHILDREN_RESERVE = 8 }; typedef Collection::Vector Children; HHOOK const handle; HWND window; Children children; }; const Paths paths; const Resource::Version version; Language language; Hooks hooks; IconStyle iconStyle; }; Instance::Global Instance::global; Instance::Events::Callbacks Instance::Events::callbacks; Instance::Global::Paths::Paths(HINSTANCE const hInstance) { uint length; do { exePath.Reserve( exePath.Capacity() + 255 ); length = ::GetModuleFileName( hInstance, exePath.Ptr(), exePath.Capacity() ); } while (length == exePath.Capacity()); exePath.ShrinkTo( length ); exePath.MakePretty( false ); exePath.Defrag(); wrkPath = "."; wrkPath.MakeAbsolute( true ); wrkPath.Defrag(); configPath.Reserve(configPath.Capacity() + 255);//bg //bg bool isLua = false; //bg check -lua between command line options int nArgs; LPWSTR *szArglist = ::CommandLineToArgvW(::GetCommandLineW(), &nArgs); if( szArglist != NULL) { for(int i=0; i name; name.ShrinkTo( ::GetClassName( hWnd, name.Ptr(), MAX_LENGTH+1 ) ); if (name.Equal( menuClassName ) || name.Equal( STATUSCLASSNAME ) || name.Equal( L"IME" )) return; if (window) { children.PushBack( hWnd ); Events::Signal( EVENT_SYSTEM_BUSY ); } else if (name.Equal( appClassName )) { window = hWnd; } else { return; } } const Events::WindowCreateParam param = { hWnd, createStruct.cx > 0 ? createStruct.cx : 0, createStruct.cy > 0 ? createStruct.cy : 0 }; Events::Signal( EVENT_WINDOW_CREATE, ¶m ); } } void Instance::Global::Hooks::OnDestroy(HWND const hWnd) { NST_ASSERT( hWnd ); Children::Iterator const child = children.Find( hWnd ); if (child) { Events::Signal( EVENT_SYSTEM_BUSY ); } else if (window != hWnd) { return; } { const Events::WindowDestroyParam param = { hWnd }; Events::Signal( EVENT_WINDOW_DESTROY, ¶m ); } if (child) children.Erase( child ); else window = NULL; } LRESULT CALLBACK Instance::Global::Hooks::CBTProc(const int nCode,const WPARAM wParam,const LPARAM lParam) { NST_COMPILE_ASSERT( HCBT_CREATEWND >= 0 && HCBT_DESTROYWND >= 0 ); switch (nCode) { case HCBT_CREATEWND: NST_ASSERT( lParam ); if (const CREATESTRUCT* const createStruct = reinterpret_cast(lParam)->lpcs) { NST_VERIFY( wParam ); global.hooks.OnCreate( *createStruct, reinterpret_cast(wParam) ); } return 0; case HCBT_DESTROYWND: NST_VERIFY( wParam ); if (wParam) global.hooks.OnDestroy( reinterpret_cast(wParam) ); return 0; } return nCode < 0 ? ::CallNextHookEx( global.hooks.handle, nCode, wParam, lParam ) : 0; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif Instance::Global::Global() : paths ( ::GetModuleHandle(NULL) ), version ( paths.exePath.Ptr(), Resource::Version::PRODUCT ), hooks ( ::GetModuleHandle(NULL) ), iconStyle ( ICONSTYLE_NES ) { } Instance::Language& Instance::GetLanguage() { return global.language; } const String::Heap& Instance::GetVersion() { return global.version; } const Path& Instance::GetExePath() { return global.paths.exePath; } const Path Instance::GetExePath(const GenericString file) { return Path( global.paths.exePath.Directory(), file ); } const Path Instance::GetConfigPath(const GenericString file)//bg { return Path( global.paths.configPath, file ); } const Path Instance::GetFullPath(const GenericString relPath) { Path curPath( "." ); curPath.MakeAbsolute( true ); const BOOL succeeded = ::SetCurrentDirectory( global.paths.wrkPath.Ptr() ); Path wrkPath( relPath ); wrkPath.MakeAbsolute(); if (succeeded) ::SetCurrentDirectory( curPath.Ptr() ); return wrkPath; } const Path Instance::GetLongPath(wcstring const shortPath) { Path longPath; longPath.Reserve( 255 ); uint length = ::GetLongPathName( shortPath, longPath.Ptr(), longPath.Capacity() + 1 ); if (length > longPath.Capacity() + 1) { longPath.Reserve( length - 1 ); length = ::GetLongPathName( shortPath, longPath.Ptr(), longPath.Capacity() + 1 ); } if (!length) return shortPath; const wchar_t slashed = GenericString(shortPath).Back(); longPath.ShrinkTo( length ); longPath.MakePretty( slashed == '\\' || slashed == '/' ); return longPath; } const Path Instance::GetTmpPath(GenericString file) { Path path; path.Reserve( 255 ); if (uint length = ::GetTempPath( path.Capacity() + 1, path.Ptr() )) { if (length > path.Capacity() + 1) { path.Reserve( length - 1 ); length = ::GetTempPath( path.Capacity() + 1, path.Ptr() ); } if (length) path = GetLongPath( path.Ptr() ); } if (path.Length()) path.MakePretty( true ); else path << ".\\"; if (file.Empty()) file = L"nestopia.tmp"; path << file; return path; } Instance::Events::Callbacks::~Callbacks() { NST_VERIFY( Empty() ); } void Instance::Events::Add(const Callback& callback) { NST_ASSERT( bool(callback) && !callbacks.Find( callback ) ); callbacks.PushBack( callback ); } void Instance::Events::Signal(const Event event,const void* param) { for (Callbacks::ConstIterator it(callbacks.Begin()), end(callbacks.End()); it != end; ++it) (*it)( event, param ); } void Instance::Events::Remove(const void* const instance) { for (Callbacks::Iterator it(callbacks.Begin()); it != callbacks.End(); ++it) { if (it->VoidPtr() == instance) { callbacks.Erase( it ); break; } } } Window::Generic Instance::GetMainWindow() { return global.hooks.window; } uint Instance::NumChildWindows() { return global.hooks.children.Size(); } Window::Generic Instance::GetChildWindow(uint i) { return global.hooks.children[i]; } Window::Generic Instance::GetActiveWindow() { HWND hWnd = ::GetActiveWindow(); return hWnd ? hWnd : global.hooks.window; } Instance::IconStyle Instance::GetIconStyle() { return global.iconStyle; } void Instance::SetIconStyle(IconStyle style) { global.iconStyle = style; } void Instance::ShowChildWindows(bool show) { const uint state = (show ? SW_SHOWNA : SW_HIDE); for (Global::Hooks::Children::ConstIterator it(global.hooks.children.Begin()), end(global.hooks.children.End()); it != end; ++it) ::ShowWindow( *it, state ); } Instance::Waiter::Waiter() : hCursor(::SetCursor(Resource::Cursor::GetWait())) {} Instance::Locker::Locker() : hWnd(GetMainWindow()), enabled(::IsWindowEnabled(hWnd)) { ::EnableWindow( hWnd, false ); ::LockWindowUpdate( hWnd ); } bool Instance::Locker::CheckInput(int vKey) const { if (::GetAsyncKeyState( vKey ) & 0x8000U) { while (::GetAsyncKeyState( vKey ) & 0x8000U) ::Sleep( 10 ); return true; } return false; } Instance::Locker::~Locker() { ::LockWindowUpdate( NULL ); ::EnableWindow( hWnd, enabled ); for (MSG msg;::PeekMessage( &msg, NULL, 0, 0, PM_REMOVE|PM_QS_INPUT );); } Instance::Instance() { if (!static_cast(cfg)["preferences"]["application"]["allow-multiple-instances"].Yes()) { ::CreateMutex( NULL, true, L"Nestopia Mutex" ); if (::GetLastError() == ERROR_ALREADY_EXISTS) { if (Window::Generic window = Window::Generic::Find( appClassName )) { window.Activate(); if (const uint length = cfg.GetStartupFile().Length()) { COPYDATASTRUCT cds; cds.dwData = COPYDATA_OPENFILE_ID; cds.cbData = (length + 1) * sizeof(wchar_t); cds.lpData = const_cast(cfg.GetStartupFile().Ptr()); window.Send( WM_COPYDATA, 0, &cds ); } } throw Exception(); } } if (global.paths.exePath.Empty()) throw Exception( L"unicows.dll file is missing!" ); global.language.Load( cfg ); if (global.hooks.handle == NULL) throw Exception( IDS_ERR_FAILED, L"SetWindowsHookEx()" ); if (FAILED(::CoInitializeEx( NULL, COINIT_APARTMENTTHREADED ))) throw Exception( IDS_ERR_FAILED, L"CoInitializeEx()" ); Object::Pod initCtrlEx; initCtrlEx.dwSize = sizeof(initCtrlEx); initCtrlEx.dwICC = ICC_WIN95_CLASSES; ::InitCommonControlsEx( &initCtrlEx ); } Instance::~Instance() { ::CoUninitialize(); } void Instance::Save() { global.language.Save( cfg ); } } } nestopia-1.51.1/source/win32/NstApplicationInstance.hpp000066400000000000000000000071041411157722000230130ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_APPLICATION_INSTANCE_H #define NST_APPLICATION_INSTANCE_H #pragma once #include "NstObjectDelegate.hpp" #include "NstCollectionVector.hpp" #include "NstApplicationConfiguration.hpp" #include "NstWindowGeneric.hpp" namespace Nestopia { namespace Application { class Instance { public: Instance(); ~Instance(); void Save(); static const Path& GetExePath(); static const Path GetExePath(const GenericString); static const Path GetConfigPath(const GenericString);//bg static const Path GetLongPath(wcstring); static const Path GetTmpPath(GenericString=GenericString()); static const Path GetFullPath(const GenericString); static const String::Heap& GetVersion(); static uint NumChildWindows(); static void ShowChildWindows(bool=true); static Window::Generic GetChildWindow(uint=0); static Window::Generic GetMainWindow(); static Window::Generic GetActiveWindow(); class Language; static Language& GetLanguage(); enum IconStyle { ICONSTYLE_NES, ICONSTYLE_FAMICOM }; static IconStyle GetIconStyle(); static void SetIconStyle(IconStyle); enum { WM_NST_COMMAND_RESUME = WM_APP + 55, WM_NST_LAUNCH = WM_APP + 56, COPYDATA_OPENFILE_ID = 0xDEAF }; enum Event { EVENT_WINDOW_CREATE = 1, EVENT_WINDOW_DESTROY, EVENT_SYSTEM_BUSY, EVENT_FULLSCREEN, EVENT_DESKTOP }; class Events { public: struct WindowCreateParam { HWND hWnd; uint x; uint y; }; struct WindowDestroyParam { HWND hWnd; }; private: typedef Object::Delegate Callback; struct Callbacks : Collection::Vector { ~Callbacks(); }; static void Add(const Callback&); static Callbacks callbacks; public: static void Remove(const void*); static void Signal(Event,const void* = NULL); template static void Add(Data* data,Code code) { Add( Callback(data,code) ); } }; private: Configuration cfg; struct Global; static Global global; static const wchar_t appClassName[]; public: Configuration& GetConfiguration2() { return cfg; } static wcstring GetClassName() { return appClassName; } class Waiter { HCURSOR const hCursor; public: Waiter(); ~Waiter() { ::SetCursor( hCursor ); } }; class Locker { HWND const hWnd; const bool enabled; public: Locker(); ~Locker(); bool CheckInput(int) const; }; }; } } #endif nestopia-1.51.1/source/win32/NstApplicationLanguage.cpp000066400000000000000000000062731411157722000227730ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstApplicationException.hpp" #include "NstApplicationLanguage.hpp" namespace Nestopia { namespace Application { bool Instance::Language::Resource::Load(wcstring const p) { if (!Dll::Load( p )) return false; path = p; return true; } void Instance::Language::Load(const Configuration& cfg) { if (!resource) Load( cfg["language"]["file"].Str().Ptr() ); } void Instance::Language::Save(Configuration& cfg) const { if (resource.path.Length()) cfg["language"]["file"].Str() = resource.path; } void Instance::Language::Load(wcstring const path) { if (!path || !*path) { Paths paths; EnumerateResources( paths ); if (paths.empty()) throw Exception( L"language\\english.nlg file not found!" ); Paths::const_iterator it( paths.begin() ); for (Paths::const_iterator end(paths.end()); it != end; ++it) { if (it->File() == L"english.nlg") break; } if (it == paths.end()) it = paths.begin(); if (!resource.Load( it->Ptr() )) throw Exception( L"Failed to load language plugin file!" ); } else if (!resource.Load( path )) { Load( NULL ); } } void Instance::Language::UpdateResource(wcstring const update) { NST_ASSERT( update ); resource.path = update; } void Instance::Language::EnumerateResources(Paths& paths) const { for (uint i=0; i < 2 && paths.empty(); ++i) { struct FileFinder { WIN32_FIND_DATA data; HANDLE const handle; FileFinder(wcstring const path) : handle(::FindFirstFile( path, &data )) {} ~FileFinder() { if (handle != INVALID_HANDLE_VALUE) ::FindClose( handle ); } }; Path path( Instance::GetExePath(i ? L"*.*" : L"language\\*.*") ); FileFinder findFile( path.Ptr() ); if (findFile.handle != INVALID_HANDLE_VALUE) { do { if (!(findFile.data.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_DIRECTORY))) { path.File() = findFile.data.cFileName; if (path.Extension() == L"nlg") paths.push_back( path ); } } while (::FindNextFile( findFile.handle, &findFile.data )); } } } } } nestopia-1.51.1/source/win32/NstApplicationLanguage.hpp000066400000000000000000000034041411157722000227710ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_APPLICATION_LANGUAGE_H #define NST_APPLICATION_LANGUAGE_H #pragma once #include #include "NstSystemDll.hpp" #include "NstApplicationInstance.hpp" namespace Nestopia { namespace Application { class Instance::Language { public: void Load(const Configuration&); void Save(Configuration&) const; typedef std::vector Paths; void UpdateResource(wcstring); void EnumerateResources(Paths&) const; private: void Load(wcstring); struct Resource : System::Dll { bool Load(wcstring); Path path; }; Resource resource; public: HMODULE GetResourceHandle() const { return resource.GetHandle(); } const Path& GetResourcePath() const { return resource.path; } }; } } #endif nestopia-1.51.1/source/win32/NstApplicationMain.cpp000066400000000000000000000125521411157722000221310ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstWindowUser.hpp" #include "NstWindowParam.hpp" #include "NstApplicationMain.hpp" #include "../core/api/NstApiMachine.hpp" namespace Nestopia { namespace Application { Main::Main(const int cmdShow) : menu ( IDR_MENU ), preferences ( emulator, instance.GetConfiguration2(), menu ), logfile ( emulator, menu, preferences ), language ( emulator, menu ), paths ( emulator, instance.GetConfiguration2(), menu ), window ( emulator, instance.GetConfiguration2(), menu, paths, preferences, cmdShow ), recentFiles ( emulator, instance.GetConfiguration2(), menu ), recentDirs ( emulator, instance.GetConfiguration2(), menu ), machine ( emulator, instance.GetConfiguration2(), menu, preferences ), netplay ( emulator, instance.GetConfiguration2(), menu, paths, window.Get() ), launcher ( emulator, instance.GetConfiguration2(), menu, paths, window.Get() ), fds ( emulator, instance.GetConfiguration2(), menu, paths ), tapeRecorder ( emulator, instance.GetConfiguration2(), menu, paths ), dipSwitches ( emulator, instance.GetConfiguration2(), menu ), barcodeReader ( emulator, menu ), nsf ( emulator, instance.GetConfiguration2(), menu ), movie ( emulator, menu, paths ), cheats ( emulator, instance.GetConfiguration2(), menu, paths ), saveStates ( emulator, menu, paths, window ), imageDatabase ( emulator, instance.GetConfiguration2(), menu, paths ), imageInfo ( emulator, menu ), help ( emulator, menu ), inesHeader ( emulator, menu, paths ), files ( emulator, menu, paths, preferences, movie, tapeRecorder, cheats, saveStates, window ) { static const Window::MsgHandler::Entry
messages[] = { { WM_CLOSE, &Main::OnWinClose }, { WM_QUERYENDSESSION, &Main::OnWinQueryEndSession } }; window.Get().Messages().Add( this, messages ); menu.Commands().Add( IDM_FILE_QUIT, this, &Main::OnCmdFileExit ); instance.GetConfiguration2().Reset(); if (instance.GetConfiguration2().GetStartupFile().Length()) window.Get().Send( Instance::WM_NST_LAUNCH, 0, instance.GetConfiguration2().GetStartupFile().Ptr() ); } Main::~Main() { emulator.Unload(); menu.Commands().Remove( this ); window.Get().Messages().Remove( this ); } void Main::Save() { Instance::Waiter waiter; Configuration& cfg = instance.GetConfiguration2(); preferences.Save ( cfg ); recentFiles.Save ( cfg ); recentDirs.Save ( cfg ); paths.Save ( cfg ); imageDatabase.Save ( cfg ); launcher.Save ( cfg, preferences[Managers::Preferences::SAVE_LAUNCHERSIZE], preferences[Managers::Preferences::SAVE_LAUNCHER] ); netplay.Save ( cfg, preferences[Managers::Preferences::SAVE_NETPLAY_GAMELIST] ); fds.Save ( cfg ); dipSwitches.Save ( cfg ); tapeRecorder.Save ( cfg ); nsf.Save ( cfg ); window.Save ( cfg ); machine.Save ( cfg ); if (preferences[Managers::Preferences::SAVE_CHEATS]) cheats.Save( cfg ); if (preferences[Managers::Preferences::SAVE_SETTINGS]) cfg.EnableSaving(); instance.Save(); } int Main::Run() { int exitCode = window.Run(); emulator.Unload(); if (exitCode == EXIT_SUCCESS) Save(); return exitCode; } bool Main::FirstUnloadOnExit() { return ( preferences[Managers::Preferences::FIRST_UNLOAD_ON_EXIT] && emulator.IsImage() ); } bool Main::OkToExit() const { return ( !preferences[Managers::Preferences::CONFIRM_EXIT] || Window::User::Confirm( IDS_ARE_YOU_SURE, IDS_TITLE_EXIT ) ); } void Main::Exit() { if (netplay.Close()) { if (FirstUnloadOnExit()) { window.Get().SendCommand( IDM_FILE_CLOSE ); } else if (OkToExit()) { emulator.Unload(); if (menu[IDM_MACHINE_SYSTEM_AUTO].Checked()) Nes::Machine(emulator).SetMode( Nes::Machine::NTSC ); ::PostQuitMessage( EXIT_SUCCESS ); } } } ibool Main::OnWinClose(Window::Param&) { Exit(); return true; } ibool Main::OnWinQueryEndSession(Window::Param& param) { netplay.Close(); if (emulator.IsImage()) window.Get().SendCommand( IDM_FILE_CLOSE ); param.lParam = !emulator.IsImage(); return true; } void Main::OnCmdFileExit(uint) { Exit(); Managers::Manager::Resume(); } } } nestopia-1.51.1/source/win32/NstApplicationMain.hpp000066400000000000000000000060261411157722000221350ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_APPLICATION_MAIN_H #define NST_APPLICATION_MAIN_H #pragma once #include "NstApplicationInstance.hpp" #include "NstManagerPaths.hpp" #include "NstManagerLogfile.hpp" #include "NstManagerPreferences.hpp" #include "NstManagerLauncher.hpp" #include "NstManagerMachine.hpp" #include "NstManagerNetplay.hpp" #include "NstManagerFds.hpp" #include "NstManagerTapeRecorder.hpp" #include "NstManagerDipSwitches.hpp" #include "NstManagerBarcodeReader.hpp" #include "NstManagerNsf.hpp" #include "NstManagerMovie.hpp" #include "NstManagerSaveStates.hpp" #include "NstManagerCheats.hpp" #include "NstManagerRecentFiles.hpp" #include "NstManagerRecentDirs.hpp" #include "NstManagerImageInfo.hpp" #include "NstManagerImageDatabase.hpp" #include "NstManagerLanguage.hpp" #include "NstManagerHelp.hpp" #include "NstManagerFiles.hpp" #include "NstManagerInesHeader.hpp" #include "NstWindowMain.hpp" namespace Nestopia { namespace Application { class Main { public: explicit Main(int); ~Main(); int Run(); private: void Save(); void Exit(); bool FirstUnloadOnExit(); bool OkToExit() const; ibool OnWinClose (Window::Param&); ibool OnWinQueryEndSession (Window::Param&); void OnCmdFileExit(uint); Managers::Emulator emulator; Instance instance; Window::Menu menu; Managers::Preferences preferences; Managers::Logfile logfile; Managers::Language language; Managers::Paths paths; Window::Main window; Managers::RecentFiles recentFiles; Managers::RecentDirs recentDirs; Managers::Machine machine; Managers::Netplay netplay; Managers::Launcher launcher; Managers::Fds fds; Managers::TapeRecorder tapeRecorder; Managers::DipSwitches dipSwitches; Managers::BarcodeReader barcodeReader; Managers::Nsf nsf; Managers::Movie movie; Managers::Cheats cheats; Managers::SaveStates saveStates; Managers::ImageDatabase imageDatabase; Managers::ImageInfo imageInfo; Managers::Help help; Managers::InesHeader inesHeader; Managers::Files files; }; } } #endif nestopia-1.51.1/source/win32/NstCollectionBitSet.hpp000066400000000000000000000036151411157722000222740ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_COLLECTION_BITSET_H #define NST_COLLECTION_BITSET_H #pragma once #include "NstMain.hpp" namespace Nestopia { namespace Collection { class BitSet { public: typedef uint Bits; private: Bits bits; public: class Bit { Bits& bits; const Bits mask; public: Bit(Bits& b,Bits m) : bits(b), mask(m) {} operator bool () const { return bits & mask; } void operator = (bool set) { bits = set ? (bits | mask) : (bits & ~mask); } }; BitSet(Bits b=0) : bits(b) {} Bit operator [] (uint index) { return Bit( bits, 1U << index ); } bool operator [] (uint index) const { return bits & (1U << index); } uint operator () (uint mask) const { return bits & mask; } Bits& Word() { return bits; } const Bits& Word() const { return bits; } }; } } #endif nestopia-1.51.1/source/win32/NstCollectionRouter.hpp000066400000000000000000000140641411157722000223620ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_COLLECTION_ROUTER_H #define NST_COLLECTION_ROUTER_H #pragma once #include #include "NstCollectionVector.hpp" #include "NstObjectDelegate.hpp" namespace Nestopia { namespace Collection { template struct ConstParam { typedef const T& Type; }; template struct ConstParam { typedef const T* const Type; }; template<> struct ConstParam< bool > { typedef const bool Type; }; template<> struct ConstParam< char > { typedef const int Type; }; template<> struct ConstParam< schar > { typedef const int Type; }; template<> struct ConstParam< uchar > { typedef const uint Type; }; template<> struct ConstParam< short > { typedef const int Type; }; template<> struct ConstParam< ushort > { typedef const uint Type; }; template<> struct ConstParam< int > { typedef const int Type; }; template<> struct ConstParam< uint > { typedef const uint Type; }; template<> struct ConstParam< long > { typedef const long Type; }; template<> struct ConstParam< ulong > { typedef const ulong Type; }; template class Router { typedef typename ConstParam::Type KeyParam; public: typedef Object::Delegate Callback; template struct Entry { Key key; Output (T::*function)(Input); }; template struct HookEntry { Key key; void (T::*function)(Input); }; struct Item { const Key key; Callback callback; Item(KeyParam k) : key(k) {} }; template Router(KeyParam,Data*,Code); template Router(Data*,const Array&); ~Router(); NST_NO_INLINE void Remove(const void*); void RemoveAll(const void*); void Defrag(); Callback& operator [] (KeyParam); private: NST_NO_INLINE void Add(KeyParam,const Callback&); NST_NO_INLINE void Set(KeyParam,const Callback&); NST_NO_INLINE void Remove(KeyParam,const Callback&); template void Add(Data*,const Entry*,uint); template void Set(Data*,const Entry*,uint); class Items : public Collection::Vector { public: Item& GetSorted(KeyParam,bool&); Item* FindSorted(KeyParam); Item& AtSorted(KeyParam); private: NST_FORCE_INLINE uint LowerBound(KeyParam key) const { uint left = 0, right = Size(); while (left < right) { const uint middle = (left + right) / 2; if (this->At(middle)->key < key) left = middle + 1; else right = middle; } return left; } public: const Item* FindSorted(KeyParam key) const { return const_cast(this)->FindSorted(key); } }; private: struct Hook { typedef Object::Delegate Item; typedef Vector Items; Output Invoke(Input); Items items; Callback main; Hook* next; Hook() : next(NULL) {} }; NST_NO_INLINE void AddHook(KeyParam,const typename Hook::Item&); NST_NO_INLINE uint RemoveHook(Item*,Hook*,typename Hook::Item*); NST_NO_INLINE void RemoveHook(KeyParam,const typename Hook::Item&); NST_NO_INLINE void RemoveHooks(const void*); class HookRouter { Router& router; template void Add(Data*,const HookEntry*,uint); public: HookRouter(Router& ref) : router(ref) {} typedef typename Hook::Item Callback; template void Add(KeyParam key,Data* data,Code code) { router.AddHook( key, Callback(data,code) ); } template void Add(Data* data,const Hooks& hooks) { Add( data, hooks, sizeof(array(hooks)) ); } void Remove(const void* data) { router.RemoveHooks( data ); } }; Items items; Hook* hooks; public: Router() : hooks(NULL) {} const Item* operator () (KeyParam key) const { return items.FindSorted( key ); } uint Size() const { return items.Size(); } HookRouter Hooks() { return *this; } template void Add(KeyParam key,Data* data,Code code) { Add( key, Callback(data,code) ); } template void Add(Data* data,const Array& arr) { Add( data, arr, sizeof(array(arr)) ); } template void Add(Data* data,const Array& arr,const HookArray& hookArray) { Add( data, arr, sizeof(array(arr)) ); Hooks().Add( data, hookArray ); } template void Set(KeyParam key,Data* data,Code code) { Set( key, Callback(data,code) ); } template void Set(Data* data,const Array& arr) { Set( data, arr, sizeof(array(arr)) ); } template void Remove(KeyParam key,Data* data,Code code) { Remove( key, Callback(data,code) ); } }; } } #include "NstCollectionRouter.inl" #endif nestopia-1.51.1/source/win32/NstCollectionRouter.inl000066400000000000000000000221111411157722000223450ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// namespace Nestopia { namespace Collection { template template Router::Router(KeyParam key,Data* const data,Code code) : hooks(NULL) { Add( key, Callback(data,code) ); } template template Router::Router(Data* const data,const Array& arr) : hooks(NULL) { Add( data, arr, sizeof(array(arr)) ); } template Router::~Router() { for (Hook* it = hooks; it; ) { Hook* const him = it; it = it->next; delete him; } } template Output Router::Hook::Invoke(Input input) { for (uint i=0; i < items.Size(); ++i) items[i]( input ); return main ? main( input ) : Output(0); } template void Router::Add(KeyParam key,const Callback& callback) { bool existing; Callback& item = items.GetSorted( key, existing ).callback; if (existing) { NST_ASSERT ( hooks && item.template CodePtr() == &Hook::Invoke && !item.template DataPtr()->main ); item.template DataPtr()->main = callback; } else { item = callback; } } template template void Router::Add(Data* const data,const Entry* list,const uint count) { items.Reserve( items.Size() + count ); for (const Entry* const end = list + count; list != end; ++list) Add( list->key, Callback(data,list->function) ); } template template void Router::HookRouter::Add(Data* const data,const HookEntry* list,const uint count) { for (const HookEntry* const end = list + count; list != end; ++list) router.AddHook( list->key, Callback(data,list->function) ); } template void Router::Set(KeyParam key,const Callback& callback) { if (Item* const item = items.FindSorted( key )) { if (item->callback.template CodePtr() == &Hook::Invoke) item->callback.template DataPtr()->main = callback; else item->callback = callback; } else { Add( key, callback ); } } template template void Router::Set(Data* const data,const Entry* list,const uint count) { for (const Entry* const end = list + count; list != end; ++list) Set( list->key, Callback(data,list->function) ); } template void Router::Remove(KeyParam key,const Callback& callback) { if (Item* const item = items.FindSorted( key )) { if (item->callback == callback) { items.Erase( item ); } else if ( item->callback.template CodePtr() == &Hook::Invoke && item->callback.template DataPtr()->main == callback ) { item->callback.template DataPtr()->main.Reset(); } } } template void Router::Remove(const void* const data) { for (uint i=0; i < items.Size(); ) { const Callback& callback = items[i].callback; if (callback.VoidPtr() == data) { items.Erase( items.At(i) ); } else { if ( callback.template CodePtr() == &Hook::Invoke && callback.template DataPtr()->main.VoidPtr() == data ) callback.template DataPtr()->main.Unset(); ++i; } } } template void Router::RemoveAll(const void* const data) { RemoveHooks( data ); Remove( data ); } template void Router::Defrag() { items.Defrag(); } template void Router::AddHook(KeyParam key,const typename Hook::Item& newItem) { Hook* hook; bool existing; Callback& callback = items.GetSorted( key, existing ).callback; if (existing && callback.template CodePtr() == &Hook::Invoke) { hook = callback.template DataPtr(); NST_ASSERT( hook && hook->items.Size() ); } else { NST_ASSERT( !existing || callback ); hook = new Hook; if (Hook* it = hooks) { while (it->next) it = it->next; it->next = hook; } else { hooks = hook; } if (existing) hook->main = callback; callback.Set( hook, &Hook::Invoke ); } hook->items.PushBack( newItem ); } template uint Router::RemoveHook(Item* const mainItem,Hook* const hook,typename Hook::Item* const hookItem) { NST_ASSERT( mainItem ); hook->items.Erase( hookItem ); if (hook->items.Size()) return 0; uint result; if (hook->main) { result = 1; mainItem->callback = hook->main; } else { result = 2; items.Erase( mainItem ); } if (hooks == hook) { hooks = hook->next; } else { Hook* it = hooks; while (it->next != hook) it = it->next; it->next = hook->next; } delete hook; return result; } template void Router::RemoveHook(KeyParam key,const typename Hook::Item& item) { if (Item* const mainItem = items.FindSorted( key )) { NST_ASSERT( mainItem->callback.template CodePtr() == &Hook::Invoke ); Hook* const hook = mainItem->callback.template DataPtr(); NST_ASSERT( hook ); if (typename Hook::Item* const hookItem = hook->items.FindSorted( item )) RemoveHook( mainItem, hook, hookItem ); } } template void Router::RemoveHooks(const void* const data) { for (uint i=0; i < items.Size(); ++i) { Item& mainItem = items[i]; if (mainItem.callback.template CodePtr() == &Hook::Invoke) { Hook* const hook = mainItem.callback.template DataPtr(); NST_ASSERT( hook ); for (uint j=0; j < hook->items.Size(); ) { typename Hook::Item& hookItem = hook->items[j]; if (hookItem.VoidPtr() != data) { ++j; } else if (const uint result = RemoveHook( &mainItem, hook, &hookItem )) { i -= (result == 2); break; } } } } } template typename Router::Callback& Router::operator [] (KeyParam key) { Callback& callback = items.AtSorted( key ).callback; if (callback.template CodePtr() == &Hook::Invoke) return callback.template DataPtr()->main; return callback; } template typename Router::Item& Router::Items::GetSorted(KeyParam key,bool& existing) { const uint pos = this->LowerBound( key ); existing = (pos != this->Size() && this->At(pos)->key == key); if (!existing) { this->Insert( this->At(pos), NULL, 1 ); new (static_cast(this->At(pos))) Item( key ); } return *this->At(pos); } template typename Router::Item* Router::Items::FindSorted(KeyParam key) { const uint pos = this->LowerBound( key ); return pos != this->Size() && this->At(pos)->key == key ? this->At(pos) : NULL; } template typename Router::Item& Router::Items::AtSorted(KeyParam key) { const uint pos = this->LowerBound( key ); NST_ASSERT( pos < this->Size() && this->At(pos)->key == key ); return *this->At(pos); } } } nestopia-1.51.1/source/win32/NstCollectionVector.cpp000066400000000000000000000110021411157722000223240ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstCollectionVector.hpp" #ifdef NST_MSVC_OPTIMIZE #pragma optimize("t", on) #endif namespace Nestopia { namespace Collection { Vector::Vector(const uint inSize) : data (inSize ? std::malloc( inSize ) : NULL), capacity (inSize), size (inSize) {} Vector::Vector(const void* const NST_RESTRICT inData,const uint inSize) : data (inSize ? std::memcpy( std::malloc( inSize ), inData, inSize ) : NULL), capacity (inSize), size (inSize) { NST_ASSERT( bool(inData) >= bool(inSize) ); } Vector::Vector(const Vector& base) : data (base.size ? std::memcpy( std::malloc( base.size ), base.data, base.size ) : NULL), capacity (base.size), size (base.size) { } bool Vector::Valid(const void* const it) const { return it >= bytes && it <= bytes + size; } bool Vector::InBound(const void* const it) const { return it >= bytes && it < bytes + size; } void Vector::Assign(const void* const NST_RESTRICT inData,const uint inSize) { size = inSize; if (capacity < inSize) data = std::realloc( data, capacity = inSize ); std::memcpy( data, inData, inSize ); } void Vector::Append(const void* const NST_RESTRICT inData,const uint inSize) { size += inSize; if (capacity < size) data = std::realloc( data, capacity = size * 2 ); std::memcpy( bytes + (size - inSize), inData, inSize ); } void Vector::Insert(void* const offset,const void* const NST_RESTRICT inData,const uint inSize) { NST_ASSERT( Valid(offset) ); if (inSize) { const uint pos = static_cast(offset) - bytes; const uint end = size - pos; size += inSize; if (capacity >= size) { std::memmove( static_cast(offset) + inSize, offset, end ); if (inData) std::memcpy( offset, inData, inSize ); } else { capacity = size * 2; void* const NST_RESTRICT next = std::malloc( capacity ); std::memcpy( next, data, pos ); if (inData) std::memcpy( static_cast(next) + pos, inData, inSize ); std::memcpy( static_cast(next) + pos + inSize, offset, end ); void* tmp = data; data = next; std::free( tmp ); } } } void Vector::Erase(void* const begin,void* const end) { NST_ASSERT( end >= begin && begin >= bytes && end <= bytes + size ); const uint back = (bytes + size) - static_cast(end); size -= static_cast(end) - static_cast(begin); std::memmove( begin, end, back ); } void Vector::Destroy() { if (void* tmp = data) { data = NULL; capacity = 0; size = 0; std::free( tmp ); } } void Vector::operator = (const Vector& base) { Assign( base.data, base.size ); } void Vector::Reserve(const uint inSize) { if (capacity < inSize) data = std::realloc( data, capacity = inSize ); } void Vector::Resize(const uint inSize) { size = inSize; Reserve( inSize ); } void Vector::Grow(const uint inSize) { Resize( size + inSize ); } void Vector::Defrag() { if (capacity != size) data = std::realloc( data, capacity = size ); } void Vector::Import(Vector& base) { void* tmp = data; data = base.data; base.data = NULL; size = base.size; base.size = 0; capacity = base.capacity; base.capacity = 0; std::free( tmp ); } } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif nestopia-1.51.1/source/win32/NstCollectionVector.hpp000066400000000000000000000145061411157722000223450ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_COLLECTION_VECTOR_H #define NST_COLLECTION_VECTOR_H #pragma once #include #include "NstMain.hpp" namespace Nestopia { namespace Collection { template class Vector; template<> class Vector { protected: union { void* data; uchar* bytes; }; uint capacity; uint size; explicit Vector(uint); Vector(const Vector&); Vector(const void* NST_RESTRICT,uint); void operator = (const Vector&); void Assign(const void* NST_RESTRICT,uint); void Append(const void* NST_RESTRICT,uint); void Insert(void*,const void* NST_RESTRICT,uint); void Erase(void*,void*); void Reserve(uint); void Resize(uint); void Grow(uint); bool Valid(const void*) const; bool InBound(const void*) const; Vector() : data(NULL), capacity(0), size(0) {} ~Vector() { NST_ASSERT ( capacity >= size && bool(data) >= bool(size) && bool(data) >= bool(capacity) ); std::free( data ); } void Shrink(uint inSize) { NST_ASSERT( size >= inSize ); size -= inSize; } public: void Destroy(); void Defrag(); void Import(Vector&); bool Empty() const { return !size; } void Clear() { size = 0; } }; template class Vector : public Vector { public: typedef T Type; typedef T* Iterator; typedef const T* ConstIterator; enum { ITEM_SIZE = sizeof(Type) }; Vector() {} Vector(const Type* items,uint count) : Vector(items,ITEM_SIZE * count) {} explicit Vector(uint count) : Vector(count * ITEM_SIZE) {} Vector(const Vector& vector) : Vector(vector) {} Vector& operator = (const Vector& vector) { Vector::operator = (vector); return *this; } void PushBack(const Type& item) { Vector::Append( &item, ITEM_SIZE ); } void PushBack(const Vector& vector) { Vector::Append( vector.data, vector.size ); } void Assign(ConstIterator items,uint count) { Vector::Assign( items, ITEM_SIZE * count ); } void Append(ConstIterator items,uint count) { Vector::Append( items, ITEM_SIZE * count ); } void Insert(Iterator pos,ConstIterator items,uint count) { Vector::Insert( pos, items, ITEM_SIZE * count ); } void Insert(Iterator pos,const Type& item) { Vector::Insert( pos, &item, ITEM_SIZE ); } void Erase(Iterator begin,Iterator end) { Vector::Erase( begin, end ); } void Erase(Iterator offset,uint count=1) { Vector::Erase( offset, offset + count ); } Type& operator [] (uint i) { return static_cast(data)[i]; } const Type& operator [] (uint i) const { return static_cast(data)[i]; } Type* Ptr() { return static_cast(data); } const Type* Ptr() const { return static_cast(data); } Iterator Begin() { return static_cast(data); } ConstIterator Begin() const { return static_cast(data); } Iterator End() { return reinterpret_cast(bytes + size); } ConstIterator End() const { return reinterpret_cast(bytes + size); } Iterator At(uint pos) { return static_cast(data) + pos; } ConstIterator At(uint pos) const { return static_cast(data) + pos; } Type& Front() { NST_ASSERT( size ); return *static_cast(data); } const Type& Front() const { NST_ASSERT( size ); return *static_cast(data); } Type& Back() { NST_ASSERT( size ); return *(reinterpret_cast(bytes + size) - 1); } const Type& Back() const { NST_ASSERT( size ); return *(reinterpret_cast(bytes + size) - 1); } uint Size() const { NST_ASSERT( size % ITEM_SIZE == 0 ); return size / ITEM_SIZE; } uint Length() const { return Size(); } uint Capacity() const { NST_ASSERT( capacity % ITEM_SIZE == 0 ); return capacity / ITEM_SIZE; } void Reserve(uint count) { Vector::Reserve( count * ITEM_SIZE ); } void Resize(uint count) { Vector::Resize( count * ITEM_SIZE ); } void SetTo(uint count) { size = count * ITEM_SIZE; NST_ASSERT( capacity >= size ); } void Grow(uint count=1) { Vector::Grow( count * ITEM_SIZE ); } void Shrink(uint count=1) { Vector::Shrink( count * ITEM_SIZE ); } bool InBound(ConstIterator it) const { return Vector::InBound( it ); } bool Valid(ConstIterator it) const { return Vector::Valid( it ); } template ConstIterator Find(const Value&) const; template Iterator Find(const Value& value) { ConstIterator const it = static_cast*>(this)->Find( value ); return reinterpret_cast(bytes + (reinterpret_cast(it) - bytes)); } }; template template typename Vector::ConstIterator Vector::Find(const Value& value) const { for (ConstIterator it(Ptr()), end(End()); it != end; ++it) if (*it == value) return it; return NULL; } } } #endif nestopia-1.51.1/source/win32/NstCtrlCheckBox.cpp000066400000000000000000000025621411157722000213740ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstWindowCustom.hpp" #include "NstCtrlCheckBox.hpp" namespace Nestopia { namespace Window { namespace Control { void CheckBox::Check(const bool state) const { control.Send( BM_SETCHECK, state ? BST_CHECKED : BST_UNCHECKED, 0 ); } bool CheckBox::Checked() const { return control.Send( BM_GETCHECK, 0, 0 ) == BST_CHECKED; } } } } nestopia-1.51.1/source/win32/NstCtrlCheckBox.hpp000066400000000000000000000030321411157722000213720ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_CTRL_CHECKBOX_H #define NST_CTRL_CHECKBOX_H #pragma once #include "NstCtrlStandard.hpp" namespace Nestopia { namespace Window { namespace Control { class CheckBox : public Generic { public: CheckBox(HWND hWnd=NULL) : Generic( hWnd ) {} CheckBox(HWND hWnd,uint id) : Generic( hWnd, id ) {} void Check(bool=true) const; bool Checked() const; void Uncheck() const { Check( false ); } bool Unchecked() const { return !Checked(); } }; } } } #endif nestopia-1.51.1/source/win32/NstCtrlComboBox.cpp000066400000000000000000000043761411157722000214230ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstWindowCustom.hpp" #include "NstCtrlComboBox.hpp" #include namespace Nestopia { namespace Window { namespace Control { NST_COMPILE_ASSERT( CB_ERR < 0 && CB_ERRSPACE < 0 ); ComboBox::Item::DataProxy::operator ComboBox::Value () const { return ComboBox_GetItemData( item.control, item.index ); } void ComboBox::Item::DataProxy::operator = (Value data) const { ComboBox_SetItemData( item.control, item.index, data ); } void ComboBox::Item::Select() const { ComboBox_SetCurSel( control, index ); } void ComboBox::Item::Erase() const { ComboBox_DeleteString( control, index ); } ComboBox::Item ComboBox::Add(wcstring name) const { NST_ASSERT( name ); return Item( control, ComboBox_AddString( control, name ) ); } void ComboBox::Reserve(uint items,uint lengths) const { control.Send( CB_INITSTORAGE, items, sizeof(wchar_t) * lengths ); } uint ComboBox::Size() const { const int size = ComboBox_GetCount( control ); return NST_MAX(size,0); } void ComboBox::Clear() const { ComboBox_ResetContent( control ); } ComboBox::Item ComboBox::Selection() const { return Item( control, ComboBox_GetCurSel( control ) ); } } } } nestopia-1.51.1/source/win32/NstCtrlComboBox.hpp000066400000000000000000000047141411157722000214240ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_CTRL_COMBOBOX_H #define NST_CTRL_COMBOBOX_H #pragma once #include "NstCtrlStandard.hpp" namespace Nestopia { namespace Window { namespace Control { class ComboBox : public Generic { public: typedef ULONG_PTR Value; private: class Item : public ImplicitBool { class DataProxy { const Item& item; public: DataProxy(const Item& i) : item(i) {} operator Value () const; void operator = (const Value) const; }; const Window::Generic control; const int index; public: Item(Window::Generic w,int i) : control(w), index(i) {} void Erase() const; void Select() const; int GetIndex() const { return index; } bool operator ! () const { return index < 0; } DataProxy Data() const { return *this; } }; public: ComboBox(HWND hWnd=NULL) : Generic( hWnd ) {} ComboBox(HWND hWnd,uint id) : Generic( hWnd, id ) {} void Reserve(uint,uint) const; Item Add(wcstring) const; void Clear() const; Item Selection() const; uint Size() const; Item operator [] (uint i) const { return Item( control, i ); } Item Back() const { return Item( control, Size() - 1 ); } template void Add(T* list,uint count) const { for (uint i=0; i < count; ++i) Add( list[i] ); } }; } } } #endif nestopia-1.51.1/source/win32/NstCtrlEdit.cpp000066400000000000000000000025211411157722000205660ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstWindowCustom.hpp" #include "NstCtrlEdit.hpp" namespace Nestopia { namespace Window { namespace Control { void Edit::SetNumberOnly(const bool numOnly) const { control.Style(ES_NUMBER) = numOnly; } void Edit::Limit(const uint length) const { control.Send( EM_SETLIMITTEXT, length, 0 ); } } } } nestopia-1.51.1/source/win32/NstCtrlEdit.hpp000066400000000000000000000040421411157722000205730ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_CTRL_EDIT_H #define NST_CTRL_EDIT_H #pragma once #include "NstCtrlStandard.hpp" namespace Nestopia { namespace Window { namespace Control { class Edit : public Generic { class TryText { const Edit& edit; public: TryText(const Edit& e) : edit(e) {} template void operator << (const T* t) const { if (*t) edit.Text() << t; } template uint operator >> (T& t) const { return (edit.Text() >> t); } }; public: Edit(HWND hWnd=NULL) : Generic( hWnd ) {} Edit(HWND hWnd,uint id) : Generic( hWnd, id ) {} void Limit(uint) const; void SetNumberOnly(bool=true) const; void Clear() const { Text().Clear(); } template void operator << (const T& t) const { Text() << t; } template uint operator >> (T& t) const { return (Text() >> t); } TryText Try() const { return *this; } }; } } } #endif nestopia-1.51.1/source/win32/NstCtrlListBox.cpp000066400000000000000000000070151411157722000212700ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstWindowCustom.hpp" #include "NstCtrlListBox.hpp" #include namespace Nestopia { namespace Window { namespace Control { NST_COMPILE_ASSERT( LB_ERR < 0 && LB_ERRSPACE < 0 ); ListBox::Item::DataProxy::operator ULONG_PTR () const { return ListBox_GetItemData( item.control, item.index ); } void ListBox::Item::DataProxy::operator = (const ULONG_PTR data) const { ListBox_SetItemData( item.control, item.index, data ); } void ListBox::Item::TextProxy::operator << (wcstring const string) const { NST_ASSERT( string ); const int selection = ListBox_GetCurSel( item.control ); ListBox_DeleteString( item.control, item.index ); ListBox_InsertString( item.control, item.index, string ); if (selection != LB_ERR) ListBox_SetCurSel( item.control, selection ); } void ListBox::Item::Select() const { ListBox_SetCurSel( control, index ); } void ListBox::Item::Remove() const { ListBox_DeleteString( control, index ); } ListBox::Item ListBox::Selection() const { return Item( control, ListBox_GetCurSel( control ) ); } bool ListBox::AnySelection() const { return ListBox_GetCurSel( control ) != LB_ERR; } ListBox::Item ListBox::Add(wcstring const text) const { NST_ASSERT( text ); return Item( control, ListBox_AddString( control, text ) ); } ListBox::Item ListBox::Insert(const uint index,wcstring const text) const { NST_ASSERT( text ); return Item( control, ListBox_InsertString( control, index, text ) ); } uint ListBox::Size() const { const int size = ListBox_GetCount( control ); return NST_MAX(size,0); } void ListBox::Reserve(const uint capacity) const { if (capacity < Size()) control.Send( LB_INITSTORAGE, capacity, 0 ); } void ListBox::Clear() const { ListBox_ResetContent( control ); } ListBox::HScrollBar::HScrollBar(HWND h) : width(0), hWnd(h), hDC(h ? ::GetDC(h) : NULL) { NST_VERIFY( hWnd ); } void ListBox::HScrollBar::Update(wcstring string,uint length) { NST_ASSERT( string || !length ); SIZE size; if (hDC && ::GetTextExtentPoint32( hDC, string, length, &size ) && width < size.cx) width = size.cx; } ListBox::HScrollBar::~HScrollBar() { if (hDC) { ::ReleaseDC( hWnd, hDC ); if (width) { RECT rect; ::GetClientRect( hWnd, &rect ); if (width > rect.right) ListBox_SetHorizontalExtent( hWnd, width ); } } } } } } nestopia-1.51.1/source/win32/NstCtrlListBox.hpp000066400000000000000000000064511411157722000213000ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_CTRL_LISTBOX_H #define NST_CTRL_LISTBOX_H #pragma once #include "NstCtrlStandard.hpp" namespace Nestopia { namespace Window { namespace Control { class ListBox : public Generic { class Item : public ImplicitBool { class DataProxy { const Item& item; public: DataProxy(const Item& i) : item(i) {} operator ULONG_PTR () const; void operator = (ULONG_PTR) const; }; class TextProxy { const Item& item; public: TextProxy(const Item& i) : item(i) {} void operator << (wcstring) const; template uint operator >> (T&) const; }; const Window::Generic control; const int index; public: Item(Window::Generic w,uint i) : control(w), index(i) {} void Remove() const; void Select() const; int GetIndex() const { return index; } bool operator ! () const { return index < 0; } DataProxy Data() const { return *this; } TextProxy Text() const { return *this; } }; public: ListBox(HWND hWnd=NULL) : Generic( hWnd ) {} ListBox(HWND hWnd,uint id) : Generic( hWnd, id ) {} Item Add(wcstring) const; Item Insert(uint,wcstring) const; Item Selection() const; bool AnySelection() const; void Reserve(uint) const; uint Size() const; void Clear() const; template void Add(T* list,uint count) const { Reserve( count ); for (uint i=0; i < count; ++i) Add( list[i] ); } Item operator [] (uint i) const { return Item( control, i ); } class HScrollBar { long width; HWND const hWnd; HDC const hDC; public: HScrollBar(HWND); ~HScrollBar(); void Update(wcstring,uint); }; }; template uint ListBox::Item::TextProxy::operator >> (T& string) const { NST_VERIFY( item.control ); const int size = item.control.Send( LB_GETTEXTLEN, item.index, 0 ); if (size > 0) { string.Resize( size ); if (item.control.Send( LB_GETTEXT, item.index, static_cast(string.Ptr()) ) > 0) return string.Validate(); } string.Clear(); return 0; } } } } #endif nestopia-1.51.1/source/win32/NstCtrlListView.cpp000066400000000000000000000150531411157722000214530ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstWindowCustom.hpp" #include "NstCtrlListView.hpp" #include namespace Nestopia { namespace Window { namespace Control { void ListView::ColumnsProxy::Insert(const uint index,wcstring const text) const { NST_ASSERT( text ); LVCOLUMN lvColumn; lvColumn.mask = LVCF_FMT|LVCF_TEXT; lvColumn.fmt = LVCFMT_LEFT; lvColumn.pszText = const_cast( text ); ListView_InsertColumn( control, index, &lvColumn ); } void ListView::ColumnsProxy::Align() const { for (int i=0; ListView_SetColumnWidth( control, i, LVSCW_AUTOSIZE_USEHEADER ); ++i) { const int header = ListView_GetColumnWidth( control, i ); ListView_SetColumnWidth( control, i, LVSCW_AUTOSIZE ); const int width = ListView_GetColumnWidth( control, i ); if (width < header) ListView_SetColumnWidth( control, i, header ); } } void ListView::ColumnsProxy::GetOrder(int* const array,const uint count) const { ListView_GetColumnOrderArray( control, count, array ); } uint ListView::ColumnsProxy::GetIndex(const uint index) const { LVCOLUMN lvColumn; lvColumn.mask = LVCF_ORDER; ListView_GetColumn( control, index, &lvColumn ); return NST_MAX(lvColumn.iOrder,0); } void ListView::ColumnsProxy::Clear() const { while (ListView_DeleteColumn( control, 0 )); } ListView::StyleExProxy::operator uint () const { return ListView_GetExtendedListViewStyle( control ); } void ListView::StyleExProxy::operator = (const uint style) const { ListView_SetExtendedListViewStyle( control, style ); } void ListView::Item::TextProxy::operator << (wcstring const text) const { ListView_SetItemText( item.control, item.index, index, const_cast(text) ); } void ListView::Item::TextProxy::GetText(Buffer& buffer) const { NST_ASSERT( buffer.Empty() ); LVITEM lvItem; lvItem.iSubItem = index; do { buffer.Resize( buffer.Length() + BLOCK_SIZE ); lvItem.cchTextMax = buffer.Length() + 1; lvItem.pszText = buffer.Ptr(); lvItem.cchTextMax = item.control.Send( LVM_GETITEMTEXT, item.index, &lvItem ); } while (*(buffer.Ptr() + buffer.Length())); buffer.ShrinkTo( lvItem.cchTextMax ); } void ListView::Item::DataProxy::operator = (const LPARAM data) const { LVITEM lvItem; lvItem.mask = LVIF_PARAM; lvItem.iItem = item.index; lvItem.iSubItem = 0; lvItem.lParam = data; ListView_SetItem( item.control, &lvItem ); } ListView::Item::DataProxy::operator LPARAM () const { LVITEM lvItem; lvItem.mask = LVIF_PARAM; lvItem.iItem = item.index; lvItem.iSubItem = 0; lvItem.lParam = 0; ListView_GetItem( item.control, &lvItem ); return lvItem.lParam; } bool ListView::Item::Delete() const { return index != ~0U ? ListView_DeleteItem( control, index ) : false; } void ListView::Item::Select(const bool state) const { ListView_SetItemState( control, index, state ? LVIS_SELECTED : 0, LVIS_SELECTED ); } void ListView::Item::Check(const bool state) const { ListView_SetCheckState( control, index, state ); } bool ListView::Item::Checked() const { return ListView_GetCheckState( control, index ); } void ListView::Item::Show() const { ListView_EnsureVisible( control, index, false ); } ListView::Item ListView::Selection() const { return Item( control, ListView_GetNextItem( control, -1, LVNI_SELECTED ) ); } int ListView::Add(GenericString text,const LPARAM data,const bool checked) const { HeapString tmp; LVITEM lvItem; if (text.Length()) { if (text.NullTerminated()) { lvItem.pszText = const_cast(text.Ptr()); } else { tmp = text; lvItem.pszText = tmp.Ptr(); } } else { lvItem.pszText = LPSTR_TEXTCALLBACK; } lvItem.mask = LVIF_TEXT; if (data) lvItem.mask |= LVIF_PARAM; lvItem.iItem = INT_MAX; lvItem.iSubItem = 0; lvItem.lParam = data; const int index = ListView_InsertItem( control, &lvItem ); if (checked) ListView_SetCheckState( control, index, true ); return index; } uint ListView::Size() const { const int count = ListView_GetItemCount( control ); return NST_MAX(count,0); } void ListView::Clear() const { ListView_DeleteAllItems( control ); } void ListView::Reserve(const uint capacity) const { if (capacity > Size()) ListView_SetItemCount( control, capacity ); } void ListView::SetBkColor(const uint color) const { ListView_SetBkColor( control, color ); } void ListView::SetTextColor(const uint color) const { ListView_SetTextColor( control, color ); } void ListView::SetTextBkColor(const uint color) const { ListView_SetTextBkColor( control, color ); } bool ListView::HitTest(const uint x,const uint y) const { LVHITTESTINFO lvHitTestInfo; lvHitTestInfo.pt.x = x; lvHitTestInfo.pt.y = y; ::ScreenToClient( control, &lvHitTestInfo.pt ); return ListView_HitTest( control, &lvHitTestInfo ) != -1; } void ListView::Sort(const SortFunction& sortFunction) const { if (Size() > 1) ListView_SortItems( control, SortProc, reinterpret_cast(&sortFunction) ); } int CALLBACK ListView::SortProc(LPARAM obj1,LPARAM obj2,LPARAM ref) { return (*reinterpret_cast(ref)) ( reinterpret_cast( obj1 ), reinterpret_cast( obj2 ) ); } } } } nestopia-1.51.1/source/win32/NstCtrlListView.hpp000066400000000000000000000107271411157722000214630ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_CTRL_LISTVIEW_H #define NST_CTRL_LISTVIEW_H #pragma once #include "NstCtrlStandard.hpp" #include "NstString.hpp" namespace Nestopia { namespace Window { namespace Control { class ListView : public Generic { class StyleExProxy { const Window::Generic control; public: StyleExProxy(Window::Generic w) : control(w) {} operator uint () const; void operator = (uint) const; }; class ColumnsProxy { const Window::Generic control; public: ColumnsProxy(Window::Generic w) : control(w) {} void Insert(uint,wcstring) const; void GetOrder(int*,uint) const; uint GetIndex(uint) const; void Align() const; void Clear() const; template void Set(const T (&list)[N]) const { Clear(); for (uint i=0; i < N; ++i) Insert( i, list[i] ); } }; class Item { class TextProxy { typedef HeapString Buffer; enum { BLOCK_SIZE = 255 }; const Item& item; const uint index; void GetText(Buffer&) const; public: TextProxy(const Item& i,uint s) : item(i), index(s) {} void operator << (wcstring) const; template uint operator >> (T& string) const { Buffer buffer; GetText( buffer ); string = buffer; return string.Length(); } }; class DataProxy { const Item& item; public: DataProxy(const Item& i) : item(i) {} void operator = (LPARAM) const; operator LPARAM () const; operator void* () const { return reinterpret_cast( operator LPARAM() ); } void operator = (const void* data) const { operator = (reinterpret_cast(data)); } }; const Window::Generic control; const uint index; public: Item(Window::Generic w,uint i) : control(w), index(i) {} bool Delete() const; void Select(bool=true) const; void Show() const; void Check(bool=true) const; bool Checked() const; uint GetIndex() const { return index; } TextProxy Text(uint i=0) const { return TextProxy( *this, i ); } DataProxy Data() const { return *this; } }; typedef Object::Delegate SortFunction; void Sort(const SortFunction&) const; static int CALLBACK SortProc(LPARAM,LPARAM,LPARAM); public: uint Size() const; void Clear() const; void Reserve(uint) const; int Add(GenericString = GenericString(),LPARAM=0,bool=false) const; Item Selection() const; void SetBkColor(uint) const; void SetTextColor(uint) const; void SetTextBkColor(uint) const; bool HitTest(uint,uint) const; ListView(HWND hWnd=NULL) : Generic( hWnd ) {} ListView(HWND hWnd,uint id) : Generic( hWnd, id ) {} ColumnsProxy Columns() const { return control; } StyleExProxy StyleEx() const { return control; } Item operator [] (uint index) const { return Item( control, index ); } template void Sort(Data* data,Code code) const { Sort( SortFunction(data,code) ); } int Add(GenericString name,const void* const data,const bool checked=false) const { return Add( name, reinterpret_cast(data), checked ); } }; } } } #endif nestopia-1.51.1/source/win32/NstCtrlRadioButton.hpp000066400000000000000000000025651411157722000221500ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_CTRL_RADIOBUTTON_H #define NST_CTRL_RADIOBUTTON_H #pragma once #include "NstCtrlCheckBox.hpp" namespace Nestopia { namespace Window { namespace Control { class RadioButton : public CheckBox { public: RadioButton(HWND hWnd=NULL) : CheckBox( hWnd ) {} RadioButton(HWND hWnd,uint id) : CheckBox( hWnd, id ) {} }; } } } #endif nestopia-1.51.1/source/win32/NstCtrlSlider.cpp000066400000000000000000000030111411157722000211160ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstWindowCustom.hpp" #include "NstCtrlSlider.hpp" #include namespace Nestopia { namespace Window { namespace Control { Slider::PositionProxy::operator int () const { return control.Send( TBM_GETPOS, 0, 0 ); } void Slider::PositionProxy::operator = (const int pos) const { control.Send( TBM_SETPOS, true, pos ); } void Slider::SetRange(const int minimum,const int maximum) const { control.Send( TBM_SETRANGE, false, MAKELONG(minimum,maximum) ); } } } } nestopia-1.51.1/source/win32/NstCtrlSlider.hpp000066400000000000000000000032231411157722000211300ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_CTRL_SLIDER_H #define NST_CTRL_SLIDER_H #pragma once #include "NstCtrlStandard.hpp" namespace Nestopia { namespace Window { namespace Control { class Slider : public Generic { class PositionProxy { const Window::Generic control; public: PositionProxy(Window::Generic w) : control(w) {} operator int () const; void operator = (int) const; }; public: Slider(HWND hWnd=NULL) : Generic( hWnd ) {} Slider(HWND hWnd,uint id) : Generic( hWnd, id ) {} void SetRange(int,int) const; PositionProxy Position() const { return control; } }; } } } #endif nestopia-1.51.1/source/win32/NstCtrlStandard.cpp000066400000000000000000000066221411157722000214470ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstWindowCustom.hpp" #include "NstWindowParam.hpp" #include "NstCtrlStandard.hpp" #include "NstString.hpp" namespace Nestopia { namespace Window { namespace Control { bool Generic::FixedFont() const { bool fixed = false; if (HFONT const hFontNew = reinterpret_cast(control.Send( WM_GETFONT ))) { if (HDC const hdc = ::GetDC( control )) { if (HFONT const hFontOld = reinterpret_cast(::SelectObject( hdc, hFontNew ))) { TEXTMETRIC tm; if (::GetTextMetrics( hdc, &tm ) && !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH)) fixed = true; ::SelectObject( hdc, hFontOld ); } ::ReleaseDC( control, hdc ); } } return fixed; } Point Generic::GetMaxTextSize() const { Point size; if (HFONT const hFontNew = reinterpret_cast(control.Send( WM_GETFONT ))) { if (HDC const hdc = ::GetDC( control )) { if (HFONT const hFontOld = reinterpret_cast(::SelectObject( hdc, hFontNew ))) { TEXTMETRIC tm; if (::GetTextMetrics( hdc, &tm )) { const uint width = control.Coordinates().Width(); HeapString text; control.Text() >> text; for (wcstring s=text.Ptr(), n=s; *s; s=n, ++n) { while (*n && *n != '\n') ++n; SIZE tsize; if (::GetTextExtentExPoint( hdc, s, n-s, width, NULL, NULL, &tsize )) size.x = NST_MAX(size.x,tsize.cx); size.y += tm.tmHeight; } if (size.x) size.x += 4*4; if (size.y) size.y += 4*2; } ::SelectObject( hdc, hFontOld ); } ::ReleaseDC( control, hdc ); } } return size; } NotificationHandler::NotificationHandler(const uint id,MsgHandler& m) : control(id), msgHandler(m) { Initialize(); } NotificationHandler::~NotificationHandler() { msgHandler.Hooks().Remove( this ); } void NotificationHandler::Initialize() { msgHandler.Hooks().Add( WM_NOTIFY, this, &NotificationHandler::OnNotify ); } void NotificationHandler::OnNotify(Param& param) { NST_ASSERT( param.lParam ); const NMHDR& nmhdr = *reinterpret_cast(param.lParam); if (control == nmhdr.idFrom) { Items::iterator it(items.find( nmhdr.code )); if (it != items.end()) it->second( nmhdr ); } } } } } nestopia-1.51.1/source/win32/NstCtrlStandard.hpp000066400000000000000000000064531411157722000214560ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_CTRL_STANDARD_H #define NST_CTRL_STANDARD_H #pragma once #include #include "NstWindowGeneric.hpp" namespace Nestopia { namespace Window { namespace Control { class Generic { public: bool FixedFont() const; Point GetMaxTextSize() const; protected: Window::Generic control; public: Generic(HWND hWnd=NULL) : control(hWnd) {} Generic(HWND hWnd,uint id) : control( ::GetDlgItem( hWnd, id ) ) { NST_VERIFY( control ); } void Enable(bool state=true) const { control.Enable( state ); } void Disable() const { Enable( false ); } bool Enabled() const { return control.Enabled(); } void Redraw() const { control.Redraw(); } Window::Generic GetWindow() const { return control; } HWND GetHandle() const { return control; } Window::Generic::Stream Text() const { return control; } }; class NotificationHandler { public: template struct Entry { uint msg; void (T::*function)(const NMHDR&); }; private: typedef Object::Delegate Callback; typedef std::map Items; const uint control; Items items; MsgHandler& msgHandler; void Initialize(); void OnNotify(Param&); template void Add(T*,const Entry*,uint); Callback& operator () (uint id) { return items[id]; } public: NotificationHandler(uint,MsgHandler&); template NotificationHandler(uint,MsgHandler&,T*,const Entry(&)[N]); ~NotificationHandler(); template void Add(T* data,const Entry(&entries)[N]) { Add( data, entries, N ); } }; template NotificationHandler::NotificationHandler ( const uint id, MsgHandler& m, T* const data, const Entry(&entries)[N] ) : control(id), msgHandler(m) { Initialize(); Add( data, entries, N ); } template void NotificationHandler::Add(T* const object,const Entry* it,const uint count) { for (const Entry* const end = it + count; it != end; ++it) (*this)( it->msg ).Set( object, it->function ); } } } } #endif nestopia-1.51.1/source/win32/NstCtrlTreeView.cpp000066400000000000000000000077661411157722000214530ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "language/resource.h" #include "NstApplicationException.hpp" #include "NstResourceBitmap.hpp" #include "NstWindowCustom.hpp" #include "NstCtrlTreeView.hpp" #include namespace Nestopia { namespace Window { namespace Control { TreeView::ImageList::ImageList(const uint x,const uint y,const uint selected,const uint unselected) : handle(ImageList_Create(x,y,ILC_COLOR16|ILC_MASK,0,2)) { if (handle) { try { if ( ImageList_AddMasked( static_cast(handle), Resource::Bitmap( selected ), 0 ) == -1 || ImageList_AddMasked( static_cast(handle), Resource::Bitmap( unselected ), 0 ) == -1 ) throw Application::Exception( IDS_ERR_FAILED, L"ImageList_Add()" ); } catch (const Application::Exception& exception) { ImageList_Destroy( static_cast(handle) ); throw exception; } } else { throw Application::Exception( IDS_ERR_FAILED, L"ImageList_Create()" ); } } TreeView::ImageList::~ImageList() { if (handle) ImageList_Destroy( static_cast(handle) ); } void TreeView::Item::Select() const { NST_VERIFY( hItem ); TreeView_SelectItem( root, static_cast(hItem) ); } void TreeView::SetImageList(const ImageList& imageList) const { NST_VERIFY( imageList.handle ); TreeView_SetImageList( control, static_cast(imageList.handle), TVSIL_NORMAL ); } void TreeView::Add(const GenericString text) const { TVINSERTSTRUCT tv; tv.hParent = TVI_ROOT; tv.hInsertAfter = TVI_LAST; tv.item.mask = TVIF_TEXT; tv.item.pszText = const_cast( text.Ptr() ); tv.item.cchTextMax = text.Length(); if (TreeView_GetImageList( control, TVSIL_NORMAL )) { tv.item.mask = TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE; tv.item.iImage = ImageList::UNSELECTED; tv.item.iSelectedImage = ImageList::SELECTED; } TreeView_InsertItem( control, &tv ); } TreeView::Item TreeView::operator [] (const uint index) const { HTREEITEM hItem = TreeView_GetRoot( control ); for (uint i=index; i; --i) hItem = TreeView_GetNextSibling( control, hItem ); return Item( control, hItem, hItem ? int(index) : -1 ); } int TreeView::GetIndex(void* const handle) const { int index = -1; if (handle) { index = 0; for (HTREEITEM hItem = TreeView_GetRoot( control ); hItem && hItem != static_cast(handle); ++index) hItem = TreeView_GetNextSibling( control, hItem ); } return index; } TreeView::Item TreeView::Selection() const { HTREEITEM const hSelection = TreeView_GetSelection( control ); return Item( control, hSelection, GetIndex( hSelection ) ); } void TreeView::SetBackgroundColor(const uint color) const { TreeView_SetBkColor( control, color ); } void TreeView::SetTextColor(const uint color) const { TreeView_SetTextColor( control, color ); } } } } nestopia-1.51.1/source/win32/NstCtrlTreeView.hpp000066400000000000000000000041361411157722000214440ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_CTRL_TREEVIEW_H #define NST_CTRL_TREEVIEW_H #pragma once #include "NstCtrlStandard.hpp" #include "NstString.hpp" namespace Nestopia { namespace Window { namespace Control { class TreeView : public Generic { class Item { const Window::Generic root; void* const hItem; const int index; public: Item(Window::Generic w,void* h,int i) : root(w), hItem(h), index(i) {} void Select() const; int GetIndex() const { return index; } }; public: TreeView(HWND hWnd=NULL) : Generic( hWnd ) {} TreeView(HWND hWnd,uint id) : Generic( hWnd, id ) {} class ImageList { friend class TreeView; void* const handle; enum {SELECTED,UNSELECTED}; public: ImageList(uint,uint,uint,uint); ~ImageList(); }; void SetImageList(const ImageList&) const; void Add(GenericString) const; Item Selection() const; void SetBackgroundColor(uint) const; void SetTextColor(uint) const; int GetIndex(void*) const; Item operator [] (uint) const; }; } } } #endif nestopia-1.51.1/source/win32/NstDialogAbout.cpp000066400000000000000000000050001411157722000212410ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "resource/resource.h" #include "NstResourceCursor.hpp" #include "NstWindowParam.hpp" #include "NstDialogAbout.hpp" #include "NstApplicationInstance.hpp" #include namespace Nestopia { namespace Window { struct About::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; }; const MsgHandler::Entry About::Handlers::messages[] = { { WM_INITDIALOG, &About::OnInitDialog }, { WM_SETCURSOR, &About::OnSetCursor } }; const MsgHandler::Entry About::Handlers::commands[] = { { IDC_ABOUT_URL, &About::OnCmdClick } }; About::About() : dialog(IDD_ABOUT,this,Handlers::messages,Handlers::commands) {} ibool About::OnInitDialog(Param&) { dialog.SetItemIcon( IDC_ABOUT_ICON, Application::Instance::GetIconStyle() == Application::Instance::ICONSTYLE_NES ? IDI_APP : IDI_APP_J ); dialog.Control( IDC_ABOUT_NAMEVERSION ).Text() << "Nestopia UE 1.51.1"; return true; } ibool About::OnSetCursor(Param& param) { HCURSOR hCursor; hCursor = Resource::Cursor::GetArrow(); ::SetCursor( hCursor ); ::SetWindowLongPtr( dialog, DWLP_MSGRESULT, true ); return true; } ibool About::OnCmdClick(Param& param) { if (param.Button().Clicked()) { HeapString cmd; if (dialog.Control( param.Button().GetId() ).Text() >> cmd) { cmd.Insert( 0, L"http://" ); ::ShellExecute( NULL, L"open", cmd.Ptr(), NULL, NULL, SW_SHOWNORMAL ); } } return true; } } } nestopia-1.51.1/source/win32/NstDialogAbout.hpp000066400000000000000000000026221411157722000212550ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIALOG_ABOUT_H #define NST_DIALOG_ABOUT_H #pragma once #include "NstWindowDialog.hpp" namespace Nestopia { namespace Window { class About { public: About(); private: struct Handlers; ibool OnInitDialog (Param&); ibool OnSetCursor (Param&); ibool OnCmdClick (Param&); Dialog dialog; public: void Open() { dialog.Open(); } }; } } #endif nestopia-1.51.1/source/win32/NstDialogAutoSaver.cpp000066400000000000000000000062621411157722000221130ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstApplicationInstance.hpp" #include "NstWindowParam.hpp" #include "NstManagerPaths.hpp" #include "NstDialogAutoSaver.hpp" namespace Nestopia { namespace Window { AutoSaver::Settings::Settings() : interval(1), notify(true) {} struct AutoSaver::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; }; const MsgHandler::Entry AutoSaver::Handlers::messages[] = { { WM_INITDIALOG, &AutoSaver::OnInitDialog } }; const MsgHandler::Entry AutoSaver::Handlers::commands[] = { { IDC_AUTOSAVE_CLEAR, &AutoSaver::OnCmdClear }, { IDC_AUTOSAVE_BROWSE, &AutoSaver::OnCmdBrowse }, { IDOK, &AutoSaver::OnCmdOk } }; AutoSaver::AutoSaver(const Managers::Paths& p) : dialog(IDD_AUTOSAVER,this,Handlers::messages,Handlers::commands), paths(p) {} AutoSaver::~AutoSaver() { } const Path AutoSaver::GetStateFile() const { return Application::Instance::GetFullPath( settings.stateFile ); } ibool AutoSaver::OnInitDialog(Param&) { dialog.Edit(IDC_AUTOSAVE_FILE) << settings.stateFile.Ptr(); dialog.Edit(IDC_AUTOSAVE_TIME).Limit(2); dialog.Edit(IDC_AUTOSAVE_TIME) << settings.interval; dialog.CheckBox(IDC_AUTOSAVE_ENABLE_MSG).Check( settings.notify ); return true; } ibool AutoSaver::OnCmdClear(Param& param) { if (param.Button().Clicked()) dialog.Edit(IDC_AUTOSAVE_FILE).Clear(); return true; } ibool AutoSaver::OnCmdBrowse(Param& param) { if (param.Button().Clicked()) { Path tmp; dialog.Edit(IDC_AUTOSAVE_FILE) >> tmp; dialog.Edit(IDC_AUTOSAVE_FILE).Try() << paths.BrowseSave( Managers::Paths::File::STATE, Managers::Paths::SUGGEST, Application::Instance::GetFullPath(tmp) ).Ptr(); } return true; } ibool AutoSaver::OnCmdOk(Param& param) { if (param.Button().Clicked()) { dialog.Edit(IDC_AUTOSAVE_FILE) >> settings.stateFile; dialog.Edit(IDC_AUTOSAVE_TIME) >> settings.interval; settings.notify = dialog.CheckBox(IDC_AUTOSAVE_ENABLE_MSG).Checked(); paths.FixFile( Managers::Paths::File::STATE, settings.stateFile ); dialog.Close(); } return true; } } } nestopia-1.51.1/source/win32/NstDialogAutoSaver.hpp000066400000000000000000000035711411157722000221200ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIALOG_AUTOSAVER_H #define NST_DIALOG_AUTOSAVER_H #pragma once #include "NstWindowDialog.hpp" namespace Nestopia { namespace Window { class AutoSaver { public: explicit AutoSaver(const Managers::Paths&); ~AutoSaver(); enum { DEFAULT_SAVE_SLOT = 0 }; const Path GetStateFile() const; private: struct Handlers; struct Settings { Settings(); uint interval; bool notify; Path stateFile; }; ibool OnInitDialog (Param&); ibool OnCmdBrowse (Param&); ibool OnCmdClear (Param&); ibool OnCmdOk (Param&); Dialog dialog; const Managers::Paths& paths; Settings settings; public: void Open() { dialog.Open(); } uint GetInterval() const { return settings.interval * 60 * 1000; } bool ShouldNotify() const { return settings.notify; } }; } } #endif nestopia-1.51.1/source/win32/NstDialogBarcodeReader.cpp000066400000000000000000000057311411157722000226640ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstWindowParam.hpp" #include "NstManagerEmulator.hpp" #include "NstDialogBarcodeReader.hpp" namespace Nestopia { namespace Window { struct BarcodeReader::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; }; const MsgHandler::Entry BarcodeReader::Handlers::messages[] = { { WM_INITDIALOG, &BarcodeReader::OnInitDialog } }; const MsgHandler::Entry BarcodeReader::Handlers::commands[] = { { IDC_BARCODE_TRANSFER, &BarcodeReader::OnCmdTransfer }, { IDC_BARCODE_RANDOM, &BarcodeReader::OnCmdRandom }, { IDC_BARCODE_DIGITS, &BarcodeReader::OnCmdDigits } }; BarcodeReader::BarcodeReader(Managers::Emulator& emulator,String::Heap& string) : dialog (IDD_BARCODE,this,Handlers::messages,Handlers::commands), barcodeReader (emulator), code (string) { } ibool BarcodeReader::OnInitDialog(Param&) { Control::Edit edit( dialog.Edit(IDC_BARCODE_DIGITS) ); edit.Limit( Nes::BarcodeReader::MAX_DIGITS ); if (code.Length()) edit << code.Ptr(); if (!barcodeReader.CanTransfer()) { edit.Disable(); dialog.Control( IDC_BARCODE_RANDOM ).Disable(); dialog.Control( IDC_BARCODE_TRANSFER ).Disable(); } return true; } ibool BarcodeReader::OnCmdDigits(Param& param) { if (param.Edit().Changed()) dialog.Edit( IDC_BARCODE_DIGITS ) >> code; return true; } ibool BarcodeReader::OnCmdRandom(Param& param) { if (param.Button().Clicked()) { char string[Nes::BarcodeReader::MAX_DIGITS+1]; if (barcodeReader.Randomize( string )) dialog.Edit( IDC_BARCODE_DIGITS ) << string; } return true; } ibool BarcodeReader::OnCmdTransfer(Param& param) { if (param.Button().Clicked() && barcodeReader.IsDigitsSupported( code.Length() )) { barcodeReader.Transfer( code.Ptr(), code.Length() ); dialog.Close(); } return true; } } } nestopia-1.51.1/source/win32/NstDialogBarcodeReader.hpp000066400000000000000000000031561411157722000226700ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIALOG_BARCODEREADER_H #define NST_DIALOG_BARCODEREADER_H #pragma once #include "NstWindowDialog.hpp" #include "../core/api/NstApiBarcodeReader.hpp" namespace Nestopia { namespace Window { class BarcodeReader { public: BarcodeReader(Managers::Emulator&,String::Heap&); private: struct Handlers; ibool OnInitDialog (Param&); ibool OnCmdDigits (Param&); ibool OnCmdRandom (Param&); ibool OnCmdTransfer (Param&); Dialog dialog; Nes::BarcodeReader barcodeReader; String::Heap& code; public: void Open() { dialog.Open(); } }; } } #endif nestopia-1.51.1/source/win32/NstDialogBrowse.cpp000066400000000000000000000071341411157722000214420ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstObjectPod.hpp" #include "NstApplicationInstance.hpp" #include "NstDialogBrowse.hpp" #include #include namespace Nestopia { namespace Window { const Path Browser::OpenFile(wchar_t* const filter,const Path dir,const Path ext) { for (uint i=0; filter[i]; ++i) { if (filter[i] == '\t') filter[i] = '\0'; } Path path; path.Reserve( MAX_PATH*2 ); Object::Pod ofn; ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = Application::Instance::GetActiveWindow(); ofn.lpstrFile = path.Ptr(); ofn.nMaxFile = path.Capacity(); ofn.lpstrInitialDir = dir.Length() ? dir.Ptr() : L"."; ofn.Flags = OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY; if (filter) { ofn.lpstrFilter = filter; ofn.nFilterIndex = 1; } if (ext.Length()) ofn.lpstrDefExt = ext.Ptr(); if (::GetOpenFileName( &ofn )) path.Validate(); else path.Clear(); return path; } const Path Browser::SaveFile(wchar_t* const filter,Path initial) { Path path; path.Reserve( MAX_PATH*2 ); const Path extension( initial.Extension() ); if (initial.File().Length() && initial.File()[0] != '.') path = initial.File(); initial.File().Clear(); Object::Pod ofn; ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = Application::Instance::GetActiveWindow(); ofn.lpstrFile = path.Ptr(); ofn.nMaxFile = path.Capacity(); ofn.lpstrInitialDir = initial.Length() ? initial.Ptr() : L"."; ofn.Flags = OFN_EXPLORER|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY; if (filter) { for (uint i=0; filter[i]; ++i) { if (filter[i] == '\t') filter[i] = '\0'; } ofn.lpstrFilter = filter; ofn.nFilterIndex = 1; } if (extension.Length()) ofn.lpstrDefExt = extension.Ptr(); if (::GetSaveFileName( &ofn )) path.Validate(); else path.Clear(); return path; } const Path Browser::SelectDirectory() { Path path; path.Reserve( MAX_PATH*2 ); Object::Pod bi; bi.hwndOwner = Application::Instance::GetActiveWindow(); bi.pszDisplayName = path.Ptr(); bi.ulFlags = BIF_RETURNONLYFSDIRS; if (LPITEMIDLIST const idl = ::SHBrowseForFolder( &bi )) { if (::SHGetPathFromIDList( idl, path.Ptr() ) && path.Validate()) path.MakePretty( true ); else path.Clear(); IMalloc* pMalloc; if (SUCCEEDED(::SHGetMalloc( &pMalloc ))) { pMalloc->Free( idl ); pMalloc->Release(); } } else { path.Clear(); } return path; } } } nestopia-1.51.1/source/win32/NstDialogBrowse.hpp000066400000000000000000000024521411157722000214450ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIALOG_BROWSE_H #define NST_DIALOG_BROWSE_H #pragma once #include "NstString.hpp" namespace Nestopia { namespace Window { namespace Browser { const Path OpenFile(wchar_t*,Path,Path); const Path SaveFile(wchar_t*,Path=Path()); const Path SelectDirectory(); } } } #endif nestopia-1.51.1/source/win32/NstDialogCheats.cpp000066400000000000000000001300201411157722000213770ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstIoStream.hpp" #include "NstResourceString.hpp" #include "NstWindowParam.hpp" #include "NstWindowDropFiles.hpp" #include "NstWindowUser.hpp" #include "NstManagerPaths.hpp" #include "NstDialogCheats.hpp" #include "NstApplicationInstance.hpp" #include "../core/NstXml.hpp" #include "../core/api/NstApiCartridge.hpp" #include namespace Nestopia { namespace Window { class Cheats::MainDialog { public: MainDialog(Codes&,Codes&,bool&,bool&,Searcher&,Managers::Emulator&,const Managers::Paths&); private: struct Handlers; class Section { public: Section(uint,Dialog&,Codes&,const bool&,bool&,Searcher&,Managers::Emulator&,const Managers::Paths&); void UpdateHexView() const; private: struct Handlers; class CodeDialog { public: struct Context { Code code; bool edit; bool& hex; Searcher& searcher; Context(bool& h,Searcher& s) : edit(false), hex(h), searcher(s) {} }; CodeDialog(Managers::Emulator&,const Managers::Paths&,Context&); private: struct Handlers; ibool OnInitDialog(Param&); ibool OnDestroy(Param&); ibool OnCmdSubmit (Param&); ibool OnCmdValidate (Param&); ibool OnCmdGameCurrent (Param&); ibool OnCmdGameBrowse (Param&); ibool OnCmdHex (Param&); ibool OnCmdType (Param&); ibool OnSearchType (Param&); ibool OnCmdReset (Param&); void OnItemChanged(const NMHDR&); void UpdateInput() const; void UpdateHexView(bool) const; void UpdateSearchList() const; bool GetRawCode (NesCode&) const; bool GetGenieCode (NesCode&) const; bool GetRockyCode (NesCode&) const; void SetRawCode (const NesCode&) const; void SetGenieCode (const NesCode&) const; void SetRockyCode (const NesCode&) const; uint GetSearchValue(uint) const; void SetSearchValue(uint,uint) const; void AddSearchEntry(Control::ListView,uint) const; Context& context; Managers::Emulator& emulator; const Managers::Paths& paths; Dialog dialog; Control::NotificationHandler notificationHandler; public: bool Open() { return dialog.Open(); } }; enum { ADD, EDIT, REMOVE, IMPORT, EXPORT, CLEAR, NUM_CONTROLS }; enum Column { COLUMN_CODE, COLUMN_ADDRESS, COLUMN_VALUE, COLUMN_COMPARE, COLUMN_GAME, COLUMN_DESCRIPTION }; enum { NUM_COLUMNS = 6 }; int Sorter(const void*,const void*); void RefreshListView(); void SetCode(int=-1); void AddCodes(const Codes&); void AddToListView(const Code&) const; void OnInitDialog (Param&); void OnDropFiles (Param&); ibool OnCmdAdd (Param&); ibool OnCmdEdit (Param&); ibool OnCmdRemove (Param&); ibool OnCmdExport (Param&); ibool OnCmdImport (Param&); ibool OnCmdClear (Param&); void OnKeyDown (const NMHDR&); void OnItemChanged (const NMHDR&); void OnInsertItem (const NMHDR&); void OnDeleteItem (const NMHDR&); void OnColumnClick (const NMHDR&); const uint id; Codes& codes; const bool& showHexMainDialog; bool& showHexSubDialogs; Searcher& searcher; const Dialog& dialog; Control::NotificationHandler notificationHandler; Control::ListView listView; Control::Generic controls[NUM_CONTROLS]; Column sortColumns[NUM_COLUMNS]; Managers::Emulator& emulator; const Managers::Paths& paths; }; ibool OnInitDialog (Param&); ibool OnCmdShowHex (Param&); Dialog dialog; Section permanentView; Section temporaryView; bool& showHex; public: void Open() { dialog.Open(); } }; Cheats::Cheats(Managers::Emulator& e,const Configuration& cfg,const Managers::Paths& p) : paths ( p ), emulator ( e ) { Configuration::ConstSection cheats( cfg["cheats"] ); showHexMainDialog = cheats["show-hex-main-view"].Yes(); showHexSubDialogs = cheats["show-hex-code-view"].Yes(); for (uint i=0; i < MAX_CODES; ++i) { if (Configuration::ConstSection cheat=cheats["cheat"][i]) { Code code; uint data = cheat["address"].Int(); if (data > 0xFFFF) continue; code.address = data; data = cheat["value"].Int(); if (data > 0xFF) continue; code.value = data; if (Configuration::ConstSection compare=cheat["compare"]) { data = compare.Int(); if (data > 0xFF) continue; code.compare = data; } code.enabled = !cheat["enabled"].No(); code.crc = cheat["game"].Int(); code.description = cheat["description"].Str(); code.description.Trim(); codes[PERMANENT_CODES].insert( code ); } else { break; } } } Cheats::~Cheats() { } void Cheats::Save(Configuration& cfg) const { Configuration::Section cheats( cfg["cheats"] ); cheats["show-hex-main-view"].YesNo() = showHexMainDialog; cheats["show-hex-code-view"].YesNo() = showHexSubDialogs; uint i = 0; for (Codes::const_iterator it(codes[PERMANENT_CODES].begin()), end(codes[PERMANENT_CODES].end()); it != end; ++it) { Configuration::Section cheat( cheats["cheat"][i++] ); cheat[ "enabled" ].YesNo() = it->enabled; if (it->crc) cheat[ "game" ].Str() = HexString( 32, it->crc ).Ptr(); cheat[ "address" ].Str() = HexString( 16, it->address ).Ptr(); cheat[ "value" ].Str() = HexString( 8, it->value ).Ptr(); if (it->compare != Code::NO_COMPARE) cheat["compare"].Str() = HexString( 8, it->compare ).Ptr(); if (it->description.Length()) cheat["description"].Str() = it->description.Ptr(); } } void Cheats::Flush() { searcher.filter = Searcher::NO_FILTER; searcher.a = 0; searcher.b = 0; codes[TEMPORARY_CODES].clear(); } void Cheats::Open() { MainDialog( codes[PERMANENT_CODES], codes[TEMPORARY_CODES], showHexMainDialog, showHexSubDialogs, searcher, emulator, paths ).Open(); } bool Cheats::Load(const Path& path) { return Import( codes[TEMPORARY_CODES], path ); } bool Cheats::Save(const Path& path) const { return Export( codes[TEMPORARY_CODES], path ); } bool Cheats::Import(Codes& codes,const Path& path) { try { typedef Nes::Core::Xml Xml; Xml xml; { Io::Stream::In stream( path ); xml.Read( stream ); } if (!xml.GetRoot().IsType( L"cheats" )) return false; for (Xml::Node node(xml.GetRoot().GetFirstChild()); node && codes.size() < MAX_CODES; node=node.GetNextSibling()) { if (!node.IsType( L"cheat" )) continue; Code code; if (const Xml::Node address=node.GetChild( L"address" )) { uint v; if (0xFFFF < (v=address.GetUnsignedValue())) continue; code.address = v; if (const Xml::Node value=node.GetChild( L"value" )) { if (0xFF < (v=value.GetUnsignedValue())) continue; code.value = v; } if (const Xml::Node compare=node.GetChild( L"compare" )) { if (0xFF < (v=compare.GetUnsignedValue())) continue; code.compare = v; } } else { NesCode nesCode; if (const Xml::Node genie=node.GetChild( L"genie" )) { if (NES_FAILED(Nes::Cheats::GameGenieDecode( String::Heap(genie.GetValue()).Ptr(), nesCode ))) continue; } else if (const Xml::Node rocky=node.GetChild( L"rocky" )) { if (NES_FAILED(Nes::Cheats::ProActionRockyDecode( String::Heap(rocky.GetValue()).Ptr(), nesCode ))) continue; } else { continue; } code.FromNesCode( nesCode ); } code.description = node.GetChild( L"description" ).GetValue(); code.enabled = !node.GetAttribute( L"enabled" ).IsValue( L"0" ); code.crc = node.GetAttribute( L"game" ).GetUnsignedValue(); codes.insert( code ); } } catch (...) { return false; } return true; } bool Cheats::Export(const Codes& codes,const Path& path) { if (!path.Length() || codes.empty()) return false; try { typedef Nes::Core::Xml Xml; Xml xml; Xml::Node root( xml.GetRoot() ); root = xml.Create( L"cheats" ); root.AddAttribute( L"version", L"1.0" ); for (Codes::const_iterator it(codes.begin()), end(codes.end()); it != end; ++it) { Xml::Node node( root.AddChild( L"cheat" ) ); node.AddAttribute( L"enabled", it->enabled ? L"1" : L"0" ); if (it->crc) node.AddAttribute( L"game", HexString( 32, it->crc ).Ptr() ); char buffer[9]; if (NES_SUCCEEDED(Nes::Cheats::GameGenieEncode( it->ToNesCode(), buffer ))) node.AddChild( L"genie", HeapString(buffer).Ptr() ); if (NES_SUCCEEDED(Nes::Cheats::ProActionRockyEncode( it->ToNesCode(), buffer ))) node.AddChild( L"rocky", HeapString(buffer).Ptr() ); node.AddChild( L"address", HexString( 16, it->address ).Ptr() ); node.AddChild( L"value", HexString( 8, it->value ).Ptr() ); if (it->compare != Code::NO_COMPARE) node.AddChild( L"compare", HexString( 8, it->compare ).Ptr() ); if (it->description.Length()) node.AddChild( L"description", it->description.Ptr() ); } Io::Stream::Out stream( path ); xml.Write( root, stream ); } catch (...) { return false; } return true; } struct Cheats::MainDialog::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; }; const MsgHandler::Entry Cheats::MainDialog::Handlers::messages[] = { { WM_INITDIALOG, &MainDialog::OnInitDialog } }; const MsgHandler::Entry Cheats::MainDialog::Handlers::commands[] = { { IDC_CHEATS_SHOW_HEX, &MainDialog::OnCmdShowHex } }; Cheats::MainDialog::MainDialog ( Codes& permanentCodes, Codes& temporaryCodes, bool& showHexMainDialog, bool& showHexSubDialogs, Searcher& searcher, Managers::Emulator& emulator, const Managers::Paths& paths ) : dialog ( IDD_CHEATS, this, Handlers::messages, Handlers::commands ), permanentView ( 0, dialog, permanentCodes, showHexMainDialog, showHexSubDialogs, searcher, emulator, paths ), temporaryView ( 1, dialog, temporaryCodes, showHexMainDialog, showHexSubDialogs, searcher, emulator, paths ), showHex ( showHexMainDialog ) { } ibool Cheats::MainDialog::OnInitDialog(Param&) { dialog.CheckBox( IDC_CHEATS_SHOW_HEX ).Check( showHex ); return true; } ibool Cheats::MainDialog::OnCmdShowHex(Param& param) { if (param.Button().Clicked()) { showHex = dialog.CheckBox( IDC_CHEATS_SHOW_HEX ).Checked(); permanentView.UpdateHexView(); temporaryView.UpdateHexView(); } return true; } struct Cheats::MainDialog::Section::Handlers { static const Control::NotificationHandler::Entry
notifications[]; }; const Control::NotificationHandler::Entry Cheats::MainDialog::Section::Handlers::notifications[] = { { LVN_KEYDOWN, &Section::OnKeyDown }, { LVN_ITEMCHANGED, &Section::OnItemChanged }, { LVN_INSERTITEM, &Section::OnInsertItem }, { LVN_DELETEITEM, &Section::OnDeleteItem }, { LVN_COLUMNCLICK, &Section::OnColumnClick } }; Cheats::MainDialog::Section::Section ( uint i, Dialog& d, Codes& c, const bool& h, bool& a, Searcher& s, Managers::Emulator& e, const Managers::Paths& p ) : id ( i ), codes ( c ), showHexMainDialog ( h ), showHexSubDialogs ( a ), searcher ( s ), dialog ( d ), notificationHandler ( i == 0 ? IDC_CHEATS_STATIC_CODES : IDC_CHEATS_TEMP_CODES, d.Messages(), this, Handlers::notifications ), emulator ( e ), paths ( p ) { static const MsgHandler::Entry
commands[2][6] = { { { IDC_CHEATS_STATIC_ADD, &Section::OnCmdAdd }, { IDC_CHEATS_STATIC_EDIT, &Section::OnCmdEdit }, { IDC_CHEATS_STATIC_REMOVE, &Section::OnCmdRemove }, { IDC_CHEATS_STATIC_EXPORT, &Section::OnCmdExport }, { IDC_CHEATS_STATIC_IMPORT, &Section::OnCmdImport }, { IDC_CHEATS_STATIC_CLEAR, &Section::OnCmdClear } }, { { IDC_CHEATS_TEMP_ADD, &Section::OnCmdAdd }, { IDC_CHEATS_TEMP_EDIT, &Section::OnCmdEdit }, { IDC_CHEATS_TEMP_REMOVE, &Section::OnCmdRemove }, { IDC_CHEATS_TEMP_EXPORT, &Section::OnCmdExport }, { IDC_CHEATS_TEMP_IMPORT, &Section::OnCmdImport }, { IDC_CHEATS_TEMP_CLEAR, &Section::OnCmdClear } } }; d.Commands().Add( this, commands[i != 0] ); static const MsgHandler::HookEntry
hooks[] = { { WM_INITDIALOG, &Section::OnInitDialog }, { WM_DROPFILES, &Section::OnDropFiles } }; d.Messages().Hooks().Add( this, hooks ); for (uint i=0; i < NUM_COLUMNS; ++i) sortColumns[i] = static_cast(i); } void Cheats::MainDialog::Section::OnInitDialog(Param& param) { listView = Control::ListView( param.hWnd, id == 0 ? IDC_CHEATS_STATIC_CODES : IDC_CHEATS_TEMP_CODES ); listView.StyleEx() = LVS_EX_FULLROWSELECT|LVS_EX_CHECKBOXES; listView.Columns().Clear(); for (uint i=0; i < NUM_COLUMNS; ++i) { static const ushort columns[NUM_COLUMNS] = { IDS_CHEAT_CODE, IDS_CHEAT_ADDRESS, IDS_CHEAT_VALUE, IDS_CHEAT_COMPARE, IDS_CHEAT_GAME, IDS_CHEAT_DESCRIPTION }; listView.Columns().Insert( i, Resource::String(columns[i]) ); } controls[ ADD ] = Control::Generic( param.hWnd, id ? IDC_CHEATS_TEMP_ADD : IDC_CHEATS_STATIC_ADD ); controls[ EDIT ] = Control::Generic( param.hWnd, id ? IDC_CHEATS_TEMP_EDIT : IDC_CHEATS_STATIC_EDIT ); controls[ REMOVE ] = Control::Generic( param.hWnd, id ? IDC_CHEATS_TEMP_REMOVE : IDC_CHEATS_STATIC_REMOVE ); controls[ IMPORT ] = Control::Generic( param.hWnd, id ? IDC_CHEATS_TEMP_IMPORT : IDC_CHEATS_STATIC_IMPORT ); controls[ EXPORT ] = Control::Generic( param.hWnd, id ? IDC_CHEATS_TEMP_EXPORT : IDC_CHEATS_STATIC_EXPORT ); controls[ CLEAR ] = Control::Generic( param.hWnd, id ? IDC_CHEATS_TEMP_CLEAR : IDC_CHEATS_STATIC_CLEAR ); controls[ EDIT ].Disable(); controls[ REMOVE ].Disable(); controls[ EXPORT ].Disable(); controls[ CLEAR ].Disable(); if (!codes.empty()) { listView.Reserve( codes.size() ); for (Codes::iterator it(codes.begin()), end(codes.end()); it != end; ++it) AddToListView( *it ); } RefreshListView(); } ibool Cheats::MainDialog::Section::OnCmdAdd(Param& param) { if (param.Button().Clicked()) SetCode(); return true; } ibool Cheats::MainDialog::Section::OnCmdEdit(Param& param) { if (param.Button().Clicked()) SetCode( listView.Selection().GetIndex() ); return true; } ibool Cheats::MainDialog::Section::OnCmdRemove(Param& param) { if (param.Button().Clicked()) { NST_VERIFY( !codes.empty() ); listView.Selection().Delete(); } return true; } ibool Cheats::MainDialog::Section::OnCmdExport(Param& param) { if (param.Button().Clicked() && !codes.empty()) { Path path( paths.BrowseSave( Managers::Paths::File::XML, Managers::Paths::SUGGEST, paths.GetCheatPath() ) ); paths.FixFile( Managers::Paths::File::XML, path ); if (path.Length()) { if (path.FileExists() && User::Confirm( IDS_CHEATS_EXPORTEXISTING )) { Codes combinedCodes( codes ); if (!Import( combinedCodes, path )) User::Warn( IDS_CHEATS_EXPORTEXISTING_ERROR ); if (!Export( combinedCodes, path )) User::Fail( IDS_FILE_ERR_INVALID ); } else { if (!Export( codes, path )) User::Fail( IDS_FILE_ERR_INVALID ); } } } return true; } ibool Cheats::MainDialog::Section::OnCmdImport(Param& param) { if (param.Button().Clicked()) { const Path path( paths.BrowseLoad( Managers::Paths::File::XML, paths.GetCheatPath() ) ); if (path.Length()) { Codes newCodes; if (Import( newCodes, path )) AddCodes( newCodes ); else User::Fail( IDS_FILE_ERR_INVALID ); } } return true; } ibool Cheats::MainDialog::Section::OnCmdClear(Param& param) { if (param.Button().Clicked()) { NST_VERIFY( !codes.empty() ); listView.Clear(); RefreshListView(); } return true; } void Cheats::MainDialog::Section::AddCodes(const Codes& newCodes) { bool refresh = false; for (Codes::const_iterator it(newCodes.begin()), end(newCodes.end()); it != end; ++it) { std::pair result( codes.insert( *it ) ); if (result.second) { refresh = true; AddToListView( *result.first ); } } if (refresh) RefreshListView(); } void Cheats::MainDialog::Section::UpdateHexView() const { for (uint i=0, n=listView.Size(); i < n; ++i) { const Code* const code = static_cast(static_cast(listView[i].Data())); NST_VERIFY( code ); if (code) { listView[i].Text( COLUMN_VALUE ) << (showHexMainDialog ? HexString( 8, code->value ).Ptr() : (String::Stack<8>() << code->value).Ptr()); if (code->compare != Code::NO_COMPARE) listView[i].Text( COLUMN_COMPARE ) << (showHexMainDialog ? HexString( 8, code->compare ).Ptr() : (String::Stack<8>() << code->compare).Ptr()); } } } void Cheats::MainDialog::Section::OnKeyDown(const NMHDR& nmhdr) { switch (reinterpret_cast(nmhdr).wVKey) { case VK_INSERT: SetCode(); break; case VK_DELETE: listView.Selection().Delete(); break; } } void Cheats::MainDialog::Section::OnItemChanged(const NMHDR& nmhdr) { const NMLISTVIEW& nm = reinterpret_cast(nmhdr); if ((nm.uOldState ^ nm.uNewState) & LVIS_SELECTED) { controls[ REMOVE ].Enable( nm.uNewState & LVIS_SELECTED ); controls[ EDIT ].Enable( nm.uNewState & LVIS_SELECTED ); } if ((nm.uOldState ^ nm.uNewState) & LVIS_STATEIMAGEMASK) { NST_VERIFY( nm.lParam ); if (nm.lParam) { // As documented on MSDN the image index for the checked box is 2 (unchecked is 1) reinterpret_cast(nm.lParam)->enabled = ((nm.uNewState & LVIS_STATEIMAGEMASK) == INDEXTOSTATEIMAGEMASK( 2 )); } } } void Cheats::MainDialog::Section::OnInsertItem(const NMHDR&) { if (listView.Size() == 1) { controls[ CLEAR ].Enable(); controls[ EXPORT ].Enable(); } } void Cheats::MainDialog::Section::OnDeleteItem(const NMHDR& nmhdr) { const Code* const code = reinterpret_cast(reinterpret_cast(nmhdr).lParam); NST_VERIFY( code ); if (code) { Codes::iterator it(codes.find( *code )); NST_VERIFY( it != codes.end() ); if (it != codes.end()) codes.erase( it ); } if (listView.Size() == 1) { controls[ CLEAR ].Disable(); controls[ EXPORT ].Disable(); controls[ REMOVE ].Disable(); } } void Cheats::MainDialog::Section::OnColumnClick(const NMHDR& nmhdr) { uint column = reinterpret_cast(nmhdr).iSubItem; NST_VERIFY( column <= NUM_COLUMNS ); if (column <= NUM_COLUMNS) { sortColumns[0] = static_cast(column); for (uint i=1, next=0; i < NUM_COLUMNS; ++i, ++next) { if (next == column) next++; sortColumns[i] = static_cast(next); } if (!codes.empty()) listView.Sort( this, &Section::Sorter ); } } void Cheats::MainDialog::Section::AddToListView(const Code& code) const { const uint index = listView.Add( code.ToGenieCode(), &code, code.enabled ); listView[index].Text( COLUMN_ADDRESS ) << HexString( 16, code.address ).Ptr(); listView[index].Text( COLUMN_VALUE ) << (showHexMainDialog ? HexString( 8, code.value ).Ptr() : (String::Stack<8>() << code.value).Ptr()); listView[index].Text( COLUMN_COMPARE ) << (code.compare != Code::NO_COMPARE ? showHexMainDialog ? HexString( 8, code.compare ).Ptr() : (String::Stack<8>() << code.compare).Ptr() : L"-"); listView[index].Text( COLUMN_GAME ) << (code.crc ? HexString( 32, code.crc ).Ptr() : L"-"); listView[index].Text( COLUMN_DESCRIPTION ) << (code.description.Length() ? code.description.Ptr() : L"-"); } void Cheats::MainDialog::Section::OnDropFiles(Param& param) { DropFiles dropFiles( param ); if (dropFiles.Inside( listView.GetHandle() )) { Codes newCodes; for (uint i=0, n=dropFiles.Size(); i < n; ++i) Import( newCodes, dropFiles[i] ); AddCodes( newCodes ); } } void Cheats::MainDialog::Section::RefreshListView() { if (!codes.empty()) listView.Sort( this, &Section::Sorter ); listView.Columns().Align(); } int Cheats::MainDialog::Section::Sorter(const void* obj1,const void* obj2) { const Code& a = *static_cast( obj1 ); const Code& b = *static_cast( obj2 ); for (uint i=0; i < NUM_COLUMNS; ++i) { switch (sortColumns[i]) { case COLUMN_CODE: { const Code::GenieCode ga( a.ToGenieCode() ); const Code::GenieCode gb( b.ToGenieCode() ); if (gb == L"-") { if (ga != L"-") return -1; } else if (ga == L"-") { if (gb != L"-") return 1; } else { if (ga < gb) return -1; if (ga > gb) return 1; } continue; } case COLUMN_ADDRESS: if (a.address < b.address) return -1; if (a.address > b.address) return 1; continue; case COLUMN_VALUE: if (a.value < b.value) return -1; if (a.value > b.value) return 1; continue; case COLUMN_COMPARE: if (a.compare < b.compare) return -1; if (a.compare > b.compare) return 1; continue; case COLUMN_GAME: if ((a.crc ? a.crc : ~0U) < (b.crc ? b.crc : ~0U)) return -1; if ((a.crc ? a.crc : ~0U) > (b.crc ? b.crc : ~0U)) return 1; continue; case COLUMN_DESCRIPTION: if (!b.description.Length()) { if (a.description.Length()) return -1; } else if (!a.description.Length()) { if (b.description.Length()) return 1; } else { if (a.description < b.description) return -1; if (a.description > b.description) return 1; } continue; default: NST_UNREACHABLE(); } } return 0; } void Cheats::MainDialog::Section::SetCode(int index) { CodeDialog::Context context( showHexSubDialogs, searcher ); if (index >= 0) { if (const void* const existing = listView[index].Data()) { const Codes::const_iterator it( codes.find( *static_cast(existing) ) ); if (it != codes.end()) { context.code = *it; context.edit = true; } } } if (CodeDialog( emulator, paths, context ).Open()) { if (index >= 0) listView[index].Delete(); const std::pair result( codes.insert( context.code ) ); if (result.second) { AddToListView( *result.first ); RefreshListView(); } } } struct Cheats::MainDialog::Section::CodeDialog::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; }; const MsgHandler::Entry Cheats::MainDialog::Section::CodeDialog::Handlers::messages[] = { { WM_INITDIALOG, &CodeDialog::OnInitDialog } }; const MsgHandler::Entry Cheats::MainDialog::Section::CodeDialog::Handlers::commands[] = { { IDC_CHEATS_ADDCODE_SUBMIT, &CodeDialog::OnCmdSubmit }, { IDC_CHEATS_ADDCODE_VALIDATE, &CodeDialog::OnCmdValidate }, { IDC_CHEATS_ADDCODE_GAME_CURRENT, &CodeDialog::OnCmdGameCurrent }, { IDC_CHEATS_ADDCODE_GAME_BROWSE, &CodeDialog::OnCmdGameBrowse }, { IDC_CHEATS_ADDCODE_USE_HEX, &CodeDialog::OnCmdHex }, { IDC_CHEATS_ADDCODE_USE_RAW, &CodeDialog::OnCmdType }, { IDC_CHEATS_ADDCODE_USE_GENIE, &CodeDialog::OnCmdType }, { IDC_CHEATS_ADDCODE_USE_ROCKY, &CodeDialog::OnCmdType }, { IDC_CHEATS_ADDCODE_SEARCH_NONE, &CodeDialog::OnSearchType }, { IDC_CHEATS_ADDCODE_SEARCH_R0_A_R1_B, &CodeDialog::OnSearchType }, { IDC_CHEATS_ADDCODE_SEARCH_R0_A_R0R1_B, &CodeDialog::OnSearchType }, { IDC_CHEATS_ADDCODE_SEARCH_R0R1_B, &CodeDialog::OnSearchType }, { IDC_CHEATS_ADDCODE_SEARCH_R0_L_R1, &CodeDialog::OnSearchType }, { IDC_CHEATS_ADDCODE_SEARCH_R0_G_R1, &CodeDialog::OnSearchType }, { IDC_CHEATS_ADDCODE_SEARCH_R0_N_R1, &CodeDialog::OnSearchType }, { IDC_CHEATS_ADDCODE_SEARCH_RESET, &CodeDialog::OnCmdReset } }; Cheats::MainDialog::Section::CodeDialog::CodeDialog(Managers::Emulator& e,const Managers::Paths& p,Context& c) : context (c), emulator (e), paths (p), dialog (IDD_CHEATS_ADDCODE,this,Handlers::messages,Handlers::commands), notificationHandler (IDC_CHEATS_ADDCODE_SEARCH_LIST,dialog.Messages()) { static const Control::NotificationHandler::Entry notifications[] = { { LVN_ITEMCHANGED, &CodeDialog::OnItemChanged } }; notificationHandler.Add( this, notifications ); } ibool Cheats::MainDialog::Section::CodeDialog::OnInitDialog(Param&) { dialog.Edit( IDC_CHEATS_ADDCODE_ADDRESS ).Limit( 4 ); dialog.Edit( IDC_CHEATS_ADDCODE_DESC ).Limit( 256 ); dialog.Edit( IDC_CHEATS_ADDCODE_GENIE ).Limit( 8 ); dialog.Edit( IDC_CHEATS_ADDCODE_ROCKY ).Limit( 8 ); dialog.Edit( IDC_CHEATS_ADDCODE_GAME ).Limit( 8 ); dialog.RadioButton( IDC_CHEATS_ADDCODE_USE_RAW ).Check( true ); dialog.RadioButton( IDC_CHEATS_ADDCODE_USE_GENIE ).Check( false ); dialog.RadioButton( IDC_CHEATS_ADDCODE_USE_ROCKY ).Check( false ); dialog.Control( IDC_CHEATS_ADDCODE_GAME_CURRENT ).Enable( Nes::Cartridge(emulator).GetProfile() ); UpdateInput(); if (emulator.IsGameOn()) { Control::ListView listView( dialog.ListView(IDC_CHEATS_ADDCODE_SEARCH_LIST) ); listView.StyleEx() = LVS_EX_FULLROWSELECT; static wcstring const columns[] = { L"Index", L"R0", L"R1" }; listView.Columns().Set( columns ); if (context.searcher.filter == Searcher::NO_FILTER) { context.searcher.filter = IDC_CHEATS_ADDCODE_SEARCH_NONE; std::memcpy( context.searcher.ram, Nes::Cheats(emulator).GetRam(), Nes::Cheats::RAM_SIZE ); dialog.Control( IDC_CHEATS_ADDCODE_SEARCH_RESET ).Disable(); } else if (std::memcmp( context.searcher.ram, Nes::Cheats(emulator).GetRam(), Nes::Cheats::RAM_SIZE ) == 0) { dialog.Control( IDC_CHEATS_ADDCODE_SEARCH_RESET ).Disable(); } dialog.RadioButton( context.searcher.filter ).Check(); } else { NST_COMPILE_ASSERT ( IDC_CHEATS_ADDCODE_SEARCH_TEXT_B - IDC_CHEATS_ADDCODE_SEARCH_TEXT_A == 1 && IDC_CHEATS_ADDCODE_SEARCH_A - IDC_CHEATS_ADDCODE_SEARCH_TEXT_A == 2 && IDC_CHEATS_ADDCODE_SEARCH_B - IDC_CHEATS_ADDCODE_SEARCH_TEXT_A == 3 && IDC_CHEATS_ADDCODE_SEARCH_LIST - IDC_CHEATS_ADDCODE_SEARCH_TEXT_A == 4 && IDC_CHEATS_ADDCODE_SEARCH_NONE - IDC_CHEATS_ADDCODE_SEARCH_TEXT_A == 5 && IDC_CHEATS_ADDCODE_SEARCH_R0_A_R1_B - IDC_CHEATS_ADDCODE_SEARCH_TEXT_A == 6 && IDC_CHEATS_ADDCODE_SEARCH_R0_A_R0R1_B - IDC_CHEATS_ADDCODE_SEARCH_TEXT_A == 7 && IDC_CHEATS_ADDCODE_SEARCH_R0R1_B - IDC_CHEATS_ADDCODE_SEARCH_TEXT_A == 8 && IDC_CHEATS_ADDCODE_SEARCH_R0_L_R1 - IDC_CHEATS_ADDCODE_SEARCH_TEXT_A == 9 && IDC_CHEATS_ADDCODE_SEARCH_R0_G_R1 - IDC_CHEATS_ADDCODE_SEARCH_TEXT_A == 10 && IDC_CHEATS_ADDCODE_SEARCH_R0_N_R1 - IDC_CHEATS_ADDCODE_SEARCH_TEXT_A == 11 && IDC_CHEATS_ADDCODE_SEARCH_RESET - IDC_CHEATS_ADDCODE_SEARCH_TEXT_A == 12 ); for (uint i=IDC_CHEATS_ADDCODE_SEARCH_TEXT_A; i <= IDC_CHEATS_ADDCODE_SEARCH_RESET; ++i) dialog.Control( i ).Disable(); } dialog.CheckBox( IDC_CHEATS_ADDCODE_USE_HEX ).Check( context.hex ); UpdateHexView( false ); if (context.edit) { const NesCode nesCode( context.code.ToNesCode() ); SetRawCode( nesCode ); SetGenieCode( nesCode ); SetRockyCode( nesCode ); if (context.code.crc) dialog.Edit( IDC_CHEATS_ADDCODE_GAME ) << HexString( 32, context.code.crc, true ).Ptr(); if (context.code.description.Length()) dialog.Edit( IDC_CHEATS_ADDCODE_DESC ) << context.code.description.Ptr(); } return true; } ibool Cheats::MainDialog::Section::CodeDialog::OnDestroy(Param&) { context.searcher.a = GetSearchValue( IDC_CHEATS_ADDCODE_SEARCH_A ); context.searcher.b = GetSearchValue( IDC_CHEATS_ADDCODE_SEARCH_B ); return true; } ibool Cheats::MainDialog::Section::CodeDialog::OnCmdSubmit(Param& param) { if (param.Button().Clicked()) { bool result; NesCode nesCode; if (dialog.RadioButton( IDC_CHEATS_ADDCODE_USE_RAW ).Checked()) { result = GetRawCode( nesCode ); } else if (dialog.RadioButton( IDC_CHEATS_ADDCODE_USE_GENIE ).Checked()) { result = GetGenieCode( nesCode ); } else { result = GetRockyCode( nesCode ); } if (result) { context.code.FromNesCode( nesCode ); HeapString crc; if (dialog.Edit( IDC_CHEATS_ADDCODE_GAME ) >> crc) { crc.Insert( 0, "0x" ); crc >> context.code.crc; } else { context.code.crc = 0; } dialog.Edit( IDC_CHEATS_ADDCODE_DESC ) >> context.code.description; dialog.Close( true ); } else { User::Warn( IDS_CHEATS_INVALID_CODE, IDS_CHEATS ); } } return true; } ibool Cheats::MainDialog::Section::CodeDialog::OnCmdValidate(Param& param) { if (param.Button().Clicked()) { uint id; NesCode code; if (dialog.RadioButton( IDC_CHEATS_ADDCODE_USE_RAW ).Checked()) { id = GetRawCode( code ) ? IDC_CHEATS_ADDCODE_USE_RAW : 0; } else if (dialog.RadioButton( IDC_CHEATS_ADDCODE_USE_GENIE ).Checked()) { id = GetGenieCode( code ) ? IDC_CHEATS_ADDCODE_USE_GENIE : 0; } else { id = GetRockyCode( code ) ? IDC_CHEATS_ADDCODE_USE_ROCKY : 0; } if (id) { if (id != IDC_CHEATS_ADDCODE_USE_RAW) SetRawCode( code ); if (id != IDC_CHEATS_ADDCODE_USE_GENIE) SetGenieCode( code ); if (id != IDC_CHEATS_ADDCODE_USE_ROCKY) SetRockyCode( code ); } dialog.Edit( IDC_CHEATS_ADDCODE_RESULT ) << Resource::String(id ? IDS_CHEATS_RESULT_VALID : IDS_CHEATS_RESULT_INVALID); } return true; } ibool Cheats::MainDialog::Section::CodeDialog::OnCmdGameCurrent(Param& param) { if (param.Button().Clicked()) { if (const Nes::Cartridge::Profile* const profile = Nes::Cartridge(emulator).GetProfile()) dialog.Edit( IDC_CHEATS_ADDCODE_GAME ) << HexString( 32, profile->hash.GetCrc32(), true ).Ptr(); } return true; } ibool Cheats::MainDialog::Section::CodeDialog::OnCmdGameBrowse(Param& param) { if (param.Button().Clicked()) { Managers::Paths::File file; if (paths.Load( file, Managers::Paths::File::CARTRIDGE|Managers::Paths::File::ARCHIVE )) { bool loaded = false; Io::Stream::In stream( file.data ); Nes::Cartridge::Profile profile; switch (file.type) { case Managers::Paths::File::INES: loaded = NES_SUCCEEDED(Nes::Cartridge::ReadInes( stream, Nes::Machine::FAVORED_NES_NTSC, profile )); break; case Managers::Paths::File::UNIF: loaded = NES_SUCCEEDED(Nes::Cartridge::ReadUnif( stream, Nes::Machine::FAVORED_NES_NTSC, profile )); break; case Managers::Paths::File::XML: loaded = NES_SUCCEEDED(Nes::Cartridge::ReadRomset( stream, Nes::Machine::FAVORED_NES_NTSC, false, profile )); break; } if (loaded) { NST_VERIFY( profile.hash.GetCrc32() ); if (const uint crc = profile.hash.GetCrc32()) dialog.Edit( IDC_CHEATS_ADDCODE_GAME ) << HexString( 32, crc, true ).Ptr(); else dialog.Edit( IDC_CHEATS_ADDCODE_GAME ).Clear(); } else { User::Fail( IDS_FILE_ERR_INVALID ); } } } return true; } ibool Cheats::MainDialog::Section::CodeDialog::OnCmdHex(Param& param) { if (param.Button().Clicked()) UpdateHexView( true ); return true; } ibool Cheats::MainDialog::Section::CodeDialog::OnCmdType(Param& param) { if (param.Button().Clicked()) { const uint cmd = param.Button().GetId(); dialog.RadioButton( IDC_CHEATS_ADDCODE_USE_RAW ).Check( cmd == IDC_CHEATS_ADDCODE_USE_RAW ); dialog.RadioButton( IDC_CHEATS_ADDCODE_USE_GENIE ).Check( cmd == IDC_CHEATS_ADDCODE_USE_GENIE ); dialog.RadioButton( IDC_CHEATS_ADDCODE_USE_ROCKY ).Check( cmd == IDC_CHEATS_ADDCODE_USE_ROCKY ); UpdateInput(); } return true; } ibool Cheats::MainDialog::Section::CodeDialog::OnSearchType(Param& param) { if (param.Button().Clicked()) { context.searcher.filter = param.Button().GetId(); UpdateSearchList(); } return true; } ibool Cheats::MainDialog::Section::CodeDialog::OnCmdReset(Param& param) { if (param.Button().Clicked()) { dialog.Control( IDC_CHEATS_ADDCODE_SEARCH_RESET ).Disable(); std::memcpy( context.searcher.ram, Nes::Cheats(emulator).GetRam(), Nes::Cheats::RAM_SIZE ); UpdateSearchList(); } return true; } void Cheats::MainDialog::Section::CodeDialog::OnItemChanged(const NMHDR& nmhdr) { const NMLISTVIEW& nm = reinterpret_cast(nmhdr); if ((nm.uNewState & LVIS_SELECTED) > (nm.uOldState & LVIS_SELECTED)) { NST_VERIFY( nm.lParam <= 0xFFFF ); if (nm.lParam <= 0xFFFF) { dialog.Edit( IDC_CHEATS_ADDCODE_ADDRESS ) << HexString( 16, nm.lParam, true ).Ptr(); if (dialog.RadioButton( IDC_CHEATS_ADDCODE_USE_RAW ).Unchecked()) { dialog.RadioButton( IDC_CHEATS_ADDCODE_USE_RAW ).Check( true ); dialog.RadioButton( IDC_CHEATS_ADDCODE_USE_GENIE ).Check( false ); dialog.RadioButton( IDC_CHEATS_ADDCODE_USE_ROCKY ).Check( false ); UpdateInput(); } } } } void Cheats::MainDialog::Section::CodeDialog::UpdateInput() const { const bool raw = dialog.RadioButton( IDC_CHEATS_ADDCODE_USE_RAW ).Checked(); const bool genie = !raw && dialog.RadioButton( IDC_CHEATS_ADDCODE_USE_GENIE ).Checked(); const bool rocky = !raw && !genie; dialog.Control( IDC_CHEATS_ADDCODE_VALUE ).Enable( raw ); dialog.Control( IDC_CHEATS_ADDCODE_COMPARE ).Enable( raw ); dialog.Control( IDC_CHEATS_ADDCODE_ADDRESS ).Enable( raw ); dialog.Control( IDC_CHEATS_ADDCODE_GENIE ).Enable( genie ); dialog.Control( IDC_CHEATS_ADDCODE_ROCKY ).Enable( rocky ); } void Cheats::MainDialog::Section::CodeDialog::UpdateHexView(bool changed) const { NesCode code; if (changed) { changed = GetRawCode( code ); if (emulator.IsGameOn()) { context.searcher.a = GetSearchValue( IDC_CHEATS_ADDCODE_SEARCH_A ); context.searcher.b = GetSearchValue( IDC_CHEATS_ADDCODE_SEARCH_B ); } context.hex = dialog.CheckBox( IDC_CHEATS_ADDCODE_USE_HEX ).Checked(); } const uint digits = context.hex ? 2 : 3; dialog.Edit( IDC_CHEATS_ADDCODE_VALUE ).Limit( digits ); dialog.Edit( IDC_CHEATS_ADDCODE_COMPARE ).Limit( digits ); dialog.Edit( IDC_CHEATS_ADDCODE_VALUE ).SetNumberOnly( digits == 3 ); dialog.Edit( IDC_CHEATS_ADDCODE_COMPARE ).SetNumberOnly( digits == 3 ); if (changed) { SetRawCode( code ); } else { dialog.Edit( IDC_CHEATS_ADDCODE_VALUE ).Clear(); dialog.Edit( IDC_CHEATS_ADDCODE_COMPARE ).Clear(); } if (emulator.IsGameOn()) { dialog.Edit( IDC_CHEATS_ADDCODE_SEARCH_A ).Limit( digits ); dialog.Edit( IDC_CHEATS_ADDCODE_SEARCH_B ).Limit( digits ); dialog.Edit( IDC_CHEATS_ADDCODE_SEARCH_A ).SetNumberOnly( digits == 3 ); dialog.Edit( IDC_CHEATS_ADDCODE_SEARCH_B ).SetNumberOnly( digits == 3 ); SetSearchValue( IDC_CHEATS_ADDCODE_SEARCH_A, context.searcher.a ); SetSearchValue( IDC_CHEATS_ADDCODE_SEARCH_B, context.searcher.b ); UpdateSearchList(); } } void Cheats::MainDialog::Section::CodeDialog::UpdateSearchList() const { Application::Instance::Waiter wait; Control::ListView list( dialog.ListView(IDC_CHEATS_ADDCODE_SEARCH_LIST) ); const uchar values[] = { GetSearchValue( IDC_CHEATS_ADDCODE_SEARCH_A ), GetSearchValue( IDC_CHEATS_ADDCODE_SEARCH_B ) }; list.Clear(); list.Reserve( Nes::Cheats::RAM_SIZE ); Nes::Cheats::Ram ram = Nes::Cheats(emulator).GetRam(); switch (context.searcher.filter) { case IDC_CHEATS_ADDCODE_SEARCH_NONE: for (uint i=0; i < Nes::Cheats::RAM_SIZE; ++i) AddSearchEntry( list, i ); break; case IDC_CHEATS_ADDCODE_SEARCH_R0_N_R1: for (uint i=0; i < Nes::Cheats::RAM_SIZE; ++i) { if (context.searcher.ram[i] != ram[i]) AddSearchEntry( list, i ); } break; case IDC_CHEATS_ADDCODE_SEARCH_R0_L_R1: for (uint i=0; i < Nes::Cheats::RAM_SIZE; ++i) { if (context.searcher.ram[i] < ram[i]) AddSearchEntry( list, i ); } break; case IDC_CHEATS_ADDCODE_SEARCH_R0_G_R1: for (uint i=0; i < Nes::Cheats::RAM_SIZE; ++i) { if (context.searcher.ram[i] > ram[i]) AddSearchEntry( list, i ); } break; case IDC_CHEATS_ADDCODE_SEARCH_R0_A_R1_B: for (uint i=0; i < Nes::Cheats::RAM_SIZE; ++i) { if (context.searcher.ram[i] == values[0] && ram[i] == values[1]) AddSearchEntry( list, i ); } break; case IDC_CHEATS_ADDCODE_SEARCH_R0_A_R0R1_B: for (uint i=0; i < Nes::Cheats::RAM_SIZE; ++i) { if (context.searcher.ram[i] == values[0] && ((context.searcher.ram[i] - ram[i]) & 0xFFU) == values[1]) AddSearchEntry( list, i ); } break; case IDC_CHEATS_ADDCODE_SEARCH_R0R1_B: for (uint i=0; i < Nes::Cheats::RAM_SIZE; ++i) { if (((context.searcher.ram[i] - ram[i]) & 0xFFU) == values[1]) AddSearchEntry( list, i ); } break; } list.Columns().Align(); } bool Cheats::MainDialog::Section::CodeDialog::GetRawCode(NesCode& code) const { HeapString string; if (!(dialog.Edit( IDC_CHEATS_ADDCODE_ADDRESS ) >> string)) return false; string.Insert( 0, "0x" ); uint value; if (!(string >> value) || value > 0xFFFF) return false; code.address = value; if (!(dialog.Edit( IDC_CHEATS_ADDCODE_VALUE ) >> string)) return false; if (context.hex) string.Insert( 0, "0x" ); if (!(string >> value) || value > 0xFF) return false; code.value = value; if (dialog.Edit( IDC_CHEATS_ADDCODE_COMPARE ) >> string) { if (context.hex) string.Insert( 0, "0x" ); if (!(string >> value) || value > 0xFF) return false; code.compare = value; code.useCompare = true; } else { code.compare = 0; code.useCompare = false; } return true; } void Cheats::MainDialog::Section::CodeDialog::SetRawCode(const NesCode& code) const { dialog.Edit( IDC_CHEATS_ADDCODE_ADDRESS ) << HexString( 16, code.address, true ).Ptr(); if (context.hex) dialog.Edit( IDC_CHEATS_ADDCODE_VALUE ) << HexString( 8, code.value, true ).Ptr(); else dialog.Edit( IDC_CHEATS_ADDCODE_VALUE ) << uint(code.value); if (!code.useCompare) { dialog.Edit( IDC_CHEATS_ADDCODE_COMPARE ).Clear(); } else if (context.hex) { dialog.Edit( IDC_CHEATS_ADDCODE_COMPARE ) << HexString( 8, code.compare, true ).Ptr(); } else { dialog.Edit( IDC_CHEATS_ADDCODE_COMPARE ) << uint(code.compare); } } bool Cheats::MainDialog::Section::CodeDialog::GetGenieCode(NesCode& code) const { String::Heap string; dialog.Edit( IDC_CHEATS_ADDCODE_GENIE ) >> string; return NES_SUCCEEDED(Nes::Cheats::GameGenieDecode( string.Ptr(), code )); } void Cheats::MainDialog::Section::CodeDialog::SetGenieCode(const NesCode& code) const { char characters[8+1]; if (NES_SUCCEEDED(Nes::Cheats::GameGenieEncode( code, characters ))) dialog.Edit( IDC_CHEATS_ADDCODE_GENIE ) << characters; else dialog.Edit( IDC_CHEATS_ADDCODE_GENIE ).Clear(); } bool Cheats::MainDialog::Section::CodeDialog::GetRockyCode(NesCode& code) const { String::Heap string; dialog.Edit( IDC_CHEATS_ADDCODE_ROCKY ) >> string; return NES_SUCCEEDED(Nes::Cheats::ProActionRockyDecode( string.Ptr(), code )); } void Cheats::MainDialog::Section::CodeDialog::SetRockyCode(const NesCode& code) const { char characters[8+1]; if (NES_SUCCEEDED(Nes::Cheats::ProActionRockyEncode( code, characters ))) dialog.Edit( IDC_CHEATS_ADDCODE_ROCKY ) << characters; else dialog.Edit( IDC_CHEATS_ADDCODE_ROCKY ).Clear(); } uint Cheats::MainDialog::Section::CodeDialog::GetSearchValue(const uint id) const { uint value = 0; if (context.hex) { HeapString string; if (dialog.Edit( id ) >> string) { string.Insert( 0, "0x" ); if (!(string >> value)) value = 0; } } else { if (!(dialog.Edit( id ) >> value) || value > 0xFF) value = 0; } return value; } void Cheats::MainDialog::Section::CodeDialog::SetSearchValue(const uint id,const uint value) const { if (context.hex) dialog.Edit( id ) << HexString( 8, value, true ).Ptr(); else dialog.Edit( id ) << uint(value); } void Cheats::MainDialog::Section::CodeDialog::AddSearchEntry(Control::ListView list,const uint address) const { const int index = list.Add( HexString( 16, address, true ), address ); if (context.hex) { list[index].Text(1) << HexString( 8, context.searcher.ram[address], true ).Ptr(); list[index].Text(2) << HexString( 8, Nes::Cheats(emulator).GetRam()[address], true ).Ptr(); } else { list[index].Text(1) << String::Num( uint(context.searcher.ram[address]) ).Ptr(); list[index].Text(2) << String::Num( uint(Nes::Cheats(emulator).GetRam()[address]) ).Ptr(); } } Cheats::Code::Code() : crc (0), address (0), compare (NO_COMPARE), value (0), enabled (true) { } bool Cheats::Code::operator < (const Code& code) const { if (address < code.address) return true; if (address > code.address) return false; if (value < code.value) return true; if (value > code.value) return false; if (compare < code.compare) return true; if (compare > code.compare) return false; if ((crc ? crc : ~0U) < (code.crc ? code.crc : ~0U)) return true; return false; } Cheats::NesCode Cheats::Code::ToNesCode() const { return NesCode ( address, value, compare != NO_COMPARE ? compare : 0, compare != NO_COMPARE ); } void Cheats::Code::FromNesCode(const NesCode& code) { address = code.address; value = code.value; compare = (code.useCompare ? code.compare : NO_COMPARE); } Cheats::Code::GenieCode Cheats::Code::ToGenieCode() const { char characters[8+1]; if (NES_SUCCEEDED(Nes::Cheats::GameGenieEncode( ToNesCode(), characters ))) return characters; else return L"-"; } Cheats::Searcher::Searcher() : filter(NO_FILTER), a(0), b(0) {} } } nestopia-1.51.1/source/win32/NstDialogCheats.hpp000066400000000000000000000051131411157722000214100ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIALOG_CHEATS_H #define NST_DIALOG_CHEATS_H #pragma once #include #include "NstWindowDialog.hpp" #include "../core/api/NstApiCheats.hpp" namespace Nestopia { namespace Window { class Cheats { public: Cheats(Managers::Emulator&,const Configuration&,const Managers::Paths&); ~Cheats(); enum CodesType { PERMANENT_CODES, TEMPORARY_CODES }; enum { MAX_CODES = 0xFFFF }; typedef Nes::Cheats::Code NesCode; struct Code { Code(); enum { NO_COMPARE = 0xFFFF }; typedef String::Stack<8,wchar_t> GenieCode; NesCode ToNesCode() const; void FromNesCode(const NesCode&); GenieCode ToGenieCode() const; bool operator < (const Code&) const; HeapString description; uint crc; ushort address; ushort compare; uchar value; bool enabled; }; typedef std::set Codes; void Open(); void Save(Configuration&) const; void Flush(); bool Load(const Path&); bool Save(const Path&) const; private: class MainDialog; struct Searcher { Searcher(); enum { NO_FILTER = 0xFFFF }; ushort filter; uchar a; uchar b; uchar ram[Nes::Cheats::RAM_SIZE]; }; static bool Import(Codes&,const Path&); static bool Export(const Codes&,const Path&); const Managers::Paths& paths; Managers::Emulator& emulator; Codes codes[2]; Searcher searcher; bool showHexMainDialog; bool showHexSubDialogs; public: const Codes& GetCodes(CodesType type) const { return codes[type]; } }; } } #endif nestopia-1.51.1/source/win32/NstDialogDipSwitches.cpp000066400000000000000000000117441411157722000224310ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstWindowParam.hpp" #include "NstManagerEmulator.hpp" #include "NstDialogDipSwitches.hpp" namespace Nestopia { namespace Window { NST_COMPILE_ASSERT ( IDC_DIPSWITCHES_2 == IDC_DIPSWITCHES_1 + 1 && IDC_DIPSWITCHES_3 == IDC_DIPSWITCHES_1 + 2 && IDC_DIPSWITCHES_4 == IDC_DIPSWITCHES_1 + 3 && IDC_DIPSWITCHES_5 == IDC_DIPSWITCHES_1 + 4 && IDC_DIPSWITCHES_6 == IDC_DIPSWITCHES_1 + 5 && IDC_DIPSWITCHES_7 == IDC_DIPSWITCHES_1 + 6 && IDC_DIPSWITCHES_8 == IDC_DIPSWITCHES_1 + 7 && IDC_DIPSWITCHES_2_TEXT == IDC_DIPSWITCHES_1_TEXT + 1 && IDC_DIPSWITCHES_3_TEXT == IDC_DIPSWITCHES_1_TEXT + 2 && IDC_DIPSWITCHES_4_TEXT == IDC_DIPSWITCHES_1_TEXT + 3 && IDC_DIPSWITCHES_5_TEXT == IDC_DIPSWITCHES_1_TEXT + 4 && IDC_DIPSWITCHES_6_TEXT == IDC_DIPSWITCHES_1_TEXT + 5 && IDC_DIPSWITCHES_7_TEXT == IDC_DIPSWITCHES_1_TEXT + 6 && IDC_DIPSWITCHES_8_TEXT == IDC_DIPSWITCHES_1_TEXT + 7 ); struct DipSwitches::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; }; const MsgHandler::Entry DipSwitches::Handlers::messages[] = { { WM_INITDIALOG, &DipSwitches::OnInitDialog } }; const MsgHandler::Entry DipSwitches::Handlers::commands[] = { { IDOK, &DipSwitches::OnCmdOk } }; DipSwitches::DipSwitches(Managers::Emulator& emulator,bool u) : dialog (IDD_DIPSWITCHES,this,Handlers::messages,Handlers::commands), dipSwitches (emulator), userOpened (u) { } ibool DipSwitches::OnInitDialog(Param&) { NST_ASSERT( dipSwitches.NumDips() <= MAX_DIPS ); Point delta; for (uint i=0, canModify=dipSwitches.CanModify(); i < MAX_DIPS; ++i) { Control::ComboBox valueField( dialog.ComboBox(IDC_DIPSWITCHES_1 + i) ); Control::Generic textField( dialog.Control(IDC_DIPSWITCHES_1_TEXT + i) ); if (i < dipSwitches.NumDips()) { textField.Text() << (HeapString() << dipSwitches.GetDipName(i) << ':').Ptr(); for (uint j=0, n=dipSwitches.NumValues(i); j < n; ++j) valueField.Add( HeapString(dipSwitches.GetValueName(i,j)).Ptr() ); valueField[dipSwitches.GetValue(i)].Select(); if (!canModify) { valueField.Disable(); textField.Disable(); } } else { if (i == dipSwitches.NumDips()) delta.y = valueField.GetWindow().Coordinates().top; if (i == MAX_DIPS-1) delta.y = valueField.GetWindow().Coordinates().bottom - delta.y; textField.GetWindow().Destroy(); valueField.GetWindow().Destroy(); } } for (uint i=IDC_DIPSWITCHES_1_TEXT, n=IDC_DIPSWITCHES_1_TEXT+dipSwitches.NumDips(); i < n; ++i) { Control::Generic textField( dialog.Control(i) ); Rect rect( textField.GetWindow().Coordinates() ); rect.right = rect.left + textField.GetMaxTextSize().x; if (delta.x < rect.right) delta.x = rect.right; textField.GetWindow().Size() = rect.Size(); } delta.x = dialog.ComboBox(IDC_DIPSWITCHES_1).GetWindow().Coordinates().left - delta.x + 12; for (uint i=IDC_DIPSWITCHES_1, n=IDC_DIPSWITCHES_1+dipSwitches.NumDips(); i < n; ++i) dialog.Control(i).GetWindow().Position() -= Point(delta.x,0); dialog.Control(IDC_DIPSWITCHES_GROUP).GetWindow().Size() -= delta; if (userOpened) dialog.Control(IDC_DIPSWITCHES_DONTSHOWAGAIN).GetWindow().Destroy(); else dialog.Control(IDC_DIPSWITCHES_DONTSHOWAGAIN).GetWindow().Position() -= Point(0,delta.y); dialog.Control(IDOK).GetWindow().Position() -= delta; dialog.Control(IDCANCEL).GetWindow().Position() -= delta; dialog.Size() -= delta; return true; } ibool DipSwitches::OnCmdOk(Param& param) { if (param.Button().Clicked()) { if (dipSwitches.CanModify()) { for (uint i=0, n=dipSwitches.NumDips(); i < n; ++i) dipSwitches.SetValue( i, dialog.ComboBox( IDC_DIPSWITCHES_1 + i ).Selection().GetIndex() ); } dialog.Close( userOpened ? 0 : dialog.CheckBox(IDC_DIPSWITCHES_DONTSHOWAGAIN).Checked() ); } return true; } } } nestopia-1.51.1/source/win32/NstDialogDipSwitches.hpp000066400000000000000000000033311411157722000224270ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIALOG_DIPSWITCHES_H #define NST_DIALOG_DIPSWITCHES_H #pragma once #include "NstWindowDialog.hpp" #include "../core/api/NstApiDipSwitches.hpp" namespace Nestopia { namespace Window { class DipSwitches { public: explicit DipSwitches(Managers::Emulator&,bool); private: struct Handlers; #ifdef IDC_DIPSWITCHES_9 #error Must update dipswitch dialog fields! #endif enum { MAX_DIPS = IDC_DIPSWITCHES_8+1-IDC_DIPSWITCHES_1 }; ibool OnInitDialog (Param&); ibool OnCmdOk (Param&); Dialog dialog; Nes::DipSwitches dipSwitches; const bool userOpened; public: bool Open() { return dipSwitches.NumDips() ? dialog.Open() : false; } }; } } #endif nestopia-1.51.1/source/win32/NstDialogFds.cpp000066400000000000000000000172471411157722000207230ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstApplicationInstance.hpp" #include "NstWindowUser.hpp" #include "NstIoStream.hpp" #include "NstWindowParam.hpp" #include "NstManagerPaths.hpp" #include "NstDialogFds.hpp" #include "../core/api/NstApiFds.hpp" namespace Nestopia { namespace Window { struct Fds::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; }; const MsgHandler::Entry Fds::Handlers::messages[] = { { WM_INITDIALOG, &Fds::OnInitDialog } }; const MsgHandler::Entry Fds::Handlers::commands[] = { { IDC_FDS_CLEAR, &Fds::OnCmdClear }, { IDC_FDS_BROWSE, &Fds::OnCmdBrowse }, { IDC_FDS_DEFAULT, &Fds::OnCmdDefault }, { IDOK, &Fds::OnCmdOk } }; enum { BIOS_FILE_TYPES = ( Managers::Paths::File::ROM | Managers::Paths::File::INES | Managers::Paths::File::ARCHIVE ) }; Fds::Fds(Managers::Emulator& e,const Configuration& cfg,const Managers::Paths& p) : dialog(IDD_FDS,this,Handlers::messages,Handlers::commands), emulator(e), paths(p) { Configuration::ConstSection fds( cfg["paths"]["fds"] ); const GenericString method( fds["save-method"].Str() ); emulator.SetDiskImageSaveMethod ( ( method == L"disabled" ) ? Managers::Emulator::DISKIMAGE_SAVE_DISABLED : ( method == L"image" ) ? Managers::Emulator::DISKIMAGE_SAVE_TO_IMAGE : Managers::Emulator::DISKIMAGE_SAVE_TO_PATCH ); const GenericString led( fds["led"].Str() ); settings.led = ( ( led == L"numlock" ) ? LED_NUM_LOCK : ( led == L"capslock" ) ? LED_CAPS_LOCK : ( led == L"scrolllock" ) ? LED_SCROLL_LOCK : ( led == L"disabled" ) ? LED_DISABLED : LED_SCREEN ); settings.bios = fds["bios"].Str(); if (settings.bios.Length()) { settings.bios.MakePretty(); } else { settings.bios = "disksys.rom"; if (!paths.FindFile( settings.bios )) settings.bios.Clear(); } if (settings.bios.Length()) SubmitBios(); } Fds::~Fds() { } void Fds::Save(Configuration& cfg) const { Configuration::Section fds( cfg["paths"]["fds"] ); fds["bios"].Str() = settings.bios; fds["save-method"].Str() = ( ( emulator.GetDiskImageSaveMethod() == Managers::Emulator::DISKIMAGE_SAVE_TO_IMAGE ) ? "image" : ( emulator.GetDiskImageSaveMethod() == Managers::Emulator::DISKIMAGE_SAVE_TO_PATCH ) ? "patch" : "disabled" ); fds["led"].Str() = ( ( settings.led == LED_SCREEN ) ? "screen" : ( settings.led == LED_NUM_LOCK ) ? "numlock" : ( settings.led == LED_CAPS_LOCK ) ? "capslock" : ( settings.led == LED_SCROLL_LOCK ) ? "scrolllock" : "disabled" ); } void Fds::QueryBiosFile() { if (settings.bios.Empty()) { settings.bios = paths.BrowseLoad( BIOS_FILE_TYPES ); if (settings.bios.Length()) { settings.bios.MakePretty(); SubmitBios(); } } } void Fds::SubmitBios() { NST_ASSERT( settings.bios.Length() ); Managers::Paths::File file; if (paths.Load( file, BIOS_FILE_TYPES, Path(Application::Instance::GetFullPath(settings.bios.Directory()),settings.bios.File()), Managers::Paths::QUIETLY )) { Io::Stream::In stream( file.data ); if (NES_SUCCEEDED(Nes::Fds(emulator).SetBIOS( &static_cast(stream) ))) return; } settings.bios.Clear(); User::Warn( IDS_FDS_ERR_INVALIDBIOS ); } ibool Fds::OnInitDialog(Param&) { NST_COMPILE_ASSERT ( Managers::Emulator::DISKIMAGE_SAVE_DISABLED == IDC_FDS_SAVEDISABLE - IDC_FDS_SAVEDISABLE && Managers::Emulator::DISKIMAGE_SAVE_TO_IMAGE == IDC_FDS_SAVETOIMAGE - IDC_FDS_SAVEDISABLE && Managers::Emulator::DISKIMAGE_SAVE_TO_PATCH == IDC_FDS_SAVETOPATCH - IDC_FDS_SAVEDISABLE ); if (emulator.IsFdsOn()) { dialog.Control( IDC_FDS_BIOS ).Disable(); dialog.Control( IDC_FDS_CLEAR ).Disable(); dialog.Control( IDC_FDS_BROWSE ).Disable(); } dialog.Edit( IDC_FDS_BIOS ) << settings.bios.Ptr(); dialog.RadioButton( IDC_FDS_SAVEDISABLE + emulator.GetDiskImageSaveMethod() ).Check(); const uint id = ( ( settings.led == LED_SCREEN ) ? IDC_FDS_LED_SCREEN : ( settings.led == LED_NUM_LOCK ) ? IDC_FDS_LED_NUMLOCK : ( settings.led == LED_CAPS_LOCK ) ? IDC_FDS_LED_CAPSLOCK : ( settings.led == LED_SCROLL_LOCK ) ? IDC_FDS_LED_SCROLLLOCK : IDC_FDS_LED_DISABLE ); dialog.RadioButton( id ).Check(); return true; } ibool Fds::OnCmdDefault(Param& param) { if (param.Button().Clicked()) { dialog.RadioButton( IDC_FDS_LED_SCREEN ).Check(); dialog.RadioButton( IDC_FDS_LED_NUMLOCK ).Uncheck(); dialog.RadioButton( IDC_FDS_LED_CAPSLOCK ).Uncheck(); dialog.RadioButton( IDC_FDS_LED_SCROLLLOCK ).Uncheck(); dialog.RadioButton( IDC_FDS_LED_DISABLE ).Uncheck(); dialog.RadioButton( IDC_FDS_SAVETOPATCH ).Check(); dialog.RadioButton( IDC_FDS_SAVETOIMAGE ).Uncheck(); dialog.RadioButton( IDC_FDS_SAVEDISABLE ).Uncheck(); } return true; } ibool Fds::OnCmdClear(Param& param) { if (param.Button().Clicked()) dialog.Edit(IDC_FDS_BIOS).Clear(); return true; } ibool Fds::OnCmdBrowse(Param& param) { if (param.Button().Clicked()) dialog.Edit(IDC_FDS_BIOS).Try() << paths.BrowseLoad( BIOS_FILE_TYPES ).Ptr(); return true; } ibool Fds::OnCmdOk(Param& param) { if (param.Button().Clicked()) { emulator.SetDiskImageSaveMethod ( dialog.RadioButton( IDC_FDS_SAVEDISABLE ).Checked() ? Managers::Emulator::DISKIMAGE_SAVE_DISABLED : dialog.RadioButton( IDC_FDS_SAVETOPATCH ).Checked() ? Managers::Emulator::DISKIMAGE_SAVE_TO_PATCH : Managers::Emulator::DISKIMAGE_SAVE_TO_IMAGE ); settings.led = ( dialog.RadioButton( IDC_FDS_LED_SCREEN ).Checked() ? LED_SCREEN : dialog.RadioButton( IDC_FDS_LED_NUMLOCK ).Checked() ? LED_NUM_LOCK : dialog.RadioButton( IDC_FDS_LED_CAPSLOCK ).Checked() ? LED_CAPS_LOCK : dialog.RadioButton( IDC_FDS_LED_SCROLLLOCK ).Checked() ? LED_SCROLL_LOCK : LED_DISABLED ); Path path; dialog.Edit( IDC_FDS_BIOS ) >> path; path.MakePretty(); if (settings.bios != path) { settings.bios = path; if (settings.bios.Empty()) Nes::Fds(emulator).SetBIOS( NULL ); else SubmitBios(); } dialog.Close(); } return true; } } } nestopia-1.51.1/source/win32/NstDialogFds.hpp000066400000000000000000000036261411157722000207240ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIALOG_FDS_H #define NST_DIALOG_FDS_H #pragma once #include "NstWindowDialog.hpp" namespace Nestopia { namespace Window { class Fds { public: Fds(Managers::Emulator&,const Configuration&,const Managers::Paths&); ~Fds(); void Save(Configuration&) const; void QueryBiosFile(); enum Led { LED_DISABLED, LED_SCREEN, LED_NUM_LOCK, LED_CAPS_LOCK, LED_SCROLL_LOCK }; private: struct Handlers; void SubmitBios(); ibool OnInitDialog (Param&); ibool OnCmdBrowse (Param&); ibool OnCmdDefault (Param&); ibool OnCmdClear (Param&); ibool OnCmdOk (Param&); Dialog dialog; struct { Led led; Path bios; } settings; Managers::Emulator& emulator; const Managers::Paths& paths; public: void Open() { dialog.Open(); } Led GetLed() const { return settings.led; } }; } } #endif nestopia-1.51.1/source/win32/NstDialogFind.cpp000066400000000000000000000061221411157722000210550ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstWindowDialog.hpp" #include "NstDialogFind.hpp" namespace Nestopia { namespace Window { Finder::Finder(Custom& p) : parent(p) { struct Hook { static UINT_PTR CALLBACK FRProc(HWND hWnd,UINT uMsg,WPARAM,LPARAM lParam) { switch (uMsg) { case WM_INITDIALOG: { Generic& window = *reinterpret_cast(reinterpret_cast(lParam)->lCustData); window = hWnd; ::SetWindowLongPtr( hWnd, GWL_USERDATA, reinterpret_cast(&window) ); Dialog::RegisterModeless( hWnd ); return true; } case WM_DESTROY: *reinterpret_cast(::GetWindowLongPtr( hWnd, GWL_USERDATA )) = NULL; Dialog::UnregisterModeless( hWnd ); return false; } return false; } }; if (const uint id = ::RegisterWindowMessage(FINDMSGSTRING)) { p.Messages().Add( id, this, &Finder::OnMsg ); findReplace.lStructSize = sizeof(findReplace); findReplace.lpstrFindWhat = NULL; findReplace.wFindWhatLen = BUFFER_SIZE; findReplace.lCustData = reinterpret_cast(&window); findReplace.lpfnHook = Hook::FRProc; } } void Finder::Close() { if (window) window.Destroy(); } Finder::~Finder() { Close(); delete [] findReplace.lpstrFindWhat; findReplace.lpstrFindWhat = NULL; } void Finder::Open(const Callback& c,const uint flags) { NST_VERIFY( findReplace.lStructSize ); if (window == NULL && findReplace.lStructSize) { callback = c; if (findReplace.lpstrFindWhat == NULL) { findReplace.lpstrFindWhat = new wchar_t [BUFFER_SIZE+1]; findReplace.lpstrFindWhat[0] = '\0'; } findReplace.Flags = (flags & (DOWN|WHOLEWORD|MATCHCASE)) | FR_ENABLEHOOK; findReplace.hwndOwner = parent; ::FindText( &findReplace ); } } ibool Finder::OnMsg(Param&) { if (findReplace.Flags & FR_DIALOGTERM) { Close(); } else if (findReplace.Flags & FR_FINDNEXT) { callback( findReplace.lpstrFindWhat, findReplace.Flags & (FR_WHOLEWORD|FR_MATCHCASE|FR_DOWN) ); } return true; } } } nestopia-1.51.1/source/win32/NstDialogFind.hpp000066400000000000000000000036411411157722000210650ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIALOG_FIND_H #define NST_DIALOG_FIND_H #pragma once #include "NstObjectPod.hpp" #include "NstObjectDelegate.hpp" #include "NstWindowGeneric.hpp" #include "NstString.hpp" #include namespace Nestopia { namespace Window { class Custom; struct Param; class Finder { public: explicit Finder(Custom&); ~Finder(); enum { DOWN = FR_DOWN, WHOLEWORD = FR_WHOLEWORD, MATCHCASE = FR_MATCHCASE }; void Close(); private: typedef Object::Delegate Callback; void Open(const Callback&,uint); ibool OnMsg(Param&); enum {BUFFER_SIZE = 512-1}; Window::Generic window; const Window::Custom& parent; Object::Pod findReplace; Callback callback; public: template void Open(Data* data,Code code,uint dir=DOWN) { Open( Callback(data,code), dir ); } }; } } #endif nestopia-1.51.1/source/win32/NstDialogFrameClock.cpp000066400000000000000000000356311411157722000222120ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstSystemTimer.hpp" #include "NstSystemInfo.hpp" #include "NstWindowParam.hpp" #include "NstApplicationConfiguration.hpp" #include "NstDialogFrameClock.hpp" namespace Nestopia { namespace Window { struct FrameClock::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; }; const MsgHandler::Entry FrameClock::Handlers::messages[] = { { WM_INITDIALOG, &FrameClock::OnInitDialog }, { WM_HSCROLL, &FrameClock::OnHScroll } }; const MsgHandler::Entry FrameClock::Handlers::commands[] = { { IDC_TIMING_SYNC_REFRESH, &FrameClock::OnCmdRefresh }, { IDC_TIMING_AUTO_FRAME_SKIP, &FrameClock::OnCmdRefresh }, { IDC_TIMING_REWINDER, &FrameClock::OnCmdRewinder }, { IDC_TIMING_DEFAULT_SPEED, &FrameClock::OnCmdDefaultSpeed }, { IDC_TIMING_REWINDER_DEFAULT_SPEED, &FrameClock::OnCmdRewinder }, { IDC_TIMING_DEFAULT, &FrameClock::OnCmdDefault }, { IDOK, &FrameClock::OnCmdOk } }; FrameClock::FrameClock(const Configuration& cfg,bool mGPU) : dialog(IDD_TIMING,this,Handlers::messages,Handlers::commands), modernGPU(mGPU) { Configuration::ConstSection timing( cfg["timing"] ); { Configuration::ConstSection autoFrameSkipping( timing["auto-frame-skipping"] ); if (System::Info::GetCpuSpeed() && System::Info::GetCpuSpeed() <= MAX_MHZ_AUTO_FRAME_SKIP_ENABLE) settings.autoFrameSkip = !autoFrameSkipping["enabled"].No(); else settings.autoFrameSkip = autoFrameSkipping["enabled"].Yes(); settings.maxFrameSkips = autoFrameSkipping["max-frames"].Int(); settings.maxFrameSkips = ( settings.maxFrameSkips ? NST_CLAMP(settings.maxFrameSkips,MIN_FRAME_SKIPS,MAX_FRAME_SKIPS) : DEFAULT_FRAME_SKIPS ); } { Configuration::ConstSection performance( timing["performance"] ); if (!modernGPU || System::Info::GetCpuSpeed() <= MAX_MHZ_TRIPLE_BUFFERING_ENABLE) settings.tripleBuffering = !performance["triple-buffering"].No(); else settings.tripleBuffering = performance["triple-buffering"].Yes(); if (!System::Timer::HasPerformanceCounter()) { settings.pfCounter = false; } else if (System::Info::GetCpuCount() == 1) { settings.pfCounter = !performance["high-precision-timer"].No(); } else { settings.pfCounter = performance["high-precision-timer"].Yes(); } settings.vsync = performance["vsync"].Yes(); } { Configuration::ConstSection rewinder( timing["rewinder"] ); settings.rewinder = rewinder["enabled"].Yes(); settings.noRewindSound = rewinder["sound"].No(); settings.useDefaultRewindSpeed = !rewinder["use-native-speed"].No(); settings.rewindSpeed = rewinder["speed"].Int(); settings.rewindSpeed = ( settings.rewindSpeed ? NST_CLAMP(settings.rewindSpeed,MIN_SPEED,MAX_SPEED) : DEFAULT_REWIND_SPEED ); } { Configuration::ConstSection speed( timing["speed"] ); settings.speed = speed["default-speed"].Int(); settings.speed = ( settings.speed ? NST_CLAMP(settings.speed,MIN_SPEED,MAX_SPEED) : DEFAULT_SPEED ); settings.altSpeed = speed["alt-speed"].Int(); settings.altSpeed = ( settings.altSpeed ? NST_CLAMP(settings.altSpeed,MIN_SPEED,MAX_SPEED) : DEFAULT_ALT_SPEED ); settings.noAltSpeedSound = speed["alt-speed-sound"].No(); settings.useDefaultSpeed = !speed["use-native-speed"].No(); } } void FrameClock::Save(Configuration& cfg) const { Configuration::Section timing( cfg["timing"] ); { Configuration::Section rewinder( timing["rewinder"] ); rewinder[ "enabled" ].YesNo() = settings.rewinder; rewinder[ "use-native-speed" ].YesNo() = settings.useDefaultRewindSpeed; rewinder[ "speed" ].Int() = settings.rewindSpeed; rewinder[ "sound" ].YesNo() = !settings.noRewindSound; } { Configuration::Section autoFrameSkipping( timing["auto-frame-skipping"] ); autoFrameSkipping[ "max-frames" ].Int() = settings.maxFrameSkips; autoFrameSkipping[ "enabled" ].YesNo() = settings.autoFrameSkip; } { Configuration::Section speed( timing["speed"] ); speed[ "default-speed" ].Int() = settings.speed; speed[ "alt-speed" ].Int() = settings.altSpeed; speed[ "alt-speed-sound" ].YesNo() = !settings.noAltSpeedSound; speed[ "use-native-speed" ].YesNo() = settings.useDefaultSpeed; } { Configuration::Section performance( timing["performance"] ); performance[ "vsync" ].YesNo() = settings.vsync; performance[ "triple-buffering" ].YesNo() = settings.tripleBuffering; performance[ "high-precision-timer" ].YesNo() = settings.pfCounter; } } void FrameClock::UpdateRewinderEnable() const { const bool enabled = dialog.CheckBox( IDC_TIMING_REWINDER ).Checked(); const bool defaultSpeed = dialog.CheckBox( IDC_TIMING_REWINDER_DEFAULT_SPEED ).Checked(); dialog.Control( IDC_TIMING_REWINDER_DEFAULT_SPEED ).Enable( enabled ); dialog.Control( IDC_TIMING_REWINDER_NOSOUND ).Enable( enabled ); dialog.Control( IDC_TIMING_REWINDER_SPEED ).Enable( enabled && !defaultSpeed ); dialog.Control( IDC_TIMING_REWINDER_SPEED_NUM ).Enable( enabled && !defaultSpeed ); } ibool FrameClock::OnInitDialog(Param&) { dialog.Slider ( IDC_TIMING_SPEED ).SetRange ( MIN_SPEED, MAX_SPEED ); dialog.Slider ( IDC_TIMING_SPEED ).Position() = ( settings.speed ); dialog.Slider ( IDC_TIMING_ALT_SPEED ).SetRange ( MIN_SPEED, MAX_SPEED ); dialog.Slider ( IDC_TIMING_ALT_SPEED ).Position() = ( settings.altSpeed ); dialog.Slider ( IDC_TIMING_REWINDER_SPEED ).SetRange ( MIN_SPEED, MAX_SPEED ); dialog.Slider ( IDC_TIMING_REWINDER_SPEED ).Position() = ( settings.rewindSpeed ); dialog.Slider ( IDC_TIMING_FRAME_SKIPS ).SetRange ( MIN_FRAME_SKIPS, MAX_FRAME_SKIPS ); dialog.Slider ( IDC_TIMING_FRAME_SKIPS ).Position() = ( settings.maxFrameSkips ); dialog.RadioButton ( IDC_TIMING_SYNC_REFRESH ).Check ( !settings.autoFrameSkip ); dialog.RadioButton ( IDC_TIMING_AUTO_FRAME_SKIP ).Check ( settings.autoFrameSkip ); dialog.CheckBox ( IDC_TIMING_VSYNC ).Check ( settings.vsync ); dialog.CheckBox ( IDC_TIMING_TRIPLE_BUFFERING ).Check ( settings.tripleBuffering ); dialog.CheckBox ( IDC_TIMING_ALT_SPEED_NOSOUND ).Check ( settings.noAltSpeedSound ); dialog.CheckBox ( IDC_TIMING_REWINDER ).Check ( settings.rewinder ); dialog.CheckBox ( IDC_TIMING_DEFAULT_SPEED ).Check ( settings.useDefaultSpeed ); dialog.CheckBox ( IDC_TIMING_REWINDER_DEFAULT_SPEED ).Check ( settings.useDefaultRewindSpeed ); dialog.CheckBox ( IDC_TIMING_REWINDER_NOSOUND ).Check ( settings.noRewindSound ); dialog.CheckBox ( IDC_TIMING_PFC ).Check ( settings.pfCounter ); dialog.Control ( IDC_TIMING_PFC ).Enable ( System::Timer::HasPerformanceCounter() ); dialog.Control ( IDC_TIMING_FRAME_SKIPS ).Enable ( settings.autoFrameSkip ); dialog.Control ( IDC_TIMING_FRAME_SKIPS_TEXT ).Enable ( settings.autoFrameSkip ); dialog.Control ( IDC_TIMING_FRAME_SKIPS_NUM ).Enable ( settings.autoFrameSkip ); dialog.Control ( IDC_TIMING_SPEED ).Enable ( !settings.useDefaultSpeed ); dialog.Control ( IDC_TIMING_SPEED_NUM ).Enable ( !settings.useDefaultSpeed ); dialog.Edit( IDC_TIMING_SPEED_NUM ) << uint( settings.speed ); dialog.Edit( IDC_TIMING_ALT_SPEED_NUM ) << uint( settings.altSpeed ); dialog.Edit( IDC_TIMING_REWINDER_SPEED_NUM ) << uint( settings.rewindSpeed ); dialog.Edit( IDC_TIMING_FRAME_SKIPS_NUM ) << uint( settings.maxFrameSkips ); UpdateRewinderEnable(); return true; } ibool FrameClock::OnHScroll(Param& param) { NST_COMPILE_ASSERT ( IDC_TIMING_SPEED == IDC_TIMING_SPEED_NUM-1 && IDC_TIMING_FRAME_SKIPS == IDC_TIMING_FRAME_SKIPS_NUM-1 && IDC_TIMING_ALT_SPEED == IDC_TIMING_ALT_SPEED_NUM-1 && IDC_TIMING_REWINDER_SPEED == IDC_TIMING_REWINDER_SPEED_NUM-1 ); switch (const uint id = param.Slider().GetId()) { case IDC_TIMING_SPEED: case IDC_TIMING_ALT_SPEED: case IDC_TIMING_REWINDER_SPEED: case IDC_TIMING_FRAME_SKIPS: dialog.Edit( id+1 ) << param.Slider().Scroll(); break; } return true; } ibool FrameClock::OnCmdRefresh(Param& param) { if (param.Button().Clicked()) { const bool autoFrameSkip = (param.Button().GetId() == IDC_TIMING_AUTO_FRAME_SKIP); dialog.Control( IDC_TIMING_FRAME_SKIPS ).Enable( autoFrameSkip ); dialog.Control( IDC_TIMING_FRAME_SKIPS_TEXT ).Enable( autoFrameSkip ); dialog.Control( IDC_TIMING_FRAME_SKIPS_NUM ).Enable( autoFrameSkip ); } return true; } ibool FrameClock::OnCmdDefaultSpeed(Param& param) { if (param.Button().Clicked()) { const bool speed = dialog.CheckBox( IDC_TIMING_DEFAULT_SPEED ).Unchecked(); dialog.Control( IDC_TIMING_SPEED ).Enable( speed ); dialog.Control( IDC_TIMING_SPEED_NUM ).Enable( speed ); } return true; } ibool FrameClock::OnCmdRewinder(Param& param) { if (param.Button().Clicked()) UpdateRewinderEnable(); return true; } ibool FrameClock::OnCmdDefault(Param& param) { if (param.Button().Clicked()) { dialog.Slider ( IDC_TIMING_SPEED ).Position() = DEFAULT_SPEED; dialog.Slider ( IDC_TIMING_ALT_SPEED ).Position() = DEFAULT_ALT_SPEED; dialog.Slider ( IDC_TIMING_REWINDER_SPEED ).Position() = DEFAULT_REWIND_SPEED; dialog.Slider ( IDC_TIMING_FRAME_SKIPS ).Position() = DEFAULT_FRAME_SKIPS; dialog.RadioButton ( IDC_TIMING_SYNC_REFRESH ).Check ( true ); dialog.RadioButton ( IDC_TIMING_AUTO_FRAME_SKIP ).Check ( System::Info::GetCpuSpeed() && System::Info::GetCpuSpeed() <= MAX_MHZ_AUTO_FRAME_SKIP_ENABLE ); dialog.CheckBox ( IDC_TIMING_VSYNC ).Check ( false ); dialog.CheckBox ( IDC_TIMING_TRIPLE_BUFFERING ).Check ( !modernGPU || System::Info::GetCpuSpeed() <= MAX_MHZ_TRIPLE_BUFFERING_ENABLE ); dialog.CheckBox ( IDC_TIMING_DEFAULT_SPEED ).Check ( true ); dialog.CheckBox ( IDC_TIMING_ALT_SPEED_NOSOUND ).Check ( false ); dialog.CheckBox ( IDC_TIMING_REWINDER ).Check ( false ); dialog.CheckBox ( IDC_TIMING_REWINDER_DEFAULT_SPEED ).Check ( true ); dialog.CheckBox ( IDC_TIMING_REWINDER_NOSOUND ).Check ( false ); dialog.CheckBox ( IDC_TIMING_PFC ).Check ( System::Timer::HasPerformanceCounter() && System::Info::GetCpuCount() == 1 ); dialog.Control ( IDC_TIMING_PFC ).Enable ( System::Timer::HasPerformanceCounter() ); dialog.Control ( IDC_TIMING_FRAME_SKIPS ).Enable ( false ); dialog.Control ( IDC_TIMING_FRAME_SKIPS_TEXT ).Enable ( false ); dialog.Control ( IDC_TIMING_FRAME_SKIPS_NUM ).Enable ( false ); dialog.Control ( IDC_TIMING_SPEED ).Enable ( false ); dialog.Control ( IDC_TIMING_SPEED_NUM ).Enable ( false ); dialog.Edit ( IDC_TIMING_SPEED_NUM ) << uint(DEFAULT_SPEED); dialog.Edit ( IDC_TIMING_ALT_SPEED_NUM ) << uint(DEFAULT_ALT_SPEED); dialog.Edit ( IDC_TIMING_REWINDER_SPEED_NUM ) << uint(DEFAULT_REWIND_SPEED); dialog.Edit ( IDC_TIMING_FRAME_SKIPS_NUM ) << uint(DEFAULT_FRAME_SKIPS); UpdateRewinderEnable(); } return true; } ibool FrameClock::OnCmdOk(Param& param) { if (param.Button().Clicked()) { settings.autoFrameSkip = dialog.RadioButton ( IDC_TIMING_AUTO_FRAME_SKIP ).Checked(); settings.vsync = dialog.CheckBox ( IDC_TIMING_VSYNC ).Checked(); settings.tripleBuffering = dialog.CheckBox ( IDC_TIMING_TRIPLE_BUFFERING ).Checked(); settings.rewinder = dialog.CheckBox ( IDC_TIMING_REWINDER ).Checked(); settings.useDefaultSpeed = dialog.CheckBox ( IDC_TIMING_DEFAULT_SPEED ).Checked(); settings.useDefaultRewindSpeed = dialog.CheckBox ( IDC_TIMING_REWINDER_DEFAULT_SPEED ).Checked(); settings.noAltSpeedSound = dialog.CheckBox ( IDC_TIMING_ALT_SPEED_NOSOUND ).Checked(); settings.noRewindSound = dialog.CheckBox ( IDC_TIMING_REWINDER_NOSOUND ).Checked(); settings.pfCounter = dialog.CheckBox ( IDC_TIMING_PFC ).Checked(); settings.speed = dialog.Slider ( IDC_TIMING_SPEED ).Position(); settings.altSpeed = dialog.Slider ( IDC_TIMING_ALT_SPEED ).Position(); settings.rewindSpeed = dialog.Slider ( IDC_TIMING_REWINDER_SPEED ).Position(); settings.maxFrameSkips = dialog.Slider ( IDC_TIMING_FRAME_SKIPS ).Position(); dialog.Close(); } return true; } } } nestopia-1.51.1/source/win32/NstDialogFrameClock.hpp000066400000000000000000000067001411157722000222120ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIALOG_FRAMECLOCK_H #define NST_DIALOG_FRAMECLOCK_H #pragma once #include "NstWindowDialog.hpp" #include "NstManagerEmulator.hpp" #include "../core/api/NstApiMachine.hpp" namespace Nestopia { namespace Window { class FrameClock { public: FrameClock(const Configuration&,bool); void Save(Configuration&) const; private: struct Handlers; enum { MIN_SPEED = 30, MAX_SPEED = 240, MIN_FRAME_SKIPS = 1, MAX_FRAME_SKIPS = 16, DEFAULT_SPEED = Nes::Machine::CLK_NTSC_DOT / Nes::Machine::CLK_NTSC_VSYNC, DEFAULT_ALT_SPEED = DEFAULT_SPEED * 2, DEFAULT_REWIND_SPEED = DEFAULT_SPEED, DEFAULT_FRAME_SKIPS = 8, MAX_MHZ_TRIPLE_BUFFERING_ENABLE = 1350, MAX_MHZ_AUTO_FRAME_SKIP_ENABLE = 950 }; void UpdateRewinderEnable() const; ibool OnInitDialog (Param&); ibool OnHScroll (Param&); ibool OnCmdRefresh (Param&); ibool OnCmdDefaultSpeed (Param&); ibool OnCmdRewinder (Param&); ibool OnCmdDefault (Param&); ibool OnCmdOk (Param&); struct { bool autoFrameSkip; bool vsync; bool tripleBuffering; bool rewinder; bool useDefaultSpeed; bool useDefaultRewindSpeed; bool noAltSpeedSound; bool noRewindSound; bool pfCounter; uchar speed; uchar altSpeed; uchar rewindSpeed; uchar maxFrameSkips; } settings; Dialog dialog; const bool modernGPU; public: void Open() { dialog.Open(); } uint UsePerformanceCounter() const { return settings.pfCounter; } bool UseAutoFrameSkip() const { return settings.autoFrameSkip; } bool UseVSync() const { return settings.vsync; } bool UseTrippleBuffering() const { return settings.tripleBuffering; } bool UseRewinder() const { return settings.rewinder; } bool UseDefaultSpeed() const { return settings.useDefaultSpeed; } bool UseDefaultRewindSpeed() const { return settings.useDefaultRewindSpeed; } bool NoRewindSound() const { return settings.noRewindSound; } bool NoAltSpeedSound() const { return settings.noAltSpeedSound; } uint GetSpeed() const { return settings.speed; } uint GetAltSpeed() const { return settings.altSpeed; } uint GetRewindSpeed() const { return settings.rewindSpeed; } uint GetMaxFrameSkips() const { return settings.maxFrameSkips; } }; } } #endif nestopia-1.51.1/source/win32/NstDialogImageDatabase.cpp000066400000000000000000000144351411157722000226520ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "resource/resource.h" #include "NstWindowParam.hpp" #include "NstWindowUser.hpp" #include "NstIoStream.hpp" #include "NstResourceFile.hpp" #include "NstManagerPaths.hpp" #include "NstApplicationInstance.hpp" #include "NstDialogImageDatabase.hpp" #include "../core/api/NstApiCartridge.hpp" namespace Nestopia { namespace Window { struct ImageDatabase::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; }; const MsgHandler::Entry ImageDatabase::Handlers::messages[] = { { WM_INITDIALOG, &ImageDatabase::OnInitDialog } }; const MsgHandler::Entry ImageDatabase::Handlers::commands[] = { { IDC_IMAGEDATABASE_EXTERNAL, &ImageDatabase::OnCmdExternal }, { IDC_IMAGEDATABASE_CLEAR, &ImageDatabase::OnCmdClear }, { IDC_IMAGEDATABASE_BROWSE, &ImageDatabase::OnCmdBrowse }, { IDC_IMAGEDATABASE_DEFAULT, &ImageDatabase::OnCmdDefault }, { IDOK, &ImageDatabase::OnCmdOk } }; ImageDatabase::ImageDatabase(Managers::Emulator& e,const Configuration& cfg,const Managers::Paths& p) : dialog (IDD_IMAGE_DATABASE,this,Handlers::messages,Handlers::commands), emulator (e), paths (p) { Configuration::ConstSection database( cfg["image-database"] ); settings.internal = !database["internal"].No(); settings.external = database["external"].Yes(); settings.file = database["file"].Str(); Nes::Cartridge(emulator).GetDatabase().Enable(); Update(false); } ImageDatabase::~ImageDatabase() { } void ImageDatabase::Save(Configuration& cfg) const { Configuration::Section database( cfg["image-database"] ); database["internal"].YesNo() = settings.internal; database["external"].YesNo() = settings.external; database["file"].Str() = settings.file; } void ImageDatabase::Update(const bool reportError) { try { Application::Instance::Waiter wait; Nes::Cartridge(emulator).GetDatabase().Unload(); if (settings.internal || settings.external) { Collection::Buffer internal; if (settings.internal) Resource::File( IDR_IMAGEDATABASE, L"ImageDatabase" ).Uncompress( internal ); if (settings.external && settings.file.Empty()) settings.external = false; if (settings.external && internal.Size()) { Io::Stream::In stream0( Application::Instance::GetFullPath(settings.file) ); Io::Stream::In stream1( internal ); if (NES_FAILED(Nes::Cartridge(emulator).GetDatabase().Load( stream0, stream1 ))) throw 1; } else if (settings.external) { Io::Stream::In stream( Application::Instance::GetFullPath(settings.file) ); if (NES_FAILED(Nes::Cartridge(emulator).GetDatabase().Load( stream ))) throw 1; } else if (internal.Size()) { Io::Stream::In stream( internal ); if (NES_FAILED(Nes::Cartridge(emulator).GetDatabase().Load( stream ))) throw 1; } } } catch (...) { settings.external = false; if (reportError) Window::User::Fail( IDS_EXT_DATABASE_LOAD_FAILED ); else Window::User::Warn( IDS_EXT_DATABASE_LOAD_FAILED ); } } ibool ImageDatabase::OnInitDialog(Param&) { dialog.CheckBox( IDC_IMAGEDATABASE_INTERNAL ).Check( settings.internal ); dialog.CheckBox( IDC_IMAGEDATABASE_EXTERNAL ).Check( settings.external ); dialog.Edit( IDC_IMAGEDATABASE_FILE ) << settings.file.Ptr(); UpdateAvailibility(); return true; } void ImageDatabase::UpdateAvailibility() const { const bool external = dialog.CheckBox( IDC_IMAGEDATABASE_EXTERNAL ).Checked(); dialog.Edit( IDC_IMAGEDATABASE_FILE ).Enable( external ); dialog.Edit( IDC_IMAGEDATABASE_BROWSE ).Enable( external ); dialog.Edit( IDC_IMAGEDATABASE_CLEAR ).Enable( external ); } ibool ImageDatabase::OnCmdExternal(Param& param) { if (param.Button().Clicked()) UpdateAvailibility(); return true; } ibool ImageDatabase::OnCmdClear(Param& param) { if (param.Button().Clicked()) dialog.Edit( IDC_IMAGEDATABASE_FILE ).Clear(); return true; } ibool ImageDatabase::OnCmdBrowse(Param& param) { if (param.Button().Clicked()) { Path tmp; dialog.Edit( IDC_IMAGEDATABASE_FILE ).Text() >> tmp; dialog.Edit( IDC_IMAGEDATABASE_FILE ).Try() << paths.BrowseLoad( Managers::Paths::File::XML ).Ptr(); } return true; } ibool ImageDatabase::OnCmdDefault(Param& param) { if (param.Button().Clicked()) { dialog.CheckBox( IDC_IMAGEDATABASE_INTERNAL ).Check( true ); dialog.CheckBox( IDC_IMAGEDATABASE_EXTERNAL ).Check( false ); UpdateAvailibility(); } return true; } ibool ImageDatabase::OnCmdOk(Param& param) { if (param.Button().Clicked()) { const bool oldInternal = settings.internal; const bool oldExternal = settings.external; settings.internal = dialog.CheckBox( IDC_IMAGEDATABASE_INTERNAL ).Checked(); settings.external = dialog.CheckBox( IDC_IMAGEDATABASE_EXTERNAL ).Checked(); const Path oldFile(settings.file); dialog.Edit(IDC_IMAGEDATABASE_FILE) >> settings.file; if ((settings.internal != oldInternal || settings.external != oldExternal) || (settings.external && settings.file != oldFile)) Update(false); dialog.Close(); } return true; } } } nestopia-1.51.1/source/win32/NstDialogImageDatabase.hpp000066400000000000000000000035551411157722000226600ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIALOG_IMAGEDATABASE_H #define NST_DIALOG_IMAGEDATABASE_H #pragma once #include "NstWindowDialog.hpp" namespace Nestopia { namespace Window { class ImageDatabase { public: explicit ImageDatabase(Managers::Emulator&,const Configuration&,const Managers::Paths&); ~ImageDatabase(); void Save(Configuration&) const; private: struct Handlers; void Update(bool); void UpdateAvailibility() const; ibool OnInitDialog (Param&); ibool OnCmdExternal (Param&); ibool OnCmdBrowse (Param&); ibool OnCmdClear (Param&); ibool OnCmdDefault (Param&); ibool OnCmdOk (Param&); Dialog dialog; Managers::Emulator& emulator; const Managers::Paths& paths; struct { Path file; bool internal; bool external; } settings; public: void Open() { dialog.Open(); } }; } } #endif nestopia-1.51.1/source/win32/NstDialogImageInfo.cpp000066400000000000000000000320671411157722000220420ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstWindowParam.hpp" #include "NstResourceString.hpp" #include "NstManagerEmulator.hpp" #include "NstDialogImageInfo.hpp" #include "../core/api/NstApiCartridge.hpp" #include "../core/api/NstApiFds.hpp" #include "../core/api/NstApiNsf.hpp" namespace Nestopia { namespace Window { ImageInfo::ImageInfo(Managers::Emulator& e) : dialog (IDD_IMAGE_INFO,WM_INITDIALOG,this,&ImageInfo::OnInitDialog), emulator (e) { } ibool ImageInfo::OnInitDialog(Param&) { struct Table { static void Tab(HeapString* const strings,const uint count,const bool fixed) { if (fixed) { uint maxTab = 0; for (uint i=0; i < count; ++i) maxTab = NST_MAX(maxTab,strings[i].Length()); maxTab += 2; for (uint i=0; i < count; ++i) { if (uint pos = strings[i].Length()) { strings[i].Resize( maxTab ); strings[i][pos] = ':'; while (++pos < maxTab) strings[i][pos] = ' '; } } } else for (uint i=0; i < count; ++i) { if (strings[i].Length()) strings[i] << ": "; } } static void Output(HeapString& output,HeapString* const strings,const uint count) { for (uint i=0; i < count; ++i) { if (strings[i].Length()) { output << strings[i]; if (i < count-1) output << "\r\n"; } } } }; HeapString text; const bool fixedFont = dialog.Edit(IDC_IMAGE_INFO_EDIT).FixedFont(); if (emulator.IsCart()) { typedef Nes::Cartridge::Profile Profile; enum { SP_H = Profile::Board::SOLDERPAD_H, SP_V = Profile::Board::SOLDERPAD_V }; const Profile& profile = *Nes::Cartridge(emulator).GetProfile(); HeapString types[] = { !profile.game.title.empty() ? Resource::String( IDS_TEXT_NAME ) : HeapString(), !profile.game.altTitle.empty() ? Resource::String( IDS_TEXT_ALTNAME ) : HeapString(), !profile.game.publisher.empty() ? Resource::String( IDS_TEXT_PUBLISHER ) : HeapString(), !profile.game.developer.empty() ? Resource::String( IDS_TEXT_DEVELOPER ) : HeapString(), !profile.game.region.empty() ? Resource::String( IDS_TEXT_REGION ) : HeapString(), profile.game.players ? Resource::String( IDS_TEXT_PLAYERS ) : HeapString(), Resource::String( IDS_TEXT_FILE ), Resource::String( IDS_TEXT_DIRECTORY ), Resource::String( IDS_TEXT_SOFTPATCHED ), "CRC", "SHA-1", Resource::String( IDS_TEXT_SYSTEM ), Resource::String( IDS_TEXT_BOARD ), profile.board.GetPrg() ? "PRG-ROM" : HeapString(), profile.board.GetChr() ? "CHR-ROM" : HeapString(), profile.board.GetVram() ? "V-RAM" : HeapString(), profile.board.GetWram() ? "W-RAM" : HeapString(), !profile.board.chips.empty() ? Resource::String( IDS_TEXT_CHIPS ) : HeapString(), profile.board.solderPads & (SP_H|SP_V) ? Resource::String( IDS_TEXT_SOLDERPAD ) : HeapString(), Resource::String( IDS_TEXT_BATTERY ), profile.board.HasBattery() ? Resource::String( IDS_TEXT_FILE ) : HeapString(), profile.board.HasBattery() ? Resource::String( IDS_TEXT_DIRECTORY ) : HeapString(), Resource::String( IDS_TEXT_DUMP ) }; Table::Tab( types, sizeof(array(types)), fixedFont ); if (!profile.game.title.empty()) types[0] << profile.game.title.c_str(); if (!profile.game.title.empty()) types[1] << profile.game.altTitle.c_str(); if (!profile.game.publisher.empty()) types[2] << profile.game.publisher.c_str(); if (!profile.game.developer.empty()) types[3] << profile.game.developer.c_str(); if (!profile.game.region.empty()) types[4] << profile.game.region.c_str(); if (profile.game.players) types[5] << profile.game.players; types[6] << emulator.GetImagePath().File(); types[7] << emulator.GetImagePath().Directory(); types[8] << Resource::String( profile.patched ? IDS_TEXT_YES : IDS_TEXT_NO );; { char sha1[41] = {0}; char crc32[9] = {0}; profile.hash.Get( sha1, crc32 ); types[9] << crc32; types[10] << sha1; } types[11] << Resource::String ( profile.system.type == Profile::System::VS_UNISYSTEM ? IDS_TEXT_VSUNISYSTEM : profile.system.type == Profile::System::VS_DUALSYSTEM ? IDS_TEXT_VSDUALSYSTEM : profile.system.type == Profile::System::PLAYCHOICE_10 ? IDS_TEXT_PLAYCHOICE10 : profile.system.type == Profile::System::NES_PAL ? IDS_TEXT_NES_PAL : profile.system.type == Profile::System::NES_PAL_A ? IDS_TEXT_NES_PAL_A : profile.system.type == Profile::System::NES_PAL_B ? IDS_TEXT_NES_PAL_B : profile.system.type == Profile::System::FAMICOM ? IDS_TEXT_FAMICOM : profile.system.type == Profile::System::DENDY ? IDS_TEXT_DENDY : IDS_TEXT_NES_NTSC ); types[12] << profile.board.type.c_str(); if (profile.board.mapper && profile.board.mapper != Profile::Board::NO_MAPPER) types[12] << ", " << Resource::String( IDS_TEXT_MAPPER ) << ' ' << profile.board.mapper; if (const uint prg = profile.board.GetPrg()) types[13] << (prg % 1024 ? prg : prg / 1024) << (prg % 1024 ? " bytes" : "k"); if (const uint chr = profile.board.GetChr()) types[14] << (chr % 1024 ? chr : chr / 1024) << (chr % 1024 ? " bytes" : "k"); if (const uint vram = profile.board.GetVram()) types[15] << (vram % 1024 ? vram : vram / 1024) << (vram % 1024 ? " bytes" : "k"); if (const uint wram = profile.board.GetWram()) types[16] << (wram % 1024 ? wram : wram / 1024) << (wram % 1024 ? " bytes" : "k"); for (uint i=0, n=profile.board.chips.size(); i < n; ++i) { if (i) types[17] << ", "; types[17] << profile.board.chips[i].type.c_str(); } if (profile.board.solderPads & (SP_H|SP_V)) { types[18] << "H:" << ((profile.board.solderPads & SP_H) ? '1' : '0') << " V:" << ((profile.board.solderPads & SP_V) ? '1' : '0'); } types[19] << Resource::String( profile.board.HasBattery() ? IDS_TEXT_YES : IDS_TEXT_NO ); if (profile.board.HasBattery()) { types[20] << emulator.GetSavePath().File(); types[21] << emulator.GetSavePath().Directory(); } types[22] << Resource::String ( profile.dump.state == Profile::Dump::OK ? IDS_TEXT_OK : profile.dump.state == Profile::Dump::BAD ? IDS_TEXT_BAD : IDS_TEXT_UNKNOWN ); Table::Output( text, types, sizeof(array(types)) ); } else if (emulator.IsFds()) { const Nes::Fds fds(emulator); std::vector types( 3 + NST_MAX(fds.GetNumSides()/2,1) ); types[0] = Resource::String( IDS_TEXT_FILE ); types[1] = Resource::String( IDS_TEXT_DIRECTORY ); types[2] = Resource::String( IDS_TEXT_HEADER ); for (uint i=3, n=types.size(); i < n; ++i) types[i] = Resource::String( IDS_TEXT_DISK ).Invoke( i-3+1 ); Table::Tab( &types.front(), types.size(), fixedFont ); types[0] << emulator.GetImagePath().File(); types[1] << emulator.GetImagePath().Directory(); types[2] << Resource::String( fds.HasHeader() ? IDS_TEXT_YES : IDS_TEXT_NO ); for (uint i=0, n=fds.GetNumSides(); i < n; ++i) { Nes::Fds::DiskData data; fds.GetDiskData( i, data ); uint size = 0; for (Nes::Fds::DiskData::Files::const_iterator it(data.files.begin()), end(data.files.end()); it != end; ++it) size += it->data.size(); types[3+i/2] << (i % 2 ? ", B: " : "A: ") << (size / 1024) << "k " << Resource::String( IDS_TEXT_IN_FILES ).Invoke( data.files.size() ); if (!data.raw.empty()) types[3+i/2] << ", " << Resource::String( IDS_TEXT_TRAILING_DATA ).Invoke( data.raw.size() ); } Table::Output( text, &types.front(), types.size() ); } else if (emulator.IsNsf()) { const Nes::Nsf nsf(emulator); HeapString types[] = { Resource::String( IDS_TEXT_FILE ), Resource::String( IDS_TEXT_DIRECTORY ), *nsf.GetName() ? Resource::String( IDS_TEXT_NAME ) : HeapString(), *nsf.GetArtist() ? Resource::String( IDS_TEXT_ARTIST ) : HeapString(), *nsf.GetCopyright() ? Resource::String( IDS_TEXT_COPYRIGHT ) : HeapString(), Resource::String( IDS_TEXT_REGION ), Resource::String( IDS_TEXT_SONGS ), nsf.GetNumSongs() > 1 ? Resource::String( IDS_TEXT_STARTINGSONG ) : HeapString(), Resource::String( IDS_TEXT_EXTRACHIPS ), Resource::String( IDS_TEXT_BANKSWITCHING ), Resource::String( IDS_TEXT_LOADADDRESS ), Resource::String( IDS_TEXT_INITADDRESS ), Resource::String( IDS_TEXT_PLAYADDRESS ) }; Table::Tab( types, sizeof(array(types)), fixedFont ); types[0] << emulator.GetImagePath().File(); types[1] << emulator.GetImagePath().Directory(); if (*nsf.GetName()) types[2].Import( nsf.GetName() ); if (*nsf.GetArtist()) types[3].Import( nsf.GetArtist() ); if (*nsf.GetCopyright()) types[4].Import( nsf.GetCopyright() ); types[5] << ( nsf.GetMode() == Nes::Nsf::TUNE_MODE_NTSC ? "NTSC" : nsf.GetMode() == Nes::Nsf::TUNE_MODE_PAL ? "PAL" : "NTSC/PAL" ); types[6] << nsf.GetNumSongs(); if (nsf.GetNumSongs() > 1) types[7] << (nsf.GetStartingSong() + 1); if (const uint chips = nsf.GetChips()) { cstring c = ""; if ( chips & Nes::Nsf::CHIP_MMC5 ) { types[8] << "MMC5"; c = "+"; } if ( chips & Nes::Nsf::CHIP_VRC6 ) { types[8] << c << "VRC6"; c = "+"; } if ( chips & Nes::Nsf::CHIP_VRC7 ) { types[8] << c << "VRC7"; c = "+"; } if ( chips & Nes::Nsf::CHIP_N163 ) { types[8] << c << "N163"; c = "+"; } if ( chips & Nes::Nsf::CHIP_S5B ) { types[8] << c << "Sunsoft5B"; c = "+"; } if ( chips & Nes::Nsf::CHIP_FDS ) { types[8] << c << "FDS"; c = "+"; } } else { types[8] << Resource::String( IDS_TEXT_NO ); } types[9] << Resource::String( nsf.UsesBankSwitching() ? IDS_TEXT_YES : IDS_TEXT_NO ); types[10] << HexString( 16, nsf.GetLoadAddress() ); types[11] << HexString( 16, nsf.GetInitAddress() ); types[12] << HexString( 16, nsf.GetPlayAddress() ); Table::Output( text, types, sizeof(array(types)) ); } if (text.Length()) { dialog.Edit(IDC_IMAGE_INFO_EDIT) << text.Ptr(); Point size( dialog.Edit(IDC_IMAGE_INFO_EDIT).GetMaxTextSize() ); Point delta( dialog.Edit(IDC_IMAGE_INFO_EDIT).GetWindow().Size() ); if (size.x > delta.x) { size.x = delta.x; size.y += ::GetSystemMetrics(SM_CXVSCROLL); ::ShowScrollBar( dialog.Control(IDC_IMAGE_INFO_EDIT).GetWindow(), SB_HORZ, true ); } if (size != delta) { dialog.Edit(IDC_IMAGE_INFO_EDIT).GetWindow().Size() = size; delta -= size; dialog.Control(IDOK).GetWindow().Position() -= delta; dialog.Size() -= delta; } } return true; } } } nestopia-1.51.1/source/win32/NstDialogImageInfo.hpp000066400000000000000000000026521411157722000220440ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIALOG_IMAGEINFO_H #define NST_DIALOG_IMAGEINFO_H #pragma once #include "NstWindowDialog.hpp" namespace Nestopia { namespace Window { class ImageInfo { public: explicit ImageInfo(Managers::Emulator&); private: ibool OnInitDialog (Param&); ibool OnCmdOk (Param&); Dialog dialog; Managers::Emulator& emulator; public: void Open() { dialog.Open(); } }; } } #endif nestopia-1.51.1/source/win32/NstDialogInesHeader.cpp000066400000000000000000000505161411157722000222120ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstWindowParam.hpp" #include "NstWindowUser.hpp" #include "NstResourceString.hpp" #include "NstIoFile.hpp" #include "NstManagerPaths.hpp" #include "../core/api/NstApiCartridge.hpp" #include "NstDialogInesHeader.hpp" namespace Nestopia { namespace Window { class InesHeader::CustomSize { public: explicit CustomSize(uint&); private: struct Handlers; ibool OnInitDialog (Param&); ibool OnCmdOk (Param&); uint& size; Dialog dialog; public: void Open() { dialog.Open(); } }; struct InesHeader::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; }; const MsgHandler::Entry InesHeader::Handlers::messages[] = { { WM_INITDIALOG, &InesHeader::OnInitDialog }, }; const MsgHandler::Entry InesHeader::Handlers::commands[] = { { IDC_INES_HEADER_TYPE_STD, &InesHeader::OnCmdFileType }, { IDC_INES_HEADER_TYPE_EXT, &InesHeader::OnCmdFileType }, { IDC_INES_HEADER_PRGROM_LIST, &InesHeader::OnCmdSizeOther }, { IDC_INES_HEADER_PRGRAM_LIST, &InesHeader::OnCmdSizeOther }, { IDC_INES_HEADER_CHRROM_LIST, &InesHeader::OnCmdSizeOther }, { IDC_INES_HEADER_SYSTEM_HOME, &InesHeader::OnCmdSystem }, { IDC_INES_HEADER_SYSTEM_VS, &InesHeader::OnCmdSystem }, { IDC_INES_HEADER_SYSTEM_PC10, &InesHeader::OnCmdSystem }, { IDC_INES_HEADER_UNDOALL, &InesHeader::OnCmdUndoAll }, { IDC_INES_HEADER_SAVE, &InesHeader::OnCmdSave } }; InesHeader::InesHeader(const Managers::Paths& p) : dialog(IDD_INES_HEADER,this,Handlers::messages,Handlers::commands), paths(p) {} uint InesHeader::Import(const Path& loadPath,Collection::Buffer& buffer) { NST_ASSERT( buffer.Empty() ); try { Io::File file( loadPath, Io::File::COLLECT ); if (file.Size() >= HEADER_SIZE && file.Peek32() == HEADER_ID) { file.Stream() >> buffer; return 0; } else { return IDS_FILE_ERR_INVALID; } } catch (Io::File::Exception ids) { return ids; } catch (const std::bad_alloc&) { return IDS_ERR_OUT_OF_MEMORY; } catch (...) { return IDS_ERR_GENERIC; } } uint InesHeader::Export(const Path& savePath,const Collection::Buffer& buffer) { NST_ASSERT( buffer.Size() >= HEADER_SIZE ); try { Io::File file( savePath, Io::File::READ|Io::File::WRITE ); if (file.Size() == 0 || file.Peek32() == HEADER_ID) { file.Stream() << buffer; return 0; } else { return IDS_FILE_ERR_INVALID; } } catch (Io::File::Exception i) { return i; } catch (const std::bad_alloc&) { return IDS_ERR_OUT_OF_MEMORY; } catch (...) { return IDS_ERR_GENERIC; } } void InesHeader::Open(const Path& p) { if (p.Length()) { { Collection::Buffer buffer; if (const uint result = Import( p, buffer )) { User::Fail( result ); return; } std::memcpy( header, buffer.Ptr(), HEADER_SIZE ); } path = &p; dialog.Open(); } } ibool InesHeader::OnInitDialog(Param&) { NST_COMPILE_ASSERT ( Nes::Cartridge::Profile::System::PPU_RP2C02 == 0 && Nes::Cartridge::Profile::System::PPU_RP2C03B == 1 && Nes::Cartridge::Profile::System::PPU_RP2C03G == 2 && Nes::Cartridge::Profile::System::PPU_RP2C04_0001 == 3 && Nes::Cartridge::Profile::System::PPU_RP2C04_0002 == 4 && Nes::Cartridge::Profile::System::PPU_RP2C04_0003 == 5 && Nes::Cartridge::Profile::System::PPU_RP2C04_0004 == 6 && Nes::Cartridge::Profile::System::PPU_RC2C03B == 7 && Nes::Cartridge::Profile::System::PPU_RC2C03C == 8 && Nes::Cartridge::Profile::System::PPU_RC2C05_01 == 9 && Nes::Cartridge::Profile::System::PPU_RC2C05_02 == 10 && Nes::Cartridge::Profile::System::PPU_RC2C05_03 == 11 && Nes::Cartridge::Profile::System::PPU_RC2C05_04 == 12 && Nes::Cartridge::Profile::System::PPU_RC2C05_05 == 13 && Nes::Cartridge::Profile::System::PPU_RP2C07 == 14 ); static const wcstring vsPPU[] = { L"RP2C03B", L"RP2C03G", L"PR2C04-0001", L"RP2C04-0002", L"RP2C04-0003", L"RP2C04-0004", L"RC2C03B", L"RC2C03C", L"RC2C05-01", L"RC2C05-02", L"RC2C05-03", L"RC2C05-04", L"RC2C05-05" }; Control::ComboBox combo( dialog.ComboBox( IDC_INES_HEADER_VS_PPU_LIST ) ); combo.Add( vsPPU, sizeof(array(vsPPU)) ); combo[0].Select(); static const wcstring vsModes[] = { L"Standard", L"RBI Baseball", L"TKO Boxing", L"Super Xevious" }; combo = dialog.ComboBox( IDC_INES_HEADER_VS_MODE_LIST ); combo.Add( vsModes, sizeof(array(vsModes)) ); combo[0].Select(); dialog.Edit( IDC_INES_HEADER_MAPPER_BASE_VALUE ).Limit( 3 ); dialog.Edit( IDC_INES_HEADER_MAPPER_SUB_VALUE ).Limit( 2 ); Nes::Cartridge::NesHeader setup; setup.Import( header, HEADER_SIZE ); UpdateHeader( setup ); return true; } bool InesHeader::OkToSave(const uint fileSize) const { const uint saveSize = ( HEADER_SIZE + (dialog.CheckBox( IDC_INES_HEADER_TRAINER ).Checked() ? 512 : 0) + (dialog.ComboBox( IDC_INES_HEADER_PRGROM_LIST ).Selection().Data()) + (dialog.ComboBox( IDC_INES_HEADER_CHRROM_LIST ).Selection().Data()) ); return saveSize <= fileSize || User::Confirm( IDS_INES_HEADER_UNSAFE ); } bool InesHeader::SaveHeader(Header& save) const { Nes::Cartridge::NesHeader setup; setup.version = (dialog.RadioButton( IDC_INES_HEADER_TYPE_EXT ).Checked() ? 2 : 0); if (dialog.RadioButton( IDC_INES_HEADER_SYSTEM_VS ).Checked()) { setup.system = Nes::Cartridge::NesHeader::SYSTEM_VS; } else if (dialog.RadioButton( IDC_INES_HEADER_SYSTEM_PC10 ).Checked()) { setup.system = Nes::Cartridge::NesHeader::SYSTEM_PC10; } else { setup.system = Nes::Cartridge::NesHeader::SYSTEM_CONSOLE; } if (dialog.RadioButton( IDC_INES_HEADER_REGION_BOTH ).Checked()) { setup.region = Nes::Cartridge::NesHeader::REGION_BOTH; } else if (dialog.RadioButton( IDC_INES_HEADER_REGION_PAL ).Checked()) { setup.region = Nes::Cartridge::NesHeader::REGION_PAL; } else { setup.region = Nes::Cartridge::NesHeader::REGION_NTSC; } setup.prgRom = dialog.ComboBox( IDC_INES_HEADER_PRGROM_LIST ).Selection().Data(); setup.prgRam = dialog.ComboBox( IDC_INES_HEADER_PRGRAM_LIST ).Selection().Data(); setup.prgNvRam = dialog.ComboBox( IDC_INES_HEADER_PRGNVRAM_LIST ).Selection().Data(); setup.chrRom = dialog.ComboBox( IDC_INES_HEADER_CHRROM_LIST ).Selection().Data(); setup.chrRam = dialog.ComboBox( IDC_INES_HEADER_CHRRAM_LIST ).Selection().Data(); setup.chrNvRam = dialog.ComboBox( IDC_INES_HEADER_CHRNVRAM_LIST ).Selection().Data(); if (setup.system == Nes::Cartridge::NesHeader::SYSTEM_VS) { setup.ppu = static_cast(dialog.ComboBox( IDC_INES_HEADER_VS_PPU_LIST ).Selection().GetIndex() + 1); setup.security = dialog.ComboBox( IDC_INES_HEADER_VS_MODE_LIST ).Selection().GetIndex(); } else { setup.ppu = Nes::Cartridge::NesHeader::PPU_RP2C02; setup.security = 0; } if (dialog.RadioButton( IDC_INES_HEADER_FOURSCREEN ).Checked()) { setup.mirroring = Nes::Cartridge::NesHeader::MIRRORING_FOURSCREEN; } else if (dialog.RadioButton( IDC_INES_HEADER_HORIZONTAL ).Checked()) { setup.mirroring = Nes::Cartridge::NesHeader::MIRRORING_HORIZONTAL; } else { setup.mirroring = Nes::Cartridge::NesHeader::MIRRORING_VERTICAL; } if (!(dialog.Edit( IDC_INES_HEADER_MAPPER_BASE_VALUE ) >> setup.mapper)) return false; setup.subMapper = 0; if (setup.version && !(dialog.Edit( IDC_INES_HEADER_MAPPER_SUB_VALUE ) >> setup.subMapper)) return false; setup.trainer = dialog.CheckBox( IDC_INES_HEADER_TRAINER ).Checked(); if (NES_FAILED(setup.Export( save, HEADER_SIZE ))) return false; uchar reserved[HEADER_SIZE]; std::memset( reserved, 0, sizeof(reserved) ); if (setup.version) { reserved[8] = header[8] & 0x0EU; reserved[12] = header[12] & 0xFCU; std::memcpy( reserved+14, header+14, HEADER_SIZE-14 ); } else { reserved[7] = header[7] & 0x02U; reserved[9] = header[9] & 0xFEU; std::memcpy( reserved+10, header+10, HEADER_SIZE-10 ); } for (uint i=4; i < HEADER_SIZE-4; ++i) { if (reserved[i]) { if (!User::Confirm( IDS_INES_HEADER_REMOVE_RESERVED )) { for (uint j=4; j < HEADER_SIZE-4; ++j) save[j] |= reserved[j]; } break; } } return true; } void InesHeader::UpdateHeader(const Nes::Cartridge::NesHeader& setup) const { dialog.RadioButton( IDC_INES_HEADER_TYPE_STD ).Check( !setup.version ); dialog.RadioButton( IDC_INES_HEADER_TYPE_EXT ).Check( setup.version ); dialog.Edit( IDC_INES_HEADER_MAPPER_BASE_VALUE ).Text() << uint(setup.mapper); dialog.Edit( IDC_INES_HEADER_MAPPER_SUB_VALUE ).Text() << uint(setup.subMapper); dialog.RadioButton( IDC_INES_HEADER_FOURSCREEN ).Check( setup.mirroring == Nes::Cartridge::NesHeader::MIRRORING_FOURSCREEN ); dialog.RadioButton( IDC_INES_HEADER_VERTICAL ).Check( setup.mirroring == Nes::Cartridge::NesHeader::MIRRORING_VERTICAL ); dialog.RadioButton( IDC_INES_HEADER_HORIZONTAL ).Check( setup.mirroring != Nes::Cartridge::NesHeader::MIRRORING_VERTICAL && setup.mirroring != Nes::Cartridge::NesHeader::MIRRORING_FOURSCREEN ); dialog.RadioButton( IDC_INES_HEADER_SYSTEM_VS ).Check( setup.system == Nes::Cartridge::NesHeader::SYSTEM_VS ); dialog.RadioButton( IDC_INES_HEADER_SYSTEM_PC10 ).Check( setup.system == Nes::Cartridge::NesHeader::SYSTEM_PC10 ); dialog.RadioButton( IDC_INES_HEADER_SYSTEM_HOME ).Check( setup.system == Nes::Cartridge::NesHeader::SYSTEM_CONSOLE ); dialog.RadioButton( IDC_INES_HEADER_REGION_BOTH ).Check( setup.region == Nes::Cartridge::NesHeader::REGION_BOTH ); dialog.RadioButton( IDC_INES_HEADER_REGION_PAL ).Check( setup.region == Nes::Cartridge::NesHeader::REGION_PAL ); dialog.RadioButton( IDC_INES_HEADER_REGION_NTSC ).Check( setup.region == Nes::Cartridge::NesHeader::REGION_NTSC ); dialog.CheckBox( IDC_INES_HEADER_TRAINER ).Check( setup.trainer ); dialog.ComboBox( IDC_INES_HEADER_VS_PPU_LIST )[setup.ppu ? setup.ppu-1 : 0].Select(); dialog.ComboBox( IDC_INES_HEADER_VS_MODE_LIST )[setup.security].Select(); UpdateVersion(); UpdateSizes( IDC_INES_HEADER_PRGROM_LIST, SIZETYPE_STD_16K, setup.prgRom ); UpdateSizes( IDC_INES_HEADER_PRGRAM_LIST, setup.version ? SIZETYPE_EXT : SIZETYPE_STD_8K, setup.prgRam ); UpdateSizes( IDC_INES_HEADER_PRGNVRAM_LIST, setup.version ? SIZETYPE_EXT : SIZETYPE_STATE, setup.prgNvRam ); UpdateSizes( IDC_INES_HEADER_CHRROM_LIST, SIZETYPE_STD_8K, setup.chrRom ); UpdateSizes( IDC_INES_HEADER_CHRRAM_LIST, SIZETYPE_EXT, setup.chrRam ); UpdateSizes( IDC_INES_HEADER_CHRNVRAM_LIST, SIZETYPE_EXT, setup.chrNvRam ); } void InesHeader::UpdateVersion() const { const bool v2 = dialog.RadioButton( IDC_INES_HEADER_TYPE_EXT ).Checked(); if (!v2 && dialog.RadioButton( IDC_INES_HEADER_SYSTEM_PC10 ).Checked()) { dialog.RadioButton( IDC_INES_HEADER_SYSTEM_PC10 ).Uncheck(); dialog.RadioButton( IDC_INES_HEADER_SYSTEM_HOME ).Check(); } dialog.Control( IDC_INES_HEADER_SYSTEM_PC10 ).Enable( v2 ); if (!v2 && dialog.RadioButton( IDC_INES_HEADER_REGION_BOTH ).Checked()) { dialog.RadioButton( IDC_INES_HEADER_REGION_BOTH ).Uncheck(); dialog.RadioButton( IDC_INES_HEADER_REGION_NTSC ).Check(); } dialog.Control( IDC_INES_HEADER_REGION_BOTH ).Enable( v2 ); dialog.Control( IDC_INES_HEADER_MAPPER_SUB_TEXT ).Enable( v2 ); dialog.Control( IDC_INES_HEADER_MAPPER_SUB_VALUE ).Enable( v2 ); dialog.Control( IDC_INES_HEADER_CHRRAM_LIST ).Enable( v2 ); dialog.Control( IDC_INES_HEADER_CHRRAM_TEXT ).Enable( v2 ); dialog.Control( IDC_INES_HEADER_CHRNVRAM_LIST ).Enable( v2 ); dialog.Control( IDC_INES_HEADER_CHRNVRAM_TEXT ).Enable( v2 ); UpdateSystem(); } void InesHeader::UpdateSystem() const { const bool vsExt = ( dialog.RadioButton( IDC_INES_HEADER_SYSTEM_VS ).Checked() && dialog.RadioButton( IDC_INES_HEADER_TYPE_EXT ).Checked() ); dialog.Control( IDC_INES_HEADER_VS_PPU_LIST ).Enable( vsExt ); dialog.Control( IDC_INES_HEADER_VS_PPU_TEXT ).Enable( vsExt ); dialog.Control( IDC_INES_HEADER_VS_MODE_LIST ).Enable( vsExt ); dialog.Control( IDC_INES_HEADER_VS_MODE_TEXT ).Enable( vsExt ); } uint InesHeader::GetMaxSize(uint block) const { return (dialog.RadioButton(IDC_INES_HEADER_TYPE_EXT).Checked() ? 0xFFF : 0xFF) * block; } void InesHeader::UpdateSizes(const uint idc,const SizeType sizeType,uint sizeSelect) const { const Control::ComboBox combo( dialog.ComboBox(idc) ); combo.Clear(); if (sizeType == SIZETYPE_STD_8K || sizeType == SIZETYPE_STD_16K) { combo.Reserve( 1+8+1, 8 ); combo.Add( Resource::String(IDS_TEXT_NONE).Ptr() ).Data() = 0; uint selection = 0; uint match = 0; for (uint i=0; i < 8; ++i) { const uint size = (uint(sizeType) << i) * Nes::Core::SIZE_1K; if (sizeSelect == size) { selection = i+1; match = size; } combo.Add( (String::Stack<7>() << (size / Nes::Core::SIZE_1K) << 'k').Ptr() ).Data() = size; } combo.Add( Resource::String(IDS_TEXT_OTHER) ).Data() = OTHER_SIZE | sizeType; if (sizeSelect != match) { const uint block = uint(sizeType) * Nes::Core::SIZE_1K; sizeSelect = (sizeSelect / block + (sizeSelect % block > 0)) * block; if (sizeSelect > GetMaxSize( block )) { selection = 1+7; } else { combo.Add( (String::Stack<7>() << (sizeSelect / Nes::Core::SIZE_1K) << 'k').Ptr() ).Data() = sizeSelect; selection = 1+8+1; } } combo[selection].Select(); } else if (sizeType == SIZETYPE_EXT) { static const struct { wcstring name; uint size; } sizes[14] = { { L"128", 128 }, { L"256", 256 }, { L"512", 512 }, { L"1k", Nes::Core::SIZE_1K }, { L"2k", Nes::Core::SIZE_2K }, { L"4k", Nes::Core::SIZE_4K }, { L"8k", Nes::Core::SIZE_8K }, { L"16k", Nes::Core::SIZE_16K }, { L"32k", Nes::Core::SIZE_32K }, { L"64k", Nes::Core::SIZE_64K }, { L"128k", Nes::Core::SIZE_128K }, { L"256k", Nes::Core::SIZE_256K }, { L"512k", Nes::Core::SIZE_512K }, { L"1024k", Nes::Core::SIZE_1024K } }; combo.Reserve( 1+14, 16 ); combo.Add( Resource::String(IDS_TEXT_NONE).Ptr() ).Data() = 0; uint selection = sizeSelect ? UINT_MAX : 0; for (uint i=0; i < 14; ++i) { if (selection == UINT_MAX && sizeSelect <= sizes[i].size) selection = 1+i; combo.Add( sizes[i].name ).Data() = sizes[i].size; } combo[selection == UINT_MAX ? 1+14-1 : selection].Select(); } else { NST_ASSERT( sizeType == SIZETYPE_STATE ); combo.Reserve( 2, 16 ); combo.Add( Resource::String(IDS_TEXT_DISABLED) ).Data() = false; combo.Add( Resource::String(IDS_TEXT_ENABLED) ).Data() = true; combo[sizeSelect >= Nes::Core::SIZE_1K].Select(); } } ibool InesHeader::OnCmdFileType(Param& param) { if (param.Button().Clicked()) { UpdateVersion(); uint size = dialog.ComboBox(IDC_INES_HEADER_PRGROM_LIST).Selection().Data(); UpdateSizes( IDC_INES_HEADER_PRGROM_LIST, SIZETYPE_STD_16K, size ); size = dialog.ComboBox(IDC_INES_HEADER_PRGRAM_LIST).Selection().Data(); uint save = dialog.ComboBox(IDC_INES_HEADER_PRGNVRAM_LIST).Selection().Data(); const bool v2 = dialog.RadioButton( IDC_INES_HEADER_TYPE_EXT ).Checked(); if (dialog.ComboBox(IDC_INES_HEADER_PRGNVRAM_LIST).Size() == 2) { if (v2 && save) { save = NST_MAX(size,Nes::Core::SIZE_8K); size = 0; } } else if (!v2) { size += save; if (size < Nes::Core::SIZE_8K) size = 0; } UpdateSizes( IDC_INES_HEADER_PRGRAM_LIST, v2 ? SIZETYPE_EXT : SIZETYPE_STD_8K, size ); UpdateSizes( IDC_INES_HEADER_PRGNVRAM_LIST, v2 ? SIZETYPE_EXT : SIZETYPE_STATE, save ); size = dialog.ComboBox(IDC_INES_HEADER_CHRROM_LIST).Selection().Data(); UpdateSizes( IDC_INES_HEADER_CHRROM_LIST, SIZETYPE_STD_8K, size ); } return true; } ibool InesHeader::OnCmdSystem(Param& param) { if (param.Button().Clicked()) UpdateSystem(); return true; } ibool InesHeader::OnCmdSizeOther(Param& param) { if (param.ComboBox().SelectionChanged()) { const Control::ComboBox combo( dialog.ComboBox(param.ComboBox().GetId()) ); const uint otherSize = combo.Selection().Data(); if (otherSize & OTHER_SIZE) { const uint last = combo.Back().Data(); uint size = last; if (last & OTHER_SIZE) size &= OTHER_SIZE_DIV; else size /= Nes::Core::SIZE_1K; CustomSize( size ).Open(); if (size % (otherSize & OTHER_SIZE_DIV) || size > GetMaxSize(otherSize & OTHER_SIZE_DIV)) { size = (last & OTHER_SIZE) ? (otherSize & OTHER_SIZE_DIV) : (last / Nes::Core::SIZE_1K); User::Warn( IDS_ERR_INVALID_SIZE, IDS_TITLE_ERROR ); } if (!(last & OTHER_SIZE)) combo.Back().Erase(); combo.Add( (String::Stack<7>() << size << 'k').Ptr() ).Data() = size * Nes::Core::SIZE_1K; combo.Back().Select(); } } return true; } ibool InesHeader::OnCmdUndoAll(Param& param) { if (param.Button().Clicked()) { Nes::Cartridge::NesHeader setup; setup.Import( header, HEADER_SIZE ); UpdateHeader( setup ); } return true; } ibool InesHeader::OnCmdSave(Param& param) { if (param.Button().Clicked()) { Header header; if (!SaveHeader( header )) { User::Warn( IDS_INES_HEADER_INVALID, IDS_TITLE_ERROR ); return true; } const Path savePath( paths.BrowseSave( Managers::Paths::File::INES, Managers::Paths::DONT_SUGGEST, *path ) ); if (savePath.Empty()) return true; Collection::Buffer buffer; uint result = Import( *path, buffer ); if (result == 0) { NST_ASSERT( buffer.Size() >= HEADER_SIZE ); if (!OkToSave( buffer.Size() )) return true; std::memcpy( buffer.Ptr(), header, HEADER_SIZE ); result = Export( savePath, buffer ); if (result == 0) { dialog.Close(); return true; } } User::Fail( result ); } return true; } struct InesHeader::CustomSize::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; }; const MsgHandler::Entry InesHeader::CustomSize::Handlers::messages[] = { { WM_INITDIALOG, &CustomSize::OnInitDialog } }; const MsgHandler::Entry InesHeader::CustomSize::Handlers::commands[] = { { IDOK, &CustomSize::OnCmdOk } }; InesHeader::CustomSize::CustomSize(uint& s) : size (s), dialog (IDD_INES_HEADER_CUSTOM,this,Handlers::messages,Handlers::commands) { } ibool InesHeader::CustomSize::OnInitDialog(Param&) { const Control::Edit edit( dialog.Edit(IDC_INES_HEADER_CUSTOM_VALUE) ); edit.Limit( 5 ); edit.Text() << size; return true; } ibool InesHeader::CustomSize::OnCmdOk(Param& param) { if (param.Button().Clicked()) { dialog.Edit( IDC_INES_HEADER_CUSTOM_VALUE ) >> size; dialog.Close(); } return true; } } } nestopia-1.51.1/source/win32/NstDialogInesHeader.hpp000066400000000000000000000045101411157722000222100ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIALOG_INESHEADER_H #define NST_DIALOG_INESHEADER_H #pragma once #include "NstWindowDialog.hpp" namespace Nestopia { namespace Window { class InesHeader { public: InesHeader(const Managers::Paths&); void Open(const Path&); private: struct Handlers; class CustomSize; enum SizeType { SIZETYPE_EXT = 0, SIZETYPE_STD_8K = 8, SIZETYPE_STD_16K = 16, SIZETYPE_STATE = 2 }; enum { OTHER_SIZE = 0x40000000, OTHER_SIZE_DIV = SIZETYPE_STD_8K|SIZETYPE_STD_16K, HEADER_SIZE = 16, HEADER_ID = FourCC<'N','E','S',0x1A>::V }; typedef uchar Header[HEADER_SIZE]; static uint Import(const Path&,Collection::Buffer&); static uint Export(const Path&,const Collection::Buffer&); void UpdateHeader(const Nes::Cartridge::NesHeader&) const; void UpdateVersion() const; void UpdateSystem() const; void UpdateSizes(uint,SizeType,uint) const; bool SaveHeader(Header&) const; uint GetMaxSize(uint) const; bool OkToSave(uint) const; ibool OnInitDialog (Param&); ibool OnCmdFileType (Param&); ibool OnCmdSystem (Param&); ibool OnCmdSizeOther (Param&); ibool OnCmdUndoAll (Param&); ibool OnCmdSave (Param&); Dialog dialog; Header header; const Path* path; const Managers::Paths& paths; }; } } #endif nestopia-1.51.1/source/win32/NstDialogInput.cpp000066400000000000000000001562561411157722000213120ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstResourceString.hpp" #include "NstIoLog.hpp" #include "NstApplicationConfiguration.hpp" #include "NstManagerEmulator.hpp" #include "NstSystemKeyboard.hpp" #include "NstWindowParam.hpp" #include "NstWindowDynamic.hpp" #include "NstWindowUser.hpp" #include "NstDialogInput.hpp" #include namespace Nestopia { namespace Window { NST_COMPILE_ASSERT ( DirectX::DirectInput::AXIS_X == 0x001 && DirectX::DirectInput::AXIS_Y == 0x002 && DirectX::DirectInput::AXIS_Z == 0x004 && DirectX::DirectInput::AXIS_RX == 0x008 && DirectX::DirectInput::AXIS_RY == 0x010 && DirectX::DirectInput::AXIS_RZ == 0x020 && DirectX::DirectInput::AXIS_SLIDER_0 == 0x040 && DirectX::DirectInput::AXIS_SLIDER_1 == 0x080 && DirectX::DirectInput::AXIS_POV_0 == 0x100 && DirectX::DirectInput::AXIS_POV_1 == 0x200 && DirectX::DirectInput::AXIS_POV_2 == 0x400 && DirectX::DirectInput::AXIS_POV_3 == 0x800 && IDC_INPUT_JOYSTICKS_ENABLE == IDC_INPUT_JOYSTICKS + 1 && IDC_INPUT_JOYSTICKS_X == IDC_INPUT_JOYSTICKS + 2 && IDC_INPUT_JOYSTICKS_Y == IDC_INPUT_JOYSTICKS + 3 && IDC_INPUT_JOYSTICKS_Z == IDC_INPUT_JOYSTICKS + 4 && IDC_INPUT_JOYSTICKS_RX == IDC_INPUT_JOYSTICKS + 5 && IDC_INPUT_JOYSTICKS_RY == IDC_INPUT_JOYSTICKS + 6 && IDC_INPUT_JOYSTICKS_RZ == IDC_INPUT_JOYSTICKS + 7 && IDC_INPUT_JOYSTICKS_S0 == IDC_INPUT_JOYSTICKS + 8 && IDC_INPUT_JOYSTICKS_S1 == IDC_INPUT_JOYSTICKS + 9 && IDC_INPUT_JOYSTICKS_POV0 == IDC_INPUT_JOYSTICKS + 10 && IDC_INPUT_JOYSTICKS_POV1 == IDC_INPUT_JOYSTICKS + 11 && IDC_INPUT_JOYSTICKS_POV2 == IDC_INPUT_JOYSTICKS + 12 && IDC_INPUT_JOYSTICKS_POV3 == IDC_INPUT_JOYSTICKS + 13 && IDC_INPUT_JOYSTICKS_DEADZONE == IDC_INPUT_JOYSTICKS + 14 && IDC_INPUT_JOYSTICKS_DEADZONE_NUM == IDC_INPUT_JOYSTICKS + 15 && IDC_INPUT_JOYSTICKS_DEADZONE_TEXT == IDC_INPUT_JOYSTICKS + 16 && IDC_INPUT_JOYSTICKS_CALIBRATE == IDC_INPUT_JOYSTICKS + 17 && IDC_INPUT_JOYSTICKS_DEFAULT == IDC_INPUT_JOYSTICKS + 18 && IDM_MACHINE_INPUT_PORT1_PAD1 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 1 && IDM_MACHINE_INPUT_PORT1_PAD2 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 2 && IDM_MACHINE_INPUT_PORT1_PAD3 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 3 && IDM_MACHINE_INPUT_PORT1_PAD4 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 4 && IDM_MACHINE_INPUT_PORT1_ZAPPER == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 5 && IDM_MACHINE_INPUT_PORT1_PADDLE == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 6 && IDM_MACHINE_INPUT_PORT1_POWERPAD == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 7 && IDM_MACHINE_INPUT_PORT1_POWERGLOVE == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 8 && IDM_MACHINE_INPUT_PORT1_MOUSE == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 9 && IDM_MACHINE_INPUT_PORT1_ROB == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 10 && IDM_MACHINE_INPUT_PORT2_UNCONNECTED == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 11 && IDM_MACHINE_INPUT_PORT2_PAD1 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 12 && IDM_MACHINE_INPUT_PORT2_PAD2 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 13 && IDM_MACHINE_INPUT_PORT2_PAD3 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 14 && IDM_MACHINE_INPUT_PORT2_PAD4 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 15 && IDM_MACHINE_INPUT_PORT2_ZAPPER == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 16 && IDM_MACHINE_INPUT_PORT2_PADDLE == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 17 && IDM_MACHINE_INPUT_PORT2_POWERPAD == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 18 && IDM_MACHINE_INPUT_PORT2_POWERGLOVE == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 19 && IDM_MACHINE_INPUT_PORT2_MOUSE == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 20 && IDM_MACHINE_INPUT_PORT2_ROB == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 21 && IDM_MACHINE_INPUT_PORT3_UNCONNECTED == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 22 && IDM_MACHINE_INPUT_PORT3_PAD1 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 23 && IDM_MACHINE_INPUT_PORT3_PAD2 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 24 && IDM_MACHINE_INPUT_PORT3_PAD3 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 25 && IDM_MACHINE_INPUT_PORT3_PAD4 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 26 && IDM_MACHINE_INPUT_PORT4_UNCONNECTED == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 27 && IDM_MACHINE_INPUT_PORT4_PAD1 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 28 && IDM_MACHINE_INPUT_PORT4_PAD2 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 29 && IDM_MACHINE_INPUT_PORT4_PAD3 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 30 && IDM_MACHINE_INPUT_PORT4_PAD4 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 31 && IDM_MACHINE_INPUT_EXP_UNCONNECTED == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 32 && IDM_MACHINE_INPUT_EXP_FAMILYTRAINER == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 33 && IDM_MACHINE_INPUT_EXP_FAMILYBASICKEYBOARD == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 34 && IDM_MACHINE_INPUT_EXP_SUBORKEYBOARD == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 35 && IDM_MACHINE_INPUT_EXP_DOREMIKKOKEYBOARD == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 36 && IDM_MACHINE_INPUT_EXP_HORITRACK == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 37 && IDM_MACHINE_INPUT_EXP_PACHINKO == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 38 && IDM_MACHINE_INPUT_EXP_PADDLE == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 39 && IDM_MACHINE_INPUT_EXP_OEKAKIDSTABLET == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 40 && IDM_MACHINE_INPUT_EXP_KONAMIHYPERSHOT == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 41 && IDM_MACHINE_INPUT_EXP_BANDAIHYPERSHOT == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 42 && IDM_MACHINE_INPUT_EXP_CRAZYCLIMBER == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 43 && IDM_MACHINE_INPUT_EXP_MAHJONG == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 44 && IDM_MACHINE_INPUT_EXP_EXCITINGBOXING == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 45 && IDM_MACHINE_INPUT_EXP_TOPRIDER == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 46 && IDM_MACHINE_INPUT_EXP_POKKUNMOGURAA == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 47 && IDM_MACHINE_INPUT_EXP_PARTYTAP == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 48 && IDM_MACHINE_INPUT_EXP_TURBOFILE == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 49 && IDM_MACHINE_INPUT_EXP_BARCODEWORLD == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 50 ); const Input::Settings::Type Input::Settings::types[OFFSET_COUNT] = { { PAD1_KEYS, IDS_INPUT_KEY_SECTION_PAD1 }, { PAD2_KEYS, IDS_INPUT_KEY_SECTION_PAD2 }, { PAD3_KEYS, IDS_INPUT_KEY_SECTION_PAD3 }, { PAD4_KEYS, IDS_INPUT_KEY_SECTION_PAD4 }, { POWERPAD_KEYS, IDS_INPUT_KEY_SECTION_POWERPAD }, { POWERGLOVE_KEYS, IDS_INPUT_KEY_SECTION_POWERGLOVE }, { HORITRACK_KEYS, IDS_INPUT_KEY_SECTION_HORITRACK }, { PACHINKO_KEYS, IDS_INPUT_KEY_SECTION_PACHINKO }, { CRAZYCLIMBER_KEYS, IDS_INPUT_KEY_SECTION_CRAZYCLIMBER }, { MAHJONG_KEYS, IDS_INPUT_KEY_SECTION_MAHJONG }, { EXCITINGBOXING_KEYS, IDS_INPUT_KEY_SECTION_EXCITINGBOXING }, { POKKUNMOGURAA_KEYS, IDS_INPUT_KEY_SECTION_POKKUNMOGURAA }, { PARTYTAP_KEYS, IDS_INPUT_KEY_SECTION_PARTYTAP }, { KARAOKESTUDIO_KEYS, IDS_INPUT_KEY_SECTION_KARAOKESTUDIO }, { EMULATION_KEYS, IDS_INPUT_KEY_SECTION_EMULATION }, { FILE_KEYS, IDS_INPUT_KEY_SECTION_FILE }, { MACHINE_KEYS, IDS_INPUT_KEY_SECTION_MACHINE }, { NSF_KEYS, IDS_INPUT_KEY_SECTION_NSF }, { VIEW_KEYS, IDS_INPUT_KEY_SECTION_VIEW }, { HELP_KEYS, IDS_INPUT_KEY_SECTION_HELP }, { NUM_KEYS, 0 } }; const Input::Settings::Mapping Input::Settings::map[NUM_KEYS] = { { PAD1_KEYS + PAD_KEY_LEFT, DIK_LEFT, IDS_INPUT_PAD_KEY_LEFT, "pad-1", "left" }, { PAD1_KEYS + PAD_KEY_UP, DIK_UP, IDS_INPUT_PAD_KEY_UP, "pad-1", "up" }, { PAD1_KEYS + PAD_KEY_RIGHT, DIK_RIGHT, IDS_INPUT_PAD_KEY_RIGHT, "pad-1", "right" }, { PAD1_KEYS + PAD_KEY_DOWN, DIK_DOWN, IDS_INPUT_PAD_KEY_DOWN, "pad-1", "down" }, { PAD1_KEYS + PAD_KEY_SELECT, DIK_RSHIFT, IDS_INPUT_PAD_KEY_SELECT, "pad-1", "select" }, { PAD1_KEYS + PAD_KEY_START, DIK_RETURN, IDS_INPUT_PAD_KEY_START, "pad-1", "start" }, { PAD1_KEYS + PAD_KEY_B, DIK_COMMA, IDS_INPUT_PAD_KEY_B, "pad-1", "b" }, { PAD1_KEYS + PAD_KEY_A, DIK_PERIOD, IDS_INPUT_PAD_KEY_A, "pad-1", "a" }, { PAD1_KEYS + PAD_KEY_AUTOFIRE_B, DIK_K, IDS_INPUT_PAD_KEY_AUTOFIRE_B, "pad-1", "auto-fire-b" }, { PAD1_KEYS + PAD_KEY_AUTOFIRE_A, DIK_L, IDS_INPUT_PAD_KEY_AUTOFIRE_A, "pad-1", "auto-fire-a" }, { PAD1_KEYS + PAD_KEY_MIC, NO_KEY, IDS_INPUT_PAD_KEY_MIC, "pad-1", "mic" }, { PAD2_KEYS + PAD_KEY_LEFT, DIK_C, IDS_INPUT_PAD_KEY_LEFT, "pad-2", "left" }, { PAD2_KEYS + PAD_KEY_UP, DIK_F, IDS_INPUT_PAD_KEY_UP, "pad-2", "up" }, { PAD2_KEYS + PAD_KEY_RIGHT, DIK_B, IDS_INPUT_PAD_KEY_RIGHT, "pad-2", "right" }, { PAD2_KEYS + PAD_KEY_DOWN, DIK_V, IDS_INPUT_PAD_KEY_DOWN, "pad-2", "down" }, { PAD2_KEYS + PAD_KEY_SELECT, DIK_A, IDS_INPUT_PAD_KEY_SELECT, "pad-2", "select" }, { PAD2_KEYS + PAD_KEY_START, DIK_S, IDS_INPUT_PAD_KEY_START, "pad-2", "start" }, { PAD2_KEYS + PAD_KEY_B, DIK_Z, IDS_INPUT_PAD_KEY_B, "pad-2", "b" }, { PAD2_KEYS + PAD_KEY_A, DIK_X, IDS_INPUT_PAD_KEY_A, "pad-2", "a" }, { PAD2_KEYS + PAD_KEY_AUTOFIRE_B, DIK_Q, IDS_INPUT_PAD_KEY_AUTOFIRE_B, "pad-2", "auto-fire-b" }, { PAD2_KEYS + PAD_KEY_AUTOFIRE_A, DIK_W, IDS_INPUT_PAD_KEY_AUTOFIRE_A, "pad-2", "auto-fire-a" }, { PAD2_KEYS + PAD_KEY_MIC, DIK_M, IDS_INPUT_PAD_KEY_MIC, "pad-2", "mic" }, { PAD3_KEYS + PAD_KEY_LEFT, NO_KEY, IDS_INPUT_PAD_KEY_LEFT, "pad-3", "left" }, { PAD3_KEYS + PAD_KEY_UP, NO_KEY, IDS_INPUT_PAD_KEY_UP, "pad-3", "up" }, { PAD3_KEYS + PAD_KEY_RIGHT, NO_KEY, IDS_INPUT_PAD_KEY_RIGHT, "pad-3", "right" }, { PAD3_KEYS + PAD_KEY_DOWN, NO_KEY, IDS_INPUT_PAD_KEY_DOWN, "pad-3", "down" }, { PAD3_KEYS + PAD_KEY_SELECT, NO_KEY, IDS_INPUT_PAD_KEY_SELECT, "pad-3", "select" }, { PAD3_KEYS + PAD_KEY_START, NO_KEY, IDS_INPUT_PAD_KEY_START, "pad-3", "start" }, { PAD3_KEYS + PAD_KEY_B, NO_KEY, IDS_INPUT_PAD_KEY_B, "pad-3", "b" }, { PAD3_KEYS + PAD_KEY_A, NO_KEY, IDS_INPUT_PAD_KEY_A, "pad-3", "a" }, { PAD3_KEYS + PAD_KEY_AUTOFIRE_B, NO_KEY, IDS_INPUT_PAD_KEY_AUTOFIRE_B, "pad-3", "auto-fire-b" }, { PAD3_KEYS + PAD_KEY_AUTOFIRE_A, NO_KEY, IDS_INPUT_PAD_KEY_AUTOFIRE_A, "pad-3", "auto-fire-a" }, { PAD3_KEYS + PAD_KEY_MIC, NO_KEY, IDS_INPUT_PAD_KEY_MIC, "pad-3", "mic" }, { PAD4_KEYS + PAD_KEY_LEFT, NO_KEY, IDS_INPUT_PAD_KEY_LEFT, "pad-4", "left" }, { PAD4_KEYS + PAD_KEY_UP, NO_KEY, IDS_INPUT_PAD_KEY_UP, "pad-4", "up" }, { PAD4_KEYS + PAD_KEY_RIGHT, NO_KEY, IDS_INPUT_PAD_KEY_RIGHT, "pad-4", "right" }, { PAD4_KEYS + PAD_KEY_DOWN, NO_KEY, IDS_INPUT_PAD_KEY_DOWN, "pad-4", "down" }, { PAD4_KEYS + PAD_KEY_SELECT, NO_KEY, IDS_INPUT_PAD_KEY_SELECT, "pad-4", "select" }, { PAD4_KEYS + PAD_KEY_START, NO_KEY, IDS_INPUT_PAD_KEY_START, "pad-4", "start" }, { PAD4_KEYS + PAD_KEY_B, NO_KEY, IDS_INPUT_PAD_KEY_B, "pad-4", "b" }, { PAD4_KEYS + PAD_KEY_A, NO_KEY, IDS_INPUT_PAD_KEY_A, "pad-4", "a" }, { PAD4_KEYS + PAD_KEY_AUTOFIRE_B, NO_KEY, IDS_INPUT_PAD_KEY_AUTOFIRE_B, "pad-4", "auto-fire-b" }, { PAD4_KEYS + PAD_KEY_AUTOFIRE_A, NO_KEY, IDS_INPUT_PAD_KEY_AUTOFIRE_A, "pad-4", "auto-fire-a" }, { PAD4_KEYS + PAD_KEY_MIC, NO_KEY, IDS_INPUT_PAD_KEY_MIC, "pad-4", "mic" }, { POWERPAD_KEYS + POWERPAD_KEY_SIDE_A_1, DIK_Q, IDS_INPUT_POWERPAD_KEY_SIDE_A_1, "powerpad", "side-a-1" }, { POWERPAD_KEYS + POWERPAD_KEY_SIDE_A_2, DIK_W, IDS_INPUT_POWERPAD_KEY_SIDE_A_2, "powerpad", "side-a-2" }, { POWERPAD_KEYS + POWERPAD_KEY_SIDE_A_3, DIK_E, IDS_INPUT_POWERPAD_KEY_SIDE_A_3, "powerpad", "side-a-3" }, { POWERPAD_KEYS + POWERPAD_KEY_SIDE_A_4, DIK_R, IDS_INPUT_POWERPAD_KEY_SIDE_A_4, "powerpad", "side-a-4" }, { POWERPAD_KEYS + POWERPAD_KEY_SIDE_A_5, DIK_A, IDS_INPUT_POWERPAD_KEY_SIDE_A_5, "powerpad", "side-a-5" }, { POWERPAD_KEYS + POWERPAD_KEY_SIDE_A_6, DIK_S, IDS_INPUT_POWERPAD_KEY_SIDE_A_6, "powerpad", "side-a-6" }, { POWERPAD_KEYS + POWERPAD_KEY_SIDE_A_7, DIK_D, IDS_INPUT_POWERPAD_KEY_SIDE_A_7, "powerpad", "side-a-7" }, { POWERPAD_KEYS + POWERPAD_KEY_SIDE_A_8, DIK_F, IDS_INPUT_POWERPAD_KEY_SIDE_A_8, "powerpad", "side-a-8" }, { POWERPAD_KEYS + POWERPAD_KEY_SIDE_A_9, DIK_Z, IDS_INPUT_POWERPAD_KEY_SIDE_A_9, "powerpad", "side-a-9" }, { POWERPAD_KEYS + POWERPAD_KEY_SIDE_A_10, DIK_X, IDS_INPUT_POWERPAD_KEY_SIDE_A_10, "powerpad", "side-a-10" }, { POWERPAD_KEYS + POWERPAD_KEY_SIDE_A_11, DIK_C, IDS_INPUT_POWERPAD_KEY_SIDE_A_11, "powerpad", "side-a-11" }, { POWERPAD_KEYS + POWERPAD_KEY_SIDE_A_12, DIK_V, IDS_INPUT_POWERPAD_KEY_SIDE_A_12, "powerpad", "side-a-12" }, { POWERPAD_KEYS + POWERPAD_KEY_SIDE_B_3, DIK_Y, IDS_INPUT_POWERPAD_KEY_SIDE_B_3, "powerpad", "side-b-3" }, { POWERPAD_KEYS + POWERPAD_KEY_SIDE_B_2, DIK_U, IDS_INPUT_POWERPAD_KEY_SIDE_B_2, "powerpad", "side-b-2" }, { POWERPAD_KEYS + POWERPAD_KEY_SIDE_B_8, DIK_G, IDS_INPUT_POWERPAD_KEY_SIDE_B_8, "powerpad", "side-b-8" }, { POWERPAD_KEYS + POWERPAD_KEY_SIDE_B_7, DIK_H, IDS_INPUT_POWERPAD_KEY_SIDE_B_7, "powerpad", "side-b-7" }, { POWERPAD_KEYS + POWERPAD_KEY_SIDE_B_6, DIK_J, IDS_INPUT_POWERPAD_KEY_SIDE_B_6, "powerpad", "side-b-6" }, { POWERPAD_KEYS + POWERPAD_KEY_SIDE_B_5, DIK_K, IDS_INPUT_POWERPAD_KEY_SIDE_B_5, "powerpad", "side-b-5" }, { POWERPAD_KEYS + POWERPAD_KEY_SIDE_B_11, DIK_N, IDS_INPUT_POWERPAD_KEY_SIDE_B_11, "powerpad", "side-b-11" }, { POWERPAD_KEYS + POWERPAD_KEY_SIDE_B_10, DIK_M, IDS_INPUT_POWERPAD_KEY_SIDE_B_10, "powerpad", "side-b-10" }, { POWERGLOVE_KEYS + POWERGLOVE_KEY_SELECT, DIK_RSHIFT, IDS_INPUT_POWERGLOVE_KEY_SELECT, "powerglove", "select" }, { POWERGLOVE_KEYS + POWERGLOVE_KEY_START, DIK_RETURN, IDS_INPUT_POWERGLOVE_KEY_START, "powerglove", "start" }, { POWERGLOVE_KEYS + POWERGLOVE_KEY_MOVE_IN, DIK_A, IDS_INPUT_POWERGLOVE_KEY_MOVE_IN, "powerglove", "move-in" }, { POWERGLOVE_KEYS + POWERGLOVE_KEY_MOVE_OUT, DIK_Z, IDS_INPUT_POWERGLOVE_KEY_MOVE_OUT, "powerglove", "move-out" }, { POWERGLOVE_KEYS + POWERGLOVE_KEY_ROLL_LEFT, DIK_X, IDS_INPUT_POWERGLOVE_KEY_ROLL_LEFT, "powerglove", "roll-left" }, { POWERGLOVE_KEYS + POWERGLOVE_KEY_ROLL_RIGHT, DIK_C, IDS_INPUT_POWERGLOVE_KEY_ROLL_RIGHT, "powerglove", "roll-right" }, { HORITRACK_KEYS + HORITRACK_KEY_LEFT, DIK_LEFT, IDS_INPUT_HORITRACK_KEY_LEFT, "horitrack", "left" }, { HORITRACK_KEYS + HORITRACK_KEY_UP, DIK_UP, IDS_INPUT_HORITRACK_KEY_UP, "horitrack", "up" }, { HORITRACK_KEYS + HORITRACK_KEY_RIGHT, DIK_RIGHT, IDS_INPUT_HORITRACK_KEY_RIGHT, "horitrack", "right" }, { HORITRACK_KEYS + HORITRACK_KEY_DOWN, DIK_DOWN, IDS_INPUT_HORITRACK_KEY_DOWN, "horitrack", "down" }, { HORITRACK_KEYS + HORITRACK_KEY_SELECT, DIK_RSHIFT, IDS_INPUT_HORITRACK_KEY_SELECT, "horitrack", "select" }, { HORITRACK_KEYS + HORITRACK_KEY_START, DIK_RETURN, IDS_INPUT_HORITRACK_KEY_START, "horitrack", "start" }, { HORITRACK_KEYS + HORITRACK_KEY_B, DIK_COMMA, IDS_INPUT_HORITRACK_KEY_B, "horitrack", "b" }, { HORITRACK_KEYS + HORITRACK_KEY_A, DIK_PERIOD, IDS_INPUT_HORITRACK_KEY_A, "horitrack", "a" }, { HORITRACK_KEYS + HORITRACK_KEY_SPEED, DIK_S, IDS_INPUT_HORITRACK_KEY_SPEED, "horitrack", "speed" }, { HORITRACK_KEYS + HORITRACK_KEY_ORIENTATION, DIK_D, IDS_INPUT_HORITRACK_KEY_ORIENTATION, "horitrack", "orientation" }, { PACHINKO_KEYS + PACHINKO_KEY_LEFT, DIK_LEFT, IDS_INPUT_PACHINKO_KEY_LEFT, "pachinko", "left" }, { PACHINKO_KEYS + PACHINKO_KEY_UP, DIK_UP, IDS_INPUT_PACHINKO_KEY_UP, "pachinko", "up" }, { PACHINKO_KEYS + PACHINKO_KEY_RIGHT, DIK_RIGHT, IDS_INPUT_PACHINKO_KEY_RIGHT, "pachinko", "right" }, { PACHINKO_KEYS + PACHINKO_KEY_DOWN, DIK_DOWN, IDS_INPUT_PACHINKO_KEY_DOWN, "pachinko", "down" }, { PACHINKO_KEYS + PACHINKO_KEY_SELECT, DIK_RSHIFT, IDS_INPUT_PACHINKO_KEY_SELECT, "pachinko", "select" }, { PACHINKO_KEYS + PACHINKO_KEY_START, DIK_RETURN, IDS_INPUT_PACHINKO_KEY_START, "pachinko", "start" }, { PACHINKO_KEYS + PACHINKO_KEY_B, DIK_COMMA, IDS_INPUT_PACHINKO_KEY_B, "pachinko", "b" }, { PACHINKO_KEYS + PACHINKO_KEY_A, DIK_PERIOD, IDS_INPUT_PACHINKO_KEY_A, "pachinko", "a" }, { CRAZYCLIMBER_KEYS + CRAZYCLIMBER_KEY_LEFT_UP, DIK_W, IDS_INPUT_CRAZYCLIMBER_KEY_LEFT_UP, "crazyclimber", "left-up" }, { CRAZYCLIMBER_KEYS + CRAZYCLIMBER_KEY_LEFT_RIGHT, DIK_D, IDS_INPUT_CRAZYCLIMBER_KEY_LEFT_RIGHT, "crazyclimber", "left-right" }, { CRAZYCLIMBER_KEYS + CRAZYCLIMBER_KEY_LEFT_DOWN, DIK_S, IDS_INPUT_CRAZYCLIMBER_KEY_LEFT_DOWN, "crazyclimber", "left-down" }, { CRAZYCLIMBER_KEYS + CRAZYCLIMBER_KEY_LEFT_LEFT, DIK_A, IDS_INPUT_CRAZYCLIMBER_KEY_LEFT_LEFT, "crazyclimber", "left-left" }, { CRAZYCLIMBER_KEYS + CRAZYCLIMBER_KEY_RIGHT_UP, DIK_Y, IDS_INPUT_CRAZYCLIMBER_KEY_RIGHT_UP, "crazyclimber", "right-up" }, { CRAZYCLIMBER_KEYS + CRAZYCLIMBER_KEY_RIGHT_RIGHT, DIK_J, IDS_INPUT_CRAZYCLIMBER_KEY_RIGHT_RIGHT, "crazyclimber", "right-right" }, { CRAZYCLIMBER_KEYS + CRAZYCLIMBER_KEY_RIGHT_DOWN, DIK_H, IDS_INPUT_CRAZYCLIMBER_KEY_RIGHT_DOWN, "crazyclimber", "right-down" }, { CRAZYCLIMBER_KEYS + CRAZYCLIMBER_KEY_RIGHT_LEFT, DIK_G, IDS_INPUT_CRAZYCLIMBER_KEY_RIGHT_LEFT, "crazyclimber", "right-left" }, { MAHJONG_KEYS + MAHJONG_KEY_A, DIK_Q, IDS_INPUT_MAHJONG_KEY_A, "mahjong", "a" }, { MAHJONG_KEYS + MAHJONG_KEY_B, DIK_W, IDS_INPUT_MAHJONG_KEY_B, "mahjong", "b" }, { MAHJONG_KEYS + MAHJONG_KEY_C, DIK_E, IDS_INPUT_MAHJONG_KEY_C, "mahjong", "c" }, { MAHJONG_KEYS + MAHJONG_KEY_D, DIK_R, IDS_INPUT_MAHJONG_KEY_D, "mahjong", "d" }, { MAHJONG_KEYS + MAHJONG_KEY_E, DIK_T, IDS_INPUT_MAHJONG_KEY_E, "mahjong", "e" }, { MAHJONG_KEYS + MAHJONG_KEY_F, DIK_A, IDS_INPUT_MAHJONG_KEY_F, "mahjong", "f" }, { MAHJONG_KEYS + MAHJONG_KEY_G, DIK_S, IDS_INPUT_MAHJONG_KEY_G, "mahjong", "g" }, { MAHJONG_KEYS + MAHJONG_KEY_H, DIK_D, IDS_INPUT_MAHJONG_KEY_H, "mahjong", "h" }, { MAHJONG_KEYS + MAHJONG_KEY_I, DIK_F, IDS_INPUT_MAHJONG_KEY_I, "mahjong", "i" }, { MAHJONG_KEYS + MAHJONG_KEY_J, DIK_G, IDS_INPUT_MAHJONG_KEY_J, "mahjong", "j" }, { MAHJONG_KEYS + MAHJONG_KEY_K, DIK_H, IDS_INPUT_MAHJONG_KEY_K, "mahjong", "k" }, { MAHJONG_KEYS + MAHJONG_KEY_L, DIK_J, IDS_INPUT_MAHJONG_KEY_L, "mahjong", "l" }, { MAHJONG_KEYS + MAHJONG_KEY_M, DIK_K, IDS_INPUT_MAHJONG_KEY_M, "mahjong", "m" }, { MAHJONG_KEYS + MAHJONG_KEY_N, DIK_L, IDS_INPUT_MAHJONG_KEY_N, "mahjong", "n" }, { MAHJONG_KEYS + MAHJONG_KEY_START, DIK_Z, IDS_INPUT_MAHJONG_KEY_START, "mahjong", "start" }, { MAHJONG_KEYS + MAHJONG_KEY_SELECT, DIK_X, IDS_INPUT_MAHJONG_KEY_SELECT, "mahjong", "select" }, { MAHJONG_KEYS + MAHJONG_KEY_KAN, DIK_C, IDS_INPUT_MAHJONG_KEY_KAN, "mahjong", "kan" }, { MAHJONG_KEYS + MAHJONG_KEY_PON, DIK_V, IDS_INPUT_MAHJONG_KEY_PON, "mahjong", "pon" }, { MAHJONG_KEYS + MAHJONG_KEY_CHI, DIK_B, IDS_INPUT_MAHJONG_KEY_CHI, "mahjong", "chi" }, { MAHJONG_KEYS + MAHJONG_KEY_REACH, DIK_N, IDS_INPUT_MAHJONG_KEY_REACH, "mahjong", "reach" }, { MAHJONG_KEYS + MAHJONG_KEY_RON, DIK_M, IDS_INPUT_MAHJONG_KEY_RON, "mahjong", "ron" }, { EXCITINGBOXING_KEYS + EXCITINGBOXING_KEY_LEFT_HOOK, DIK_K, IDS_INPUT_EXCITINGBOXING_KEY_LEFT_HOOK, "excitingboxing", "left-hook" }, { EXCITINGBOXING_KEYS + EXCITINGBOXING_KEY_RIGHT_HOOK, DIK_L, IDS_INPUT_EXCITINGBOXING_KEY_RIGHT_HOOK, "excitingboxing", "right-hook" }, { EXCITINGBOXING_KEYS + EXCITINGBOXING_KEY_LEFT_JAB, DIK_COMMA, IDS_INPUT_EXCITINGBOXING_KEY_LEFT_JAB, "excitingboxing", "left-jab" }, { EXCITINGBOXING_KEYS + EXCITINGBOXING_KEY_RIGHT_JAB, DIK_PERIOD, IDS_INPUT_EXCITINGBOXING_KEY_RIGHT_JAB, "excitingboxing", "right-jab" }, { EXCITINGBOXING_KEYS + EXCITINGBOXING_KEY_STRAIGHT, DIK_UP, IDS_INPUT_EXCITINGBOXING_KEY_STRAIGHT, "excitingboxing", "straight" }, { EXCITINGBOXING_KEYS + EXCITINGBOXING_KEY_BODY, DIK_DOWN, IDS_INPUT_EXCITINGBOXING_KEY_BODY, "excitingboxing", "body" }, { EXCITINGBOXING_KEYS + EXCITINGBOXING_KEY_LEFT_MOVE, DIK_LEFT, IDS_INPUT_EXCITINGBOXING_KEY_LEFT_MOVE, "excitingboxing", "left-move" }, { EXCITINGBOXING_KEYS + EXCITINGBOXING_KEY_RIGHT_MOVE, DIK_RIGHT, IDS_INPUT_EXCITINGBOXING_KEY_RIGHT_MOVE, "excitingboxing", "right-move" }, { POKKUNMOGURAA_KEYS + POKKUNMOGURAA_KEY_ROW_1_1, DIK_T, IDS_INPUT_POKKUNMOGURAA_KEY_ROW_1_1, "pokkunmoguraa", "row-1-button-1" }, { POKKUNMOGURAA_KEYS + POKKUNMOGURAA_KEY_ROW_1_2, DIK_Y, IDS_INPUT_POKKUNMOGURAA_KEY_ROW_1_2, "pokkunmoguraa", "row-1-button-2" }, { POKKUNMOGURAA_KEYS + POKKUNMOGURAA_KEY_ROW_1_3, DIK_U, IDS_INPUT_POKKUNMOGURAA_KEY_ROW_1_3, "pokkunmoguraa", "row-1-button-3" }, { POKKUNMOGURAA_KEYS + POKKUNMOGURAA_KEY_ROW_1_4, DIK_I, IDS_INPUT_POKKUNMOGURAA_KEY_ROW_1_4, "pokkunmoguraa", "row-1-button-4" }, { POKKUNMOGURAA_KEYS + POKKUNMOGURAA_KEY_ROW_2_1, DIK_G, IDS_INPUT_POKKUNMOGURAA_KEY_ROW_2_1, "pokkunmoguraa", "row-2-button-1" }, { POKKUNMOGURAA_KEYS + POKKUNMOGURAA_KEY_ROW_2_2, DIK_H, IDS_INPUT_POKKUNMOGURAA_KEY_ROW_2_2, "pokkunmoguraa", "row-2-button-2" }, { POKKUNMOGURAA_KEYS + POKKUNMOGURAA_KEY_ROW_2_3, DIK_J, IDS_INPUT_POKKUNMOGURAA_KEY_ROW_2_3, "pokkunmoguraa", "row-2-button-3" }, { POKKUNMOGURAA_KEYS + POKKUNMOGURAA_KEY_ROW_2_4, DIK_K, IDS_INPUT_POKKUNMOGURAA_KEY_ROW_2_4, "pokkunmoguraa", "row-2-button-4" }, { POKKUNMOGURAA_KEYS + POKKUNMOGURAA_KEY_ROW_3_1, DIK_B, IDS_INPUT_POKKUNMOGURAA_KEY_ROW_3_1, "pokkunmoguraa", "row-3-button-1" }, { POKKUNMOGURAA_KEYS + POKKUNMOGURAA_KEY_ROW_3_2, DIK_N, IDS_INPUT_POKKUNMOGURAA_KEY_ROW_3_2, "pokkunmoguraa", "row-3-button-2" }, { POKKUNMOGURAA_KEYS + POKKUNMOGURAA_KEY_ROW_3_3, DIK_M, IDS_INPUT_POKKUNMOGURAA_KEY_ROW_3_3, "pokkunmoguraa", "row-3-button-3" }, { POKKUNMOGURAA_KEYS + POKKUNMOGURAA_KEY_ROW_3_4, DIK_COMMA, IDS_INPUT_POKKUNMOGURAA_KEY_ROW_3_4, "pokkunmoguraa", "row-3-button-4" }, { PARTYTAP_KEYS + PARTYTAP_UNIT_1, DIK_Q, IDS_INPUT_PARTYTAP_UNIT_1, "partytap", "unit-1" }, { PARTYTAP_KEYS + PARTYTAP_UNIT_2, DIK_W, IDS_INPUT_PARTYTAP_UNIT_2, "partytap", "unit-2" }, { PARTYTAP_KEYS + PARTYTAP_UNIT_3, DIK_E, IDS_INPUT_PARTYTAP_UNIT_3, "partytap", "unit-3" }, { PARTYTAP_KEYS + PARTYTAP_UNIT_4, DIK_R, IDS_INPUT_PARTYTAP_UNIT_4, "partytap", "unit-4" }, { PARTYTAP_KEYS + PARTYTAP_UNIT_5, DIK_T, IDS_INPUT_PARTYTAP_UNIT_5, "partytap", "unit-5" }, { PARTYTAP_KEYS + PARTYTAP_UNIT_6, DIK_Y, IDS_INPUT_PARTYTAP_UNIT_6, "partytap", "unit-6" }, { KARAOKESTUDIO_KEYS + KARAOKESTUDIO_MIC, DIK_G, IDS_INPUT_KARAOKESTUDIO_MIC, "karaokestudio", "mic" }, { KARAOKESTUDIO_KEYS + KARAOKESTUDIO_A, DIK_H, IDS_INPUT_KARAOKESTUDIO_A, "karaokestudio", "a" }, { KARAOKESTUDIO_KEYS + KARAOKESTUDIO_B, DIK_J, IDS_INPUT_KARAOKESTUDIO_B, "karaokestudio", "b" }, { EMULATION_KEYS + EMULATION_KEY_ALT_SPEED, DIK_TAB, IDS_INPUT_EMULATION_KEY_ALT_SPEED, "emulation", "alt-speed" }, { EMULATION_KEYS + EMULATION_KEY_REWIND, DIK_BACK, IDS_INPUT_EMULATION_KEY_REWIND, "emulation", "rewind" }, { EMULATION_KEYS + EMULATION_KEY_INSERT_COIN_1, DIK_F2, IDS_INPUT_EMULATION_KEY_INSERT_COIN_1, "emulation", "insert-coin-1" }, { EMULATION_KEYS + EMULATION_KEY_INSERT_COIN_2, DIK_F3, IDS_INPUT_EMULATION_KEY_INSERT_COIN_2, "emulation", "insert-coin-2" }, { FILE_KEYS + FILE_KEY_OPEN, CTRL | 'O', IDS_INPUT_FILE_KEY_OPEN, "file", "open" }, { FILE_KEYS + FILE_KEY_SAVE_STATE, VK_F5, IDS_INPUT_FILE_KEY_SAVE_STATE, "file", "save-state" }, { FILE_KEYS + FILE_KEY_LOAD_STATE, VK_F7, IDS_INPUT_FILE_KEY_LOAD_STATE, "file", "load-state" }, { FILE_KEYS + FILE_KEY_QUICK_LOAD_STATE_1, '1', IDS_INPUT_FILE_KEY_QUICK_LOAD_STATE_1, "file", "quick-load-state-1" }, { FILE_KEYS + FILE_KEY_QUICK_LOAD_STATE_2, '2', IDS_INPUT_FILE_KEY_QUICK_LOAD_STATE_2, "file", "quick-load-state-2" }, { FILE_KEYS + FILE_KEY_QUICK_LOAD_STATE_3, '3', IDS_INPUT_FILE_KEY_QUICK_LOAD_STATE_3, "file", "quick-load-state-3" }, { FILE_KEYS + FILE_KEY_QUICK_LOAD_STATE_4, '4', IDS_INPUT_FILE_KEY_QUICK_LOAD_STATE_4, "file", "quick-load-state-4" }, { FILE_KEYS + FILE_KEY_QUICK_LOAD_STATE_5, '5', IDS_INPUT_FILE_KEY_QUICK_LOAD_STATE_5, "file", "quick-load-state-5" }, { FILE_KEYS + FILE_KEY_QUICK_LOAD_STATE_6, '6', IDS_INPUT_FILE_KEY_QUICK_LOAD_STATE_6, "file", "quick-load-state-6" }, { FILE_KEYS + FILE_KEY_QUICK_LOAD_STATE_7, '7', IDS_INPUT_FILE_KEY_QUICK_LOAD_STATE_7, "file", "quick-load-state-7" }, { FILE_KEYS + FILE_KEY_QUICK_LOAD_STATE_8, '8', IDS_INPUT_FILE_KEY_QUICK_LOAD_STATE_8, "file", "quick-load-state-8" }, { FILE_KEYS + FILE_KEY_QUICK_LOAD_STATE_9, '9', IDS_INPUT_FILE_KEY_QUICK_LOAD_STATE_9, "file", "quick-load-state-9" }, { FILE_KEYS + FILE_KEY_QUICK_LOAD_LAST_STATE, '0', IDS_INPUT_FILE_KEY_QUICK_LOAD_LAST_STATE, "file", "quick-load-state-newest" }, { FILE_KEYS + FILE_KEY_QUICK_SAVE_STATE_1, SHIFT | '1', IDS_INPUT_FILE_KEY_QUICK_SAVE_STATE_1, "file", "quick-save-state-1" }, { FILE_KEYS + FILE_KEY_QUICK_SAVE_STATE_2, SHIFT | '2', IDS_INPUT_FILE_KEY_QUICK_SAVE_STATE_2, "file", "quick-save-state-2" }, { FILE_KEYS + FILE_KEY_QUICK_SAVE_STATE_3, SHIFT | '3', IDS_INPUT_FILE_KEY_QUICK_SAVE_STATE_3, "file", "quick-save-state-3" }, { FILE_KEYS + FILE_KEY_QUICK_SAVE_STATE_4, SHIFT | '4', IDS_INPUT_FILE_KEY_QUICK_SAVE_STATE_4, "file", "quick-save-state-4" }, { FILE_KEYS + FILE_KEY_QUICK_SAVE_STATE_5, SHIFT | '5', IDS_INPUT_FILE_KEY_QUICK_SAVE_STATE_5, "file", "quick-save-state-5" }, { FILE_KEYS + FILE_KEY_QUICK_SAVE_STATE_6, SHIFT | '6', IDS_INPUT_FILE_KEY_QUICK_SAVE_STATE_6, "file", "quick-save-state-6" }, { FILE_KEYS + FILE_KEY_QUICK_SAVE_STATE_7, SHIFT | '7', IDS_INPUT_FILE_KEY_QUICK_SAVE_STATE_7, "file", "quick-save-state-7" }, { FILE_KEYS + FILE_KEY_QUICK_SAVE_STATE_8, SHIFT | '8', IDS_INPUT_FILE_KEY_QUICK_SAVE_STATE_8, "file", "quick-save-state-8" }, { FILE_KEYS + FILE_KEY_QUICK_SAVE_STATE_9, SHIFT | '9', IDS_INPUT_FILE_KEY_QUICK_SAVE_STATE_9, "file", "quick-save-state-9" }, { FILE_KEYS + FILE_KEY_QUICK_SAVE_NEXT_STATE, SHIFT | '0', IDS_INPUT_FILE_KEY_QUICK_SAVE_NEXT_STATE, "file", "quick-save-state-oldest" }, { FILE_KEYS + FILE_KEY_SAVE_SCREENSHOT, ALT | 'E', IDS_INPUT_FILE_KEY_SAVE_SCREENSHOT, "file", "save-screenshot" }, { FILE_KEYS + FILE_KEY_LAUNCHER, ALT | 'L', IDS_INPUT_FILE_KEY_LAUNCHER, "file", "launcher" }, { FILE_KEYS + FILE_KEY_EXIT, ALT | 'X', IDS_INPUT_FILE_KEY_EXIT, "file", "exit" }, { MACHINE_KEYS + MACHINE_KEY_POWER, SHIFT | 'D', IDS_INPUT_MACHINE_KEY_POWER, "machine", "power" }, { MACHINE_KEYS + MACHINE_KEY_RESET_SOFT, SHIFT | 'R', IDS_INPUT_MACHINE_KEY_RESET_SOFT, "machine", "soft-reset" }, { MACHINE_KEYS + MACHINE_KEY_RESET_HARD, SHIFT | 'T', IDS_INPUT_MACHINE_KEY_RESET_HARD, "machine", "hard-reset" }, { MACHINE_KEYS + MACHINE_KEY_PAUSE, SHIFT | 'P', IDS_INPUT_MACHINE_KEY_PAUSE, "machine", "pause" }, { MACHINE_KEYS + MACHINE_KEY_UNLIMITED_SPRITES, SHIFT | 'U', IDS_INPUT_MACHINE_KEY_UNLIMITED_SPRITES, "machine", "no-sprite-limit-toggle" }, { MACHINE_KEYS + MACHINE_KEY_CHANGE_DISK_SIDE, SHIFT | 'B', IDS_INPUT_MACHINE_KEY_CHANGE_DISK_SIDE, "machine", "change-disk-side" }, { NSF_KEYS + NSF_KEY_PLAY, SHIFT | VK_UP, IDS_INPUT_NSF_KEY_PLAY, "nsf", "play-song" }, { NSF_KEYS + NSF_KEY_STOP, SHIFT | VK_DOWN, IDS_INPUT_NSF_KEY_STOP, "nsf", "stop-song" }, { NSF_KEYS + NSF_KEY_NEXT, SHIFT | VK_RIGHT, IDS_INPUT_NSF_KEY_NEXT, "nsf", "next-song" }, { NSF_KEYS + NSF_KEY_PREV, SHIFT | VK_LEFT, IDS_INPUT_NSF_KEY_PREV, "nsf", "previous-song" }, { VIEW_KEYS + VIEW_KEY_SCREENSIZE_1X, ALT | '1', IDS_INPUT_VIEW_KEY_SCREENSIZE_1X, "view", "screen-size-1x" }, { VIEW_KEYS + VIEW_KEY_SCREENSIZE_2X, ALT | '2', IDS_INPUT_VIEW_KEY_SCREENSIZE_2X, "view", "screen-size-2x" }, { VIEW_KEYS + VIEW_KEY_SCREENSIZE_3X, ALT | '3', IDS_INPUT_VIEW_KEY_SCREENSIZE_3X, "view", "screen-size-3x" }, { VIEW_KEYS + VIEW_KEY_SCREENSIZE_4X, ALT | '4', IDS_INPUT_VIEW_KEY_SCREENSIZE_4X, "view", "screen-size-4x" }, { VIEW_KEYS + VIEW_KEY_SCREENSIZE_5X, ALT | '5', IDS_INPUT_VIEW_KEY_SCREENSIZE_5X, "view", "screen-size-5x" }, { VIEW_KEYS + VIEW_KEY_SCREENSIZE_6X, ALT | '6', IDS_INPUT_VIEW_KEY_SCREENSIZE_6X, "view", "screen-size-6x" }, { VIEW_KEYS + VIEW_KEY_SCREENSIZE_7X, ALT | '7', IDS_INPUT_VIEW_KEY_SCREENSIZE_7X, "view", "screen-size-7x" }, { VIEW_KEYS + VIEW_KEY_SCREENSIZE_8X, ALT | '8', IDS_INPUT_VIEW_KEY_SCREENSIZE_8X, "view", "screen-size-8x" }, { VIEW_KEYS + VIEW_KEY_SCREENSIZE_9X, ALT | '9', IDS_INPUT_VIEW_KEY_SCREENSIZE_9X, "view", "screen-size-9x" }, { VIEW_KEYS + VIEW_KEY_SCREENSIZE_MAX, ALT | 'S', IDS_INPUT_VIEW_KEY_SCREENSIZE_MAX, "view", "screen-size-max" }, { VIEW_KEYS + VIEW_KEY_SHOW_MENU, VK_ESCAPE, IDS_INPUT_VIEW_KEY_SHOW_MENU, "view", "toggle-menu" }, { VIEW_KEYS + VIEW_KEY_SHOW_STATUSBAR, CTRL | 'B', IDS_INPUT_VIEW_KEY_SHOW_STATUSBAR, "view", "toggle-status-bar" }, { VIEW_KEYS + VIEW_KEY_SHOW_ONTOP, CTRL | 'T', IDS_INPUT_VIEW_KEY_SHOW_ONTOP, "view", "toggle-window-on-top" }, { VIEW_KEYS + VIEW_KEY_SHOW_FPS, CTRL | 'F', IDS_INPUT_VIEW_KEY_SHOW_FPS, "view", "toggle-fps" }, { VIEW_KEYS + VIEW_KEY_FULLSCREEN, ALT | VK_RETURN, IDS_INPUT_VIEW_KEY_FULLSCREEN, "view", "fullscreen" }, { HELP_KEYS + HELP_KEY_HELP, VK_F1, IDS_INPUT_HELP_KEY_HELP, "help", "readme" } }; struct Input::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; }; const MsgHandler::Entry Input::Handlers::messages[] = { { WM_INITDIALOG, &Input::OnInitDialog }, { WM_HSCROLL, &Input::OnHScroll }, { WM_DESTROY, &Input::OnDestroy } }; const MsgHandler::Entry Input::Handlers::commands[] = { { IDC_INPUT_MAP, &Input::OnCmdDblClk }, { IDC_INPUT_DEVICES, &Input::OnCmdDevice }, { IDC_INPUT_JOYSTICKS, &Input::OnCmdJoysticks }, { IDC_INPUT_SET, &Input::OnCmdSet }, { IDC_INPUT_SETALL, &Input::OnCmdSetAll }, { IDC_INPUT_CLEAR, &Input::OnCmdClear }, { IDC_INPUT_CLEARALL, &Input::OnCmdClearAll }, { IDC_INPUT_JOYSTICKS_ENABLE, &Input::OnCmdJoystickEnable }, { IDC_INPUT_JOYSTICKS_X, &Input::OnCmdJoystickAxis }, { IDC_INPUT_JOYSTICKS_Y, &Input::OnCmdJoystickAxis }, { IDC_INPUT_JOYSTICKS_Z, &Input::OnCmdJoystickAxis }, { IDC_INPUT_JOYSTICKS_RX, &Input::OnCmdJoystickAxis }, { IDC_INPUT_JOYSTICKS_RY, &Input::OnCmdJoystickAxis }, { IDC_INPUT_JOYSTICKS_RZ, &Input::OnCmdJoystickAxis }, { IDC_INPUT_JOYSTICKS_S0, &Input::OnCmdJoystickAxis }, { IDC_INPUT_JOYSTICKS_S1, &Input::OnCmdJoystickAxis }, { IDC_INPUT_JOYSTICKS_POV0, &Input::OnCmdJoystickAxis }, { IDC_INPUT_JOYSTICKS_POV1, &Input::OnCmdJoystickAxis }, { IDC_INPUT_JOYSTICKS_POV2, &Input::OnCmdJoystickAxis }, { IDC_INPUT_JOYSTICKS_POV3, &Input::OnCmdJoystickAxis }, { IDC_INPUT_JOYSTICKS_CALIBRATE, &Input::OnCmdCalibrate }, { IDC_INPUT_JOYSTICKS_DEFAULT, &Input::OnCmdJoysticksDefault }, { IDC_INPUT_DEFAULT, &Input::OnCmdDefault }, { IDC_INPUT_DEFAULT_CATEGORY, &Input::OnCmdDefaultCategory }, { IDC_INPUT_AUTOFIRE_DEFAULT, &Input::OnCmdAutoFireDefault } }; Input::Settings::Settings() : autoFireSpeed(AUTOFIRE_DEFAULT_SPEED) {} inline uint Input::Settings::Mapping::Code() const { return key & 0xFF; } inline uint Input::Settings::Mapping::Alt() const { return (key & ALT) ? VK_MENU : 0; } inline uint Input::Settings::Mapping::Shift() const { return (key & SHIFT) ? VK_SHIFT : 0; } inline uint Input::Settings::Mapping::Ctrl() const { return (key & CTRL) ? VK_CONTROL : 0; } inline const Input::Settings::Mapping& Input::Settings::GetMapping(uint type,uint index) { NST_ASSERT( index < NumTypeKeys(type) ); return map[types[type].offset + index]; } inline const Input::Settings::Type& Input::Settings::GetType(uint type) { NST_ASSERT( type < NUM_TYPES ); return types[type]; } inline void Input::Settings::Unmap(uint index) { NST_ASSERT( index < NUM_KEYS ); keys[index].Unmap(); } bool Input::Settings::Map(const uint index,const Key& key) { NST_ASSERT( index < NUM_KEYS ); if (key.Assigned()) { if (index >= COMMAND_KEYS) { for (uint i=0; i < COMMAND_KEYS; ++i) { if (key == keys[i]) return (i == index); } } for (uint i=COMMAND_KEYS; i < NUM_KEYS; ++i) { if (key == keys[i]) return (i == index); } } keys[index] = key; return true; } void Input::Settings::Clear() { for (uint i=0; i < NUM_KEYS; ++i) keys[i].Unmap(); } void Input::Settings::Clear(const uint type) { NST_ASSERT( type < NUM_TYPES ); for (uint i=types[type].offset, n=types[type+1].offset; i < n; ++i) keys[i].Unmap(); } void Input::Settings::Reset(const DirectX::DirectInput& directInput) { for (uint i=0; i < NUM_TYPES; ++i) Reset( directInput, i ); } void Input::Settings::Reset(const DirectX::DirectInput& directInput,const uint type) { NST_ASSERT( type < NUM_TYPES ); const Mapping* it = map + types[type].offset; const Mapping* const end = map + types[type + 1].offset; NST_ASSERT( it < end ); Key key; if (type < TYPE_FILE) { do { directInput.MapKeyboard( key, it->key ); Map( it->index, key ); } while (++it != end); } else { do { key.MapVirtualKey( it->Code(), it->Alt(), it->Ctrl(), it->Shift() ); Map( it->index, key ); } while (++it != end); } } Input::Input(DirectX::DirectInput& di,Managers::Emulator& emulator,const Configuration& cfg) : nes ( emulator ), directInput ( di ), dialog ( IDD_INPUT, this, Handlers::messages, Handlers::commands ) { Configuration::ConstSection input( cfg["input"] ); settings.Clear(); settings.autoFireSpeed = input["auto-fire-speed"].Int( Settings::AUTOFIRE_DEFAULT_SPEED ); settings.allowSimulAxes = input["allow-simultaneous-axes"].Yes(); if (settings.autoFireSpeed > Settings::AUTOFIRE_MAX_SPEED) settings.autoFireSpeed = Settings::AUTOFIRE_DEFAULT_SPEED; System::Guid joyGuids[DirectX::DirectInput::MAX_JOYSTICKS]; uint maxGuids = 0; if (const uint numJoysticks = directInput.NumJoysticks()) { bool referenced[DirectX::DirectInput::MAX_JOYSTICKS] = {false}; if (Configuration::ConstSection joysticks=input["joysticks"]) { bool alert = true; for (uint i=0; i < numJoysticks; ++i) { Configuration::ConstSection joystick( joysticks["joystick"][i] ); if (!joystick) break; uint index = UINT_MAX; const System::Guid guid( joystick["device"].Str() ); for (uint j=0; j < numJoysticks; ++j) { if (guid == directInput.GetJoystickGuid(j)) { index = j; referenced[j] = true; break; } } if (index == UINT_MAX) { for (uint j=0; j < numJoysticks; ++j) { if (!referenced[j]) { index = j; referenced[j] = true; break; } } if (index == UINT_MAX || (alert && !Window::User::Confirm( IDS_INPUT_JOY_GUID_MISMATCH ))) break; alert = false; } joyGuids[maxGuids++] = directInput.GetJoystickGuid(index); directInput.ScanEnableJoystick( index, !joystick["enabled"].No() ); uint deadzone = joystick["deadzone"].Int( DirectX::DirectInput::DEFAULT_DEADZONE ); if (deadzone > DirectX::DirectInput::DEADZONE_MAX) deadzone = DirectX::DirectInput::DEFAULT_DEADZONE; directInput.SetAxisDeadZone( index, deadzone ); if (Configuration::ConstSection scan=joystick["scan"]) { uint axes = 0; static cstring const names[] = { "x","y","z","rx","ry","rz","z0","z1","p0","p1","p2","p3" }; for (uint j=0; j < sizeof(array(names)); ++j) { if (scan[names[j]].Yes()) { axes |= (1U << j); } else if (!scan[names[j]].No()) { axes |= (1U << j) & DirectX::DirectInput::DEFAULT_AXES; } } directInput.SetScannerAxes( index, axes ); } } } } Configuration::ConstSection keys( input["keys"] ); HeapString keyName; for (uint i=0; i < Settings::NUM_TYPES; ++i) { for (uint j=0, n=Settings::NumTypeKeys(i); j < n; ++j) { const Settings::Mapping& mapping = Settings::GetMapping( i, j ); keyName = keys[mapping.cfgType][mapping.cfgKey].Str(); Settings::Key key; if (keyName.Length()) { if (i < Settings::TYPE_COMMAND || !key.MapVirtualKey( keyName )) directInput.MapKey( key, keyName.Ptr(), joyGuids, maxGuids ); } else { if (i < Settings::TYPE_COMMAND) directInput.MapKeyboard( key, mapping.key ); else key.MapVirtualKey( mapping.Code(), mapping.Alt(), mapping.Ctrl(), mapping.Shift() ); } if (!settings.Map( mapping.index, key )) { Io::Log() << "DirectInput: warning, key assigned to \"" << mapping.cfgType << ':' << mapping.cfgKey << "\" is already in use!\r\n"; } } } } void Input::Save(Configuration& cfg) const { Configuration::Section input( cfg["input"] ); input["auto-fire-speed"].Int() = settings.autoFireSpeed; input["allow-simultaneous-axes"].YesNo() = settings.allowSimulAxes; if (const uint numJoysticks=directInput.NumJoysticks()) { Configuration::Section joysticks( input["joysticks"] ); for (uint i=0; i < numJoysticks; ++i) { Configuration::Section joystick( joysticks["joystick"][i] ); joystick["device"].Str() = directInput.GetJoystickGuid(i).GetString(); joystick["enabled"].YesNo() = directInput.JoystickScanEnabled(i); joystick["deadzone"].Int() = directInput.GetAxisDeadZone(i); static cstring const names[] = { "x","y","z","rx","ry","rz","z0","z1","p0","p1","p2","p3" }; Configuration::Section scan( joystick["scan"] ); for (uint j=0, axes=directInput.GetScannerAxes(i); j < sizeof(array(names)); ++j) scan[names[j]].YesNo() = (axes & (1U << j)); } } Configuration::Section keys( input["keys"] ); for (uint i=0; i < Settings::NUM_TYPES; ++i) { for (uint j=0, n=Settings::NumTypeKeys(i); j < n; ++j) { const Settings::Mapping& mapping = Settings::GetMapping( i, j ); keys[mapping.cfgType][mapping.cfgKey].Str() = directInput.GetKeyName( settings.GetKey(mapping.index) ); } } } ibool Input::OnInitDialog(Param&) { { const Control::ListBox listBox( dialog.ListBox(IDC_INPUT_DEVICES) ); listBox.Reserve( Settings::NUM_TYPES ); for (uint i=0; i < Settings::NUM_TYPES; ++i) listBox.Add( Resource::String(Settings::GetType(i).name) ); listBox[0].Select(); } if (const uint numJoysticks = directInput.NumJoysticks()) { const Control::ComboBox comboBox( dialog.ComboBox(IDC_INPUT_JOYSTICKS) ); for (uint i=0; i < numJoysticks; ++i) comboBox.Add( directInput.GetJoystickName(i).Ptr() ); comboBox[0].Select(); dialog.Slider(IDC_INPUT_JOYSTICKS_DEADZONE).SetRange( 0, DirectX::DirectInput::DEADZONE_MAX ); UpdateJoysticks( 0 ); } else for (uint i=IDC_INPUT_JOYSTICKS; i <= IDC_INPUT_JOYSTICKS_DEFAULT; ++i) { dialog.Control( i ).Disable(); } dialog.Slider( IDC_INPUT_AUTOFIRE_SLIDER ).SetRange( 0, Settings::AUTOFIRE_MAX_SPEED ); dialog.Slider( IDC_INPUT_AUTOFIRE_SLIDER ).Position() = settings.autoFireSpeed; dialog.CheckBox( IDC_INPUT_ALLOW_SIMUL_AXES ).Check( settings.allowSimulAxes ); UpdateKeyNames( 0 ); UpdateKeyMap( 0 ); return true; } ibool Input::OnCmdDblClk(Param& param) { if (HIWORD(param.wParam) == LBN_DBLCLK) { if (ScanKeys() == SCAN_NEXT) SelectNextMapKey(); return true; } return false; } ibool Input::OnHScroll(Param& param) { if (param.Slider().GetId() == IDC_INPUT_JOYSTICKS_DEADZONE) { const uint deadZone = param.Slider().Scroll(); if (directInput.SetAxisDeadZone( dialog.ComboBox(IDC_INPUT_JOYSTICKS).Selection().GetIndex(), deadZone )) dialog.Edit( IDC_INPUT_JOYSTICKS_DEADZONE_NUM ) << deadZone; } return true; } void Input::UpdateKeyNames(const uint type) const { NST_ASSERT( type < Settings::NUM_TYPES ); const Control::ListBox listBox( dialog.ListBox(IDC_INPUT_KEYS) ); listBox.Clear(); listBox.Reserve( Settings::NumTypeKeys(type) ); for (uint i=0, n=Settings::NumTypeKeys(type); i < n; ++i) listBox.Add( Resource::String(Settings::GetMapping(type,i).dlgName) ); } void Input::UpdateKeyMap(const uint type) const { const Control::ListBox listBox( dialog.ListBox(IDC_INPUT_MAP) ); listBox.Clear(); listBox.Reserve( Settings::NumTypeKeys(type) ); for (uint i=0, n=Settings::NumTypeKeys(type); i < n; ++i) listBox.Add( directInput.GetKeyName( settings.GetKey(Settings::GetMapping(type,i).index) ).Ptr() ); listBox[0].Select(); } void Input::ResetJoysticks() { if (uint numJoysticks = directInput.NumJoysticks()) { do { directInput.ScanEnableJoystick( --numJoysticks, true ); directInput.SetAxisDeadZone( numJoysticks, DirectX::DirectInput::DEFAULT_DEADZONE ); directInput.SetScannerAxes( numJoysticks, DirectX::DirectInput::DEFAULT_AXES ); } while (numJoysticks); UpdateJoysticks( dialog.ComboBox(IDC_INPUT_JOYSTICKS).Selection().GetIndex() ); } } void Input::UpdateJoysticks(const uint type) const { NST_ASSERT( directInput.NumJoysticks() ); const bool enabled = directInput.JoystickScanEnabled( type ); dialog.CheckBox(IDC_INPUT_JOYSTICKS_ENABLE).Check( enabled ); { const uint deadZone = directInput.GetAxisDeadZone( type ); dialog.Slider( IDC_INPUT_JOYSTICKS_DEADZONE ).Position() = deadZone; dialog.Slider( IDC_INPUT_JOYSTICKS_DEADZONE ).Enable( enabled ); dialog.Slider( IDC_INPUT_JOYSTICKS_DEADZONE_TEXT ).Enable( enabled ); dialog.Edit( IDC_INPUT_JOYSTICKS_DEADZONE_NUM ) << deadZone; dialog.Edit( IDC_INPUT_JOYSTICKS_DEADZONE_NUM ).Enable( enabled ); } { const uint axes[] = { directInput.GetAvailableAxes( type ), directInput.GetScannerAxes( type ) }; for (uint i=0; i <= (IDC_INPUT_JOYSTICKS_POV3-IDC_INPUT_JOYSTICKS_X); ++i) { const Control::CheckBox box( dialog.CheckBox(IDC_INPUT_JOYSTICKS_X + i) ); box.Enable( enabled && (axes[0] & (1U << i)) ); box.Check( axes[1] & (1U << i) ); } } } ibool Input::OnCmdDevice(Param& param) { if (param.ListBox().SelectionChanged()) { const uint type = dialog.ListBox(IDC_INPUT_DEVICES).Selection().GetIndex(); UpdateKeyNames( type ); UpdateKeyMap( type ); } return true; } ibool Input::OnCmdJoysticks(Param& param) { if (param.ComboBox().SelectionChanged()) UpdateJoysticks( dialog.ComboBox(IDC_INPUT_JOYSTICKS).Selection().GetIndex() ); return true; } ibool Input::OnCmdJoystickEnable(Param& param) { if (param.Button().Clicked()) { const uint type = dialog.ComboBox(IDC_INPUT_JOYSTICKS).Selection().GetIndex(); directInput.ScanEnableJoystick( type, dialog.CheckBox(param.Button().GetId()).Checked() ); UpdateJoysticks( type ); } return true; } ibool Input::OnCmdJoystickAxis(Param& param) { if (param.Button().Clicked()) { directInput.SetScannerAxes ( dialog.ComboBox(IDC_INPUT_JOYSTICKS).Selection().GetIndex(), 1U << (param.Button().GetId() - IDC_INPUT_JOYSTICKS_X), dialog.CheckBox(param.Button().GetId()).Checked() ); } return true; } ibool Input::OnCmdSet(Param& param) { if (param.Button().Clicked() && ScanKeys() == SCAN_NEXT) SelectNextMapKey(); return true; } ibool Input::OnCmdSetAll(Param& param) { if (param.Button().Clicked()) { const Control::ListBox listBox( dialog.ListBox(IDC_INPUT_MAP) ); listBox[0].Select(); for (uint count=listBox.Size(); count; --count) { if (ScanKeys() == SCAN_ABORT) break; SelectNextMapKey(); } } return true; } ibool Input::OnCmdClear(Param& param) { if (param.Button().Clicked()) { const Control::ListBox keyBox( dialog.ListBox(IDC_INPUT_MAP) ); const uint index = Settings::GetMapping( dialog.ListBox(IDC_INPUT_DEVICES).Selection().GetIndex(), keyBox.Selection().GetIndex() ).index; settings.Unmap( index ); keyBox.Selection().Text() << directInput.GetKeyName( settings.GetKey(index) ).Ptr(); SelectNextMapKey(); } return true; } ibool Input::OnCmdClearAll(Param& param) { if (param.Button().Clicked()) { const uint type = dialog.ListBox(IDC_INPUT_DEVICES).Selection().GetIndex(); settings.Clear( type ); UpdateKeyMap( type ); } return true; } ibool Input::OnCmdDefaultCategory(Param& param) { if (param.Button().Clicked()) { const uint type = dialog.ListBox(IDC_INPUT_DEVICES).Selection().GetIndex(); settings.Clear( type ); settings.Reset( directInput, type ); UpdateKeyMap( type ); } return true; } ibool Input::OnCmdAutoFireDefault(Param& param) { if (param.Button().Clicked()) dialog.Slider( IDC_INPUT_AUTOFIRE_SLIDER ).Position() = Settings::AUTOFIRE_DEFAULT_SPEED; return true; } ibool Input::OnCmdCalibrate(Param& param) { if (param.Button().Clicked()) directInput.Calibrate( dialog.ComboBox(IDC_INPUT_JOYSTICKS).Selection().GetIndex() ); return true; } ibool Input::OnCmdJoysticksDefault(Param& param) { if (param.Button().Clicked()) ResetJoysticks(); return true; } ibool Input::OnCmdDefault(Param& param) { if (param.Button().Clicked()) { settings.Clear(); settings.Reset( directInput ); dialog.CheckBox( IDC_INPUT_ALLOW_SIMUL_AXES ).Uncheck(); dialog.Slider( IDC_INPUT_AUTOFIRE_SLIDER ).Position() = Settings::AUTOFIRE_DEFAULT_SPEED; ResetJoysticks(); UpdateKeyMap( dialog.ListBox(IDC_INPUT_DEVICES).Selection().GetIndex() ); } return true; } ibool Input::OnDestroy(Param&) { settings.autoFireSpeed = dialog.Slider( IDC_INPUT_AUTOFIRE_SLIDER ).Position(); settings.allowSimulAxes = dialog.CheckBox( IDC_INPUT_ALLOW_SIMUL_AXES ).Checked(); return true; } class Input::KeyPressWindow : Dynamic { public: enum Result { RESULT_OK, RESULT_ABORT, RESULT_DUPLICATE, RESULT_INVALID }; private: struct Timer { enum { RATE = 50, CLOCK = 1000, START = 5000, SEC = 1000 }; int remaining; int clock; Timer() : remaining(START), clock(START) {} }; Input& base; Timer timer; Result result; void Close(Result r) { result = r; base.dialog.Enable( true ); Destroy(); } uint OnTimer() { timer.remaining -= Timer::RATE; if (timer.remaining <= 0 || *this != ::GetForegroundWindow()) { Close( RESULT_ABORT ); return false; } if (timer.remaining <= timer.clock) { uint msgId; if (base.dialog.ListBox(IDC_INPUT_DEVICES).Selection().GetIndex() >= Settings::TYPE_COMMAND) msgId = IDS_DIALOG_INPUT_PRESS_ANY_KEY_MENU; else msgId = IDS_DIALOG_INPUT_PRESS_ANY_KEY_EMU; base.dialog.Control(IDC_INPUT_KEYPRESS_TEXT).Text() << Resource::String(msgId).Invoke( wchar_t('0' + (timer.clock / Timer::SEC)) ); timer.clock -= Timer::CLOCK; } DirectX::DirectInput::ScanMode scanMode; if (base.dialog.ListBox(IDC_INPUT_DEVICES).Selection().GetIndex() < Settings::TYPE_COMMAND) scanMode = DirectX::DirectInput::SCAN_MODE_ALL; else scanMode = DirectX::DirectInput::SCAN_MODE_JOY; Settings::Key key; switch (base.directInput.ScanKey( key, scanMode )) { case DirectX::DirectInput::SCAN_GOOD_KEY: for (uint i=10; i && base.directInput.AnyPressed(); --i) ::Sleep( 100 ); if (base.MapSelectedKey( key )) { Close( RESULT_OK ); return false; } else { Close( RESULT_DUPLICATE ); return false; } break; case DirectX::DirectInput::SCAN_INVALID_KEY: Close( RESULT_INVALID ); return false; } return true; } ibool OnCreate(Param& param) { base.dialog.Enable( false ); base.directInput.BeginScanMode( param.hWnd ); StartTimer( this, &KeyPressWindow::OnTimer, Timer::RATE ); ::SetWindowPos( param.hWnd, HWND_TOP, 0, 0, 0, 0, SWP_HIDEWINDOW ); return false; } ibool OnDestroy(Param&) { StopTimer( this, &KeyPressWindow::OnTimer ); base.directInput.EndScanMode(); base.dialog.Control(IDC_INPUT_KEYPRESS_TEXT).Text().Clear(); return false; } ibool OnKeyDown(Param& param) { if (base.dialog.ListBox(IDC_INPUT_DEVICES).Selection().GetIndex() >= Settings::TYPE_COMMAND) { if (param.wParam != VK_SHIFT && param.wParam != VK_CONTROL && param.wParam != VK_MENU) { const uint vKeys[3] = { (::GetAsyncKeyState( VK_SHIFT ) & 0x8000U) ? VK_SHIFT : 0, (::GetAsyncKeyState( VK_CONTROL ) & 0x8000U) ? VK_CONTROL : 0, (::GetAsyncKeyState( VK_MENU ) & 0x8000U) ? VK_MENU : 0 }; Settings::Key key; if (!key.MapVirtualKey( param.wParam, vKeys[0], vKeys[1], vKeys[2] )) { Close( RESULT_INVALID ); } else if (!base.MapSelectedKey( key )) { Close( RESULT_DUPLICATE ); } else { Close( RESULT_OK ); } } } return false; } public: explicit KeyPressWindow(Input& b) : base(b), result(RESULT_ABORT) { static const MsgHandler::Entry messages[] = { { WM_CREATE, &KeyPressWindow::OnCreate }, { WM_DESTROY, &KeyPressWindow::OnDestroy }, { WM_KEYDOWN, &KeyPressWindow::OnKeyDown }, { WM_SYSKEYDOWN, &KeyPressWindow::OnKeyDown } }; Messages().Set( this, messages ); Context context; context.className = L"Poll Key"; context.windowName = context.className; context.winStyle = WS_POPUP; context.hParent = base.dialog; Create( context ); } Result Poll() const { for (MSG msg; *this && ::GetMessage( &msg, NULL, 0, 0 ) > 0; ) { ::TranslateMessage( &msg ); ::DispatchMessage( &msg ); } return result; } }; INT_PTR Input::ScanKeys() { switch (KeyPressWindow(*this).Poll()) { case KeyPressWindow::RESULT_INVALID: User::Warn( IDS_DIALOG_INPUT_PRESS_ANY_KEY_INVALID, IDS_TITLE_ERROR ); return SCAN_ABORT; case KeyPressWindow::RESULT_DUPLICATE: User::Warn( IDS_DIALOG_INPUT_DUPLICATE_KEYS, IDS_TITLE_ERROR ); return SCAN_ABORT; case KeyPressWindow::RESULT_ABORT: return SCAN_ABORT; } return SCAN_NEXT; } void Input::SelectNextMapKey() { const Control::ListBox keyBox( dialog.ListBox(IDC_INPUT_MAP) ); const uint index = keyBox.Selection().GetIndex() + 1; keyBox[index < keyBox.Size() ? index : 0].Select(); } bool Input::MapSelectedKey(const Settings::Key& key) { const uint index = Settings::GetMapping( dialog.ListBox(IDC_INPUT_DEVICES).Selection().GetIndex(), dialog.ListBox(IDC_INPUT_MAP).Selection().GetIndex() ).index; if (settings.Map( index, key )) { dialog.ListBox(IDC_INPUT_MAP).Selection().Text() << directInput.GetKeyName( settings.GetKey(index) ).Ptr(); return true; } return false; } } } nestopia-1.51.1/source/win32/NstDialogInput.hpp000066400000000000000000000267631411157722000213160ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIALOG_INPUT_H #define NST_DIALOG_INPUT_H #pragma once #include "NstWindowDialog.hpp" #include "NstDirectInput.hpp" namespace Nestopia { namespace Window { class Input { public: Input(DirectX::DirectInput&,Managers::Emulator&,const Configuration&); void Save(Configuration&) const; private: struct Handlers; class KeyPressWindow; enum { SCAN_ABORT, SCAN_NEXT }; void ResetJoysticks(); void ResetKeys(); int ScanKeys(); ibool OnInitDialog (Param&); ibool OnDestroy (Param&); ibool OnHScroll (Param&); ibool OnCmdDblClk (Param&); ibool OnCmdDevice (Param&); ibool OnCmdSet (Param&); ibool OnCmdSetAll (Param&); ibool OnCmdClear (Param&); ibool OnCmdClearAll (Param&); ibool OnCmdJoystickAxis (Param&); ibool OnCmdDefaultCategory (Param&); ibool OnCmdAutoFireDefault (Param&); ibool OnCmdJoysticks (Param&); ibool OnCmdJoystickEnable (Param&); ibool OnCmdCalibrate (Param&); ibool OnCmdJoysticksDefault (Param&); ibool OnCmdDefault (Param&); void UpdateKeyMap (uint) const; void UpdateKeyNames (uint) const; void UpdateJoysticks (uint) const; public: class Settings { friend class Input; public: enum { TYPE_PAD1, TYPE_PAD2, TYPE_PAD3, TYPE_PAD4, TYPE_POWERPAD, TYPE_POWERGLOVE, TYPE_HORITRACK, TYPE_PACHINKO, TYPE_CRAZYCLIMBER, TYPE_MAHJONG, TYPE_EXCITINGBOXING, TYPE_POKKUNMOGURAA, TYPE_PARTYTAP, TYPE_KARAOKESTUDIO, TYPE_EMULATION, TYPE_FILE, TYPE_MACHINE, TYPE_NSF, TYPE_VIEW, TYPE_HELP, NUM_TYPES, TYPE_COMMAND = TYPE_FILE }; enum { PAD_KEYS = 0, PAD_KEY_A = 0, PAD_KEY_B, PAD_KEY_SELECT, PAD_KEY_START, PAD_KEY_UP, PAD_KEY_DOWN, PAD_KEY_LEFT, PAD_KEY_RIGHT, PAD_KEY_AUTOFIRE_A, PAD_KEY_AUTOFIRE_B, PAD_KEY_MIC, PAD_NUM_KEYS, PAD1_KEYS = PAD_KEYS, PAD2_KEYS = PAD1_KEYS + PAD_NUM_KEYS, PAD3_KEYS = PAD2_KEYS + PAD_NUM_KEYS, PAD4_KEYS = PAD3_KEYS + PAD_NUM_KEYS, POWERPAD_KEYS = PAD4_KEYS + PAD_NUM_KEYS, POWERPAD_KEY_SIDE_A_1 = 0, POWERPAD_KEY_SIDE_A_2, POWERPAD_KEY_SIDE_A_3, POWERPAD_KEY_SIDE_A_4, POWERPAD_KEY_SIDE_A_5, POWERPAD_KEY_SIDE_A_6, POWERPAD_KEY_SIDE_A_7, POWERPAD_KEY_SIDE_A_8, POWERPAD_KEY_SIDE_A_9, POWERPAD_KEY_SIDE_A_10, POWERPAD_KEY_SIDE_A_11, POWERPAD_KEY_SIDE_A_12, POWERPAD_KEY_SIDE_B_3, POWERPAD_KEY_SIDE_B_2, POWERPAD_KEY_SIDE_B_8, POWERPAD_KEY_SIDE_B_7, POWERPAD_KEY_SIDE_B_6, POWERPAD_KEY_SIDE_B_5, POWERPAD_KEY_SIDE_B_11, POWERPAD_KEY_SIDE_B_10, POWERPAD_NUM_SIDE_A_KEYS = Nes::Input::Controllers::PowerPad::NUM_SIDE_A_BUTTONS, POWERPAD_NUM_SIDE_B_KEYS = Nes::Input::Controllers::PowerPad::NUM_SIDE_B_BUTTONS, POWERPAD_NUM_KEYS = POWERPAD_NUM_SIDE_A_KEYS + POWERPAD_NUM_SIDE_B_KEYS, POWERGLOVE_KEYS = POWERPAD_KEYS + POWERPAD_NUM_KEYS, POWERGLOVE_KEY_SELECT = 0, POWERGLOVE_KEY_START, POWERGLOVE_KEY_MOVE_IN, POWERGLOVE_KEY_MOVE_OUT, POWERGLOVE_KEY_ROLL_LEFT, POWERGLOVE_KEY_ROLL_RIGHT, POWERGLOVE_NUM_KEYS, HORITRACK_KEYS = POWERGLOVE_KEYS + POWERGLOVE_NUM_KEYS, HORITRACK_KEY_A = 0, HORITRACK_KEY_B, HORITRACK_KEY_SELECT, HORITRACK_KEY_START, HORITRACK_KEY_UP, HORITRACK_KEY_DOWN, HORITRACK_KEY_LEFT, HORITRACK_KEY_RIGHT, HORITRACK_KEY_SPEED, HORITRACK_KEY_ORIENTATION, HORITRACK_NUM_KEYS, PACHINKO_KEYS = HORITRACK_KEYS + HORITRACK_NUM_KEYS, PACHINKO_KEY_A = 0, PACHINKO_KEY_B, PACHINKO_KEY_SELECT, PACHINKO_KEY_START, PACHINKO_KEY_UP, PACHINKO_KEY_DOWN, PACHINKO_KEY_LEFT, PACHINKO_KEY_RIGHT, PACHINKO_NUM_KEYS, CRAZYCLIMBER_KEYS = PACHINKO_KEYS + PACHINKO_NUM_KEYS, CRAZYCLIMBER_KEY_LEFT_UP = 0, CRAZYCLIMBER_KEY_LEFT_RIGHT, CRAZYCLIMBER_KEY_LEFT_DOWN, CRAZYCLIMBER_KEY_LEFT_LEFT, CRAZYCLIMBER_KEY_RIGHT_UP, CRAZYCLIMBER_KEY_RIGHT_RIGHT, CRAZYCLIMBER_KEY_RIGHT_DOWN, CRAZYCLIMBER_KEY_RIGHT_LEFT, CRAZYCLIMBER_NUM_KEYS, MAHJONG_KEYS = CRAZYCLIMBER_KEYS + CRAZYCLIMBER_NUM_KEYS, MAHJONG_KEY_A = 0, MAHJONG_KEY_B, MAHJONG_KEY_C, MAHJONG_KEY_D, MAHJONG_KEY_E, MAHJONG_KEY_F, MAHJONG_KEY_G, MAHJONG_KEY_H, MAHJONG_KEY_I, MAHJONG_KEY_J, MAHJONG_KEY_K, MAHJONG_KEY_L, MAHJONG_KEY_M, MAHJONG_KEY_N, MAHJONG_KEY_START, MAHJONG_KEY_SELECT, MAHJONG_KEY_KAN, MAHJONG_KEY_PON, MAHJONG_KEY_CHI, MAHJONG_KEY_REACH, MAHJONG_KEY_RON, MAHJONG_NUM_KEYS, EXCITINGBOXING_KEYS = MAHJONG_KEYS + MAHJONG_NUM_KEYS, EXCITINGBOXING_KEY_LEFT_HOOK = 0, EXCITINGBOXING_KEY_RIGHT_HOOK, EXCITINGBOXING_KEY_LEFT_JAB, EXCITINGBOXING_KEY_RIGHT_JAB, EXCITINGBOXING_KEY_STRAIGHT, EXCITINGBOXING_KEY_BODY, EXCITINGBOXING_KEY_LEFT_MOVE, EXCITINGBOXING_KEY_RIGHT_MOVE, EXCITINGBOXING_NUM_KEYS, POKKUNMOGURAA_KEYS = EXCITINGBOXING_KEYS + EXCITINGBOXING_NUM_KEYS, POKKUNMOGURAA_KEY_ROW_1_1 = 0, POKKUNMOGURAA_KEY_ROW_1_2, POKKUNMOGURAA_KEY_ROW_1_3, POKKUNMOGURAA_KEY_ROW_1_4, POKKUNMOGURAA_KEY_ROW_2_1, POKKUNMOGURAA_KEY_ROW_2_2, POKKUNMOGURAA_KEY_ROW_2_3, POKKUNMOGURAA_KEY_ROW_2_4, POKKUNMOGURAA_KEY_ROW_3_1, POKKUNMOGURAA_KEY_ROW_3_2, POKKUNMOGURAA_KEY_ROW_3_3, POKKUNMOGURAA_KEY_ROW_3_4, POKKUNMOGURAA_NUM_KEYS, PARTYTAP_KEYS = POKKUNMOGURAA_KEYS + POKKUNMOGURAA_NUM_KEYS, PARTYTAP_UNIT_1 = 0, PARTYTAP_UNIT_2, PARTYTAP_UNIT_3, PARTYTAP_UNIT_4, PARTYTAP_UNIT_5, PARTYTAP_UNIT_6, PARTYTAP_NUM_KEYS, KARAOKESTUDIO_KEYS = PARTYTAP_KEYS + PARTYTAP_NUM_KEYS, KARAOKESTUDIO_MIC = 0, KARAOKESTUDIO_A, KARAOKESTUDIO_B, KARAOKESTUDIO_NUM_KEYS, EMULATION_KEYS = KARAOKESTUDIO_KEYS + KARAOKESTUDIO_NUM_KEYS, EMULATION_KEY_INSERT_COIN_1 = 0, EMULATION_KEY_INSERT_COIN_2, EMULATION_KEY_ALT_SPEED, EMULATION_KEY_REWIND, EMULATION_NUM_KEYS, POLLING_KEYS = EMULATION_KEYS + EMULATION_KEY_ALT_SPEED, COMMAND_KEYS = EMULATION_KEYS + EMULATION_NUM_KEYS, FILE_KEYS = COMMAND_KEYS, FILE_KEY_OPEN = 0, FILE_KEY_SAVE_STATE, FILE_KEY_LOAD_STATE, FILE_KEY_QUICK_LOAD_STATE_1, FILE_KEY_QUICK_LOAD_STATE_2, FILE_KEY_QUICK_LOAD_STATE_3, FILE_KEY_QUICK_LOAD_STATE_4, FILE_KEY_QUICK_LOAD_STATE_5, FILE_KEY_QUICK_LOAD_STATE_6, FILE_KEY_QUICK_LOAD_STATE_7, FILE_KEY_QUICK_LOAD_STATE_8, FILE_KEY_QUICK_LOAD_STATE_9, FILE_KEY_QUICK_LOAD_LAST_STATE, FILE_KEY_QUICK_SAVE_STATE_1, FILE_KEY_QUICK_SAVE_STATE_2, FILE_KEY_QUICK_SAVE_STATE_3, FILE_KEY_QUICK_SAVE_STATE_4, FILE_KEY_QUICK_SAVE_STATE_5, FILE_KEY_QUICK_SAVE_STATE_6, FILE_KEY_QUICK_SAVE_STATE_7, FILE_KEY_QUICK_SAVE_STATE_8, FILE_KEY_QUICK_SAVE_STATE_9, FILE_KEY_QUICK_SAVE_NEXT_STATE, FILE_KEY_SAVE_SCREENSHOT, FILE_KEY_LAUNCHER, FILE_KEY_EXIT, FILE_NUM_KEYS, MACHINE_KEYS = FILE_KEYS + FILE_NUM_KEYS, MACHINE_KEY_POWER = 0, MACHINE_KEY_RESET_SOFT, MACHINE_KEY_RESET_HARD, MACHINE_KEY_PAUSE, MACHINE_KEY_UNLIMITED_SPRITES, MACHINE_KEY_CHANGE_DISK_SIDE, MACHINE_NUM_KEYS, NSF_KEYS = MACHINE_KEYS + MACHINE_NUM_KEYS, NSF_KEY_PLAY = 0, NSF_KEY_STOP, NSF_KEY_NEXT, NSF_KEY_PREV, NSF_NUM_KEYS, VIEW_KEYS = NSF_KEYS + NSF_NUM_KEYS, VIEW_KEY_SCREENSIZE_1X = 0, VIEW_KEY_SCREENSIZE_2X, VIEW_KEY_SCREENSIZE_3X, VIEW_KEY_SCREENSIZE_4X, VIEW_KEY_SCREENSIZE_5X, VIEW_KEY_SCREENSIZE_6X, VIEW_KEY_SCREENSIZE_7X, VIEW_KEY_SCREENSIZE_8X, VIEW_KEY_SCREENSIZE_9X, VIEW_KEY_SCREENSIZE_MAX, VIEW_KEY_SHOW_MENU, VIEW_KEY_SHOW_STATUSBAR, VIEW_KEY_SHOW_ONTOP, VIEW_KEY_SHOW_FPS, VIEW_KEY_FULLSCREEN, VIEW_NUM_KEYS, HELP_KEYS = VIEW_KEYS + VIEW_NUM_KEYS, HELP_KEY_HELP = 0, HELP_NUM_KEYS, NUM_KEYS = HELP_KEYS + HELP_NUM_KEYS, NUM_COMMAND_KEYS = NUM_KEYS - COMMAND_KEYS }; enum { AUTOFIRE_MAX_SPEED = 6, AUTOFIRE_NUM_SPEEDS = 7, AUTOFIRE_DEFAULT_SPEED = 3 }; typedef DirectX::DirectInput::Key Key; private: Settings(); void Reset(const DirectX::DirectInput&); void Reset(const DirectX::DirectInput&,uint); void Clear(); void Clear(uint); #pragma pack(push,1) struct Type { uchar offset; ushort name; }; struct Mapping { inline uint Code() const; inline uint Alt() const; inline uint Shift() const; inline uint Ctrl() const; uchar index; ushort key; ushort dlgName; cstring cfgType; cstring cfgKey; }; #pragma pack(pop) enum { NO_KEY = 0, OFFSET_COUNT = NUM_TYPES + 1, ALT = 0x100, SHIFT = 0x200, CTRL = 0x400 }; bool Map(uint,const Key&); inline void Unmap(uint); static inline const Mapping& GetMapping(uint,uint); static inline const Type& GetType(uint); Key keys[NUM_KEYS]; uint autoFireSpeed; bool allowSimulAxes; static const Type types[OFFSET_COUNT]; static const Mapping map[NUM_KEYS]; static uint NumTypeKeys(uint index) { NST_ASSERT( index < NUM_TYPES ); return types[index+1].offset - types[index].offset; } public: const Key& GetKey(uint type,uint index) const { NST_ASSERT( index < NumTypeKeys(type) ); return keys[types[type].offset + index]; } const Key& GetKey(uint index) const { NST_ASSERT( index < NUM_KEYS ); return keys[index]; } const Key* GetKeys(uint index=0) const { NST_ASSERT( index < NUM_KEYS ); return keys + index; } const Key* GetKeys(uint type,uint index) const { return &GetKey( type, index ); } uint AutoFireSpeed() const { return autoFireSpeed; } bool AllowSimulAxes() const { return allowSimulAxes; } }; private: void SelectNextMapKey(); bool MapSelectedKey(const Settings::Key&); Nes::Input nes; DirectX::DirectInput& directInput; Settings settings; Dialog dialog; public: void Open() { dialog.Open(); } const Settings& GetSettings() const { return settings; } }; } } #endif nestopia-1.51.1/source/win32/NstDialogLanguage.cpp000066400000000000000000000055601411157722000217250ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstWindowParam.hpp" #include "NstDialogLanguage.hpp" namespace Nestopia { namespace Window { struct Language::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; }; const MsgHandler::Entry Language::Handlers::messages[] = { { WM_INITDIALOG, &Language::OnInitDialog } }; const MsgHandler::Entry Language::Handlers::commands[] = { { IDOK, &Language::OnCmdOk }, { IDC_LANGUAGE_LIST, &Language::OnDblClk } }; Language::Language() : dialog(IDD_LANGUAGE,this,Handlers::messages,Handlers::commands) {} Language::~Language() { } ibool Language::OnInitDialog(Param&) { paths.clear(); Application::Instance::GetLanguage().EnumerateResources( paths ); const Control::ListBox listBox( dialog.ListBox(IDC_LANGUAGE_LIST) ); Path name; for (Paths::const_iterator it(paths.begin()), end(paths.end()); it != end; ++it) { name = it->File(); name.Extension().Clear(); ::CharUpperBuff( name.Ptr(), 1 ); const uint index = listBox.Add( name.Ptr() ).GetIndex(); listBox[index].Data() = (it - paths.begin()); if (*it == Application::Instance::GetLanguage().GetResourcePath()) listBox[index].Select(); } return true; } void Language::CloseOk() { const Control::ListBox listBox( dialog.ListBox(IDC_LANGUAGE_LIST) ); if (listBox.AnySelection()) { const uint index = listBox.Selection().Data(); if (paths[index] != Application::Instance::GetLanguage().GetResourcePath()) newPath = paths[index]; } dialog.Close(); } ibool Language::OnCmdOk(Param& param) { if (param.Button().Clicked()) CloseOk(); return true; } ibool Language::OnDblClk(Param& param) { if (HIWORD(param.wParam) == LBN_DBLCLK) { CloseOk(); return true; } return false; } } } nestopia-1.51.1/source/win32/NstDialogLanguage.hpp000066400000000000000000000031361411157722000217270ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIALOG_LANGUAGE_H #define NST_DIALOG_LANGUAGE_H #pragma once #include "NstWindowDialog.hpp" #include "NstApplicationLanguage.hpp" namespace Nestopia { namespace Window { class Language { public: Language(); ~Language(); private: struct Handlers; void CloseOk(); ibool OnInitDialog (Param&); ibool OnCmdOk (Param&); ibool OnDblClk (Param&); typedef Application::Instance::Language::Paths Paths; Dialog dialog; Paths paths; Path newPath; public: const Path& Open() { dialog.Open(); return newPath; } }; } } #endif nestopia-1.51.1/source/win32/NstDialogLauncher.cpp000066400000000000000000000306641411157722000217460ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "resource/resource.h" #include "NstResourceString.hpp" #include "NstResourceIcon.hpp" #include "NstWindowParam.hpp" #include "NstSystemKeyboard.hpp" #include "NstDialogLauncher.hpp" #include "NstDialogInesHeader.hpp" namespace Nestopia { namespace Window { struct Launcher::Handlers { static const MsgHandler::Entry messages[]; static const Menu::CmdHandler::Entry commands[]; static const Control::NotificationHandler::Entry listNotifications[]; static const Control::NotificationHandler::Entry treeNotifications[]; }; const MsgHandler::Entry Launcher::Handlers::messages[] = { { WM_INITDIALOG, &Launcher::OnInitDialog }, { WM_CLOSE, &Launcher::OnClose }, { WM_DESTROY, &Launcher::OnDestroy }, { WM_SIZE, &Launcher::OnSize }, { WM_DROPFILES, &Launcher::OnDropFiles } }; const Menu::CmdHandler::Entry Launcher::Handlers::commands[] = { { IDM_LAUNCHER_FILE_RUN, &Launcher::OnCmdFileRun }, { IDM_LAUNCHER_FILE_EDITHEADER, &Launcher::OnCmdEditHeader }, { IDM_LAUNCHER_FILE_REFRESH, &Launcher::OnCmdFileRefresh }, { IDM_LAUNCHER_VIEW_SHOWGRIDS, &Launcher::OnCmdViewShowGrids }, { IDM_LAUNCHER_VIEW_SHOWDATABASECORRECTED, &Launcher::OnCmdViewShowDatabaseCorrected }, { IDM_LAUNCHER_VIEW_ONTOP, &Launcher::OnCmdViewShowOnTop }, { IDM_LAUNCHER_OPTIONS_COLORS, &Launcher::OnCmdOptionsColors }, { IDM_LAUNCHER_OPTIONS_PATHS, &Launcher::OnCmdOptionsPaths } }; const Control::NotificationHandler::Entry Launcher::Handlers::listNotifications[] = { { LVN_GETDISPINFO, &Launcher::OnListGetDisplayInfo }, { LVN_KEYDOWN, &Launcher::OnListKeyDown }, { LVN_COLUMNCLICK, &Launcher::OnListColumnClick }, { LVN_ITEMACTIVATE, &Launcher::OnListItemActivate }, { LVN_ITEMCHANGED, &Launcher::OnListItemChanged }, { LVN_INSERTITEM, &Launcher::OnListInsertItem }, { LVN_DELETEALLITEMS, &Launcher::OnListDeleteAllItems }, { LVN_DELETEITEM, &Launcher::OnListDeleteItem } }; const Control::NotificationHandler::Entry Launcher::Handlers::treeNotifications[] = { { TVN_SELCHANGING, &Launcher::OnTreeSelectionChanging } }; Launcher::Launcher(const Nes::Cartridge::Database& database,const Managers::Paths& p,const Configuration& cfg) : dialog ( IDD_LAUNCHER, this, Handlers::messages ), menu ( IDR_MENU_LAUNCHER ), listNotifications ( IDC_LAUNCHER_LIST, dialog.Messages() ), treeNotifications ( IDC_LAUNCHER_TREE, dialog.Messages() ), statusBar ( dialog, STATUSBAR_SECOND_FIELD_WIDTH ), list ( dialog, menu.Commands(), p, cfg, database ), colors ( cfg ) { menu.Commands().Add( this, Handlers::commands ); dialog.Commands().Add( CMD_ENTER, this, &Launcher::OnCmdEnter ); listNotifications.Add( this, Handlers::listNotifications ); treeNotifications.Add( this, Handlers::treeNotifications ); { Configuration::ConstSection launcher( cfg["launcher"] ); menu[IDM_LAUNCHER_VIEW_ONTOP].Check( launcher["view"]["show"]["on-top"].Yes() ); Configuration::ConstSection size( launcher["window-size"] ); initialSize.x = size["x"].Int(); initialSize.y = size["y"].Int(); if (!initialSize.x || !initialSize.y) { initialSize.x = 0; initialSize.y = 0; } } HeapString name; for (uint i=0; i < 6; ++i) { static const ushort keys[6][2] = { { IDM_LAUNCHER_FILE_RUN, VK_RETURN }, { IDM_LAUNCHER_FILE_EDITHEADER, VK_F4 }, { IDM_LAUNCHER_FILE_REFRESH, VK_F5 }, { IDM_LAUNCHER_EDIT_FIND, VK_F3 }, { IDM_LAUNCHER_EDIT_INSERT, VK_INSERT }, { IDM_LAUNCHER_EDIT_REMOVE, VK_DELETE } }; menu[keys[i][0]].Text() >> name; menu[keys[i][0]].Text() << (name << '\t' << System::Keyboard::GetName( keys[i][1] )); } } Launcher::~Launcher() { Close(); } void Launcher::Save(Configuration& cfg,bool saveSize,bool saveFiles) { Configuration::Section launcher( cfg["launcher"] ); if (saveSize) { Configuration::Section size( cfg["window-size"] ); size["x"].Int() = initialSize.x; size["y"].Int() = initialSize.y; } launcher["view"]["show"]["on-top"].YesNo() = menu[IDM_LAUNCHER_VIEW_ONTOP].Checked(); list.Save( cfg, saveFiles ); colors.Save( cfg ); } void Launcher::Open(bool child) { menu[IDM_LAUNCHER_VIEW_ONTOP].Enable( !child ); dialog.Open( child ? Dialog::MODELESS_CHILD : Dialog::MODELESS_FREE ); } void Launcher::Close() { dialog.Close(); } void Launcher::Synchronize(HWND hWnd) const { if (dialog.IsOpen() && menu[IDM_LAUNCHER_VIEW_ONTOP].Enabled() && menu[IDM_LAUNCHER_VIEW_ONTOP].Unchecked()) dialog.Position().BringBehind( hWnd ); } ibool Launcher::OnInitDialog(Param&) { menu.Hook( dialog ); menu.Show(); statusBar.Enable(); if (menu[IDM_LAUNCHER_VIEW_ONTOP].Enabled()) dialog.MakeTopMost( menu[IDM_LAUNCHER_VIEW_ONTOP].Checked() ); list = dialog.ListView( IDC_LAUNCHER_LIST ); tree = dialog.TreeView( IDC_LAUNCHER_TREE ); dialog.Send ( WM_SETICON, ICON_SMALL, static_cast(Resource::Icon(Application::Instance::GetIconStyle() == Application::Instance::ICONSTYLE_NES ? IDI_PAD : IDI_PAD_J)) ); margin = dialog.Coordinates().Corner() - list.GetWindow().Coordinates().Corner(); list.SetColors( colors.GetBackgroundColor(), colors.GetForegroundColor() ); tree.SetColors( colors.GetBackgroundColor(), colors.GetForegroundColor() ); menu[ IDM_LAUNCHER_VIEW_SHOWGRIDS ].Check( list.GetStyle() & LVS_EX_GRIDLINES ); menu[ IDM_LAUNCHER_VIEW_SHOWDATABASECORRECTED ].Check( list.DatabaseCorrectionEnabled() ); menu[ IDM_LAUNCHER_FILE_REFRESH ].Enable( list.CanRefresh() ); if (initialSize.x && initialSize.y) dialog.Size() = initialSize; else initialSize = dialog.GetPlacement().Size(); return true; } ibool Launcher::OnClose(Param&) { Close(); return true; } ibool Launcher::OnDestroy(Param&) { tree.Close(); list.Close(); initialSize = dialog.GetPlacement().Size(); return true; } ibool Launcher::OnSize(Param& param) { if (param.wParam != SIZE_MINIMIZED) { const Point corner( dialog.Coordinates().Corner() - margin - list.GetWindow().Position() ); list.GetWindow().Size() = corner; tree.GetWindow().Size() = Point( tree.GetWindow().Coordinates().Width(), corner.y ); } return true; } ibool Launcher::OnCmdEnter(Param&) { OnCmdFileRun(); return true; } ibool Launcher::OnDropFiles(Param& param) { list.Insert( param ); return true; } void Launcher::UpdateItemCount(const uint count) const { if (count == 0 || count == 1) { menu[IDM_LAUNCHER_EDIT_FIND].Enable( count ); menu[IDM_LAUNCHER_EDIT_CLEAR].Enable( count ); } static HeapString form( HeapString() << ' ' << Resource::String(IDS_TEXT_FILES) << ": " ); const uint length = form.Length(); statusBar.Text(StatusBar::SECOND_FIELD) << (form << count).Ptr(); form.ShrinkTo( length ); } void Launcher::OnListGetDisplayInfo(const NMHDR& nmhdr) { list.OnGetDisplayInfo( reinterpret_cast(&nmhdr) ); } void Launcher::OnListKeyDown(const NMHDR& nmhdr) { switch (reinterpret_cast(nmhdr).wVKey) { case VK_INSERT: if (menu[ IDM_LAUNCHER_EDIT_INSERT ].Enabled()) dialog.PostCommand( IDM_LAUNCHER_EDIT_INSERT ); break; case VK_DELETE: if (menu[ IDM_LAUNCHER_EDIT_REMOVE ].Enabled()) dialog.PostCommand( IDM_LAUNCHER_EDIT_REMOVE ); break; case VK_F3: if (menu[ IDM_LAUNCHER_EDIT_FIND ].Enabled()) dialog.PostCommand( IDM_LAUNCHER_EDIT_FIND ); break; case VK_F4: if (menu[ IDM_LAUNCHER_FILE_EDITHEADER ].Enabled()) dialog.PostCommand( IDM_LAUNCHER_FILE_EDITHEADER ); break; case VK_F5: if (menu[ IDM_LAUNCHER_FILE_REFRESH ].Enabled()) dialog.PostCommand( IDM_LAUNCHER_FILE_REFRESH ); break; } } void Launcher::OnListColumnClick(const NMHDR& nmhdr) { Application::Instance::Waiter wait; list.Sort( reinterpret_cast(nmhdr).iSubItem ); } void Launcher::OnListItemActivate(const NMHDR&) { OnCmdFileRun(); } void Launcher::OnListItemChanged(const NMHDR& nmhdr) { const NMLISTVIEW& nmlv = reinterpret_cast(nmhdr); if ((nmlv.uOldState ^ nmlv.uNewState) & LVIS_SELECTED) { if (nmlv.uNewState & LVIS_SELECTED) { if (const List::Files::Entry* const entry = list[nmlv.iItem]) { { Path path( entry->GetPath(list.GetStrings()), entry->GetFile(list.GetStrings()) ); if (path.Length() > MAX_PATH) { path.ShrinkTo( MAX_PATH-3 ); path << "..."; } statusBar.Text(StatusBar::FIRST_FIELD) << path.Ptr(); } menu[IDM_LAUNCHER_FILE_RUN].Enable(); menu[IDM_LAUNCHER_FILE_EDITHEADER].Enable( entry->GetType() == List::Files::Entry::NES ); menu[IDM_LAUNCHER_EDIT_REMOVE].Enable(); } } else { OnNoSelection(); } } } void Launcher::OnListInsertItem(const NMHDR&) { UpdateItemCount( list.Size() ); } void Launcher::OnListDeleteItem(const NMHDR&) { const uint size = list.Size(); UpdateItemCount( size - (size != 0) ); } void Launcher::OnListDeleteAllItems(const NMHDR&) { OnNoSelection(); const uint size = list.Size(); UpdateItemCount( size - (size != 0) ); } void Launcher::OnTreeSelectionChanging(const NMHDR& nmhdr) { Application::Instance::Events::Signal( Application::Instance::EVENT_SYSTEM_BUSY ); list.Draw( tree.GetType(reinterpret_cast(nmhdr).itemNew.hItem) ); } void Launcher::OnNoSelection() const { statusBar.Text(StatusBar::FIRST_FIELD).Clear(); menu[IDM_LAUNCHER_FILE_RUN].Disable(); menu[IDM_LAUNCHER_FILE_EDITHEADER].Disable(); menu[IDM_LAUNCHER_EDIT_REMOVE].Disable(); } void Launcher::OnCmdFileRun(uint) { if (const List::Files::Entry* const entry = list.GetSelection()) Application::Instance::GetMainWindow().Send( Application::Instance::WM_NST_LAUNCH, 0, Path(entry->GetPath(list.GetStrings()),entry->GetFile(list.GetStrings())).Ptr() ); } void Launcher::OnCmdFileRefresh(uint) { list.Refresh(); } void Launcher::OnCmdEditHeader(uint) { if (const List::Files::Entry* const entry = list.GetSelection()) Window::InesHeader( list.GetPaths() ).Open( Path(entry->GetPath(list.GetStrings()),entry->GetFile(list.GetStrings())) ); } void Launcher::OnCmdViewShowGrids(uint) { menu[IDM_LAUNCHER_VIEW_SHOWGRIDS].Check( list.ToggleGrids() ); } void Launcher::OnCmdViewShowDatabaseCorrected(uint) { menu[IDM_LAUNCHER_VIEW_SHOWDATABASECORRECTED].Check( list.ToggleDatabase() ); } void Launcher::OnCmdViewShowOnTop(uint) { dialog.MakeTopMost( menu[IDM_LAUNCHER_VIEW_ONTOP].ToggleCheck() ); } void Launcher::OnCmdOptionsPaths(uint) { list.OpenPathDialog(); menu[IDM_LAUNCHER_FILE_REFRESH].Enable( list.CanRefresh() ); } void Launcher::OnCmdOptionsColors(uint) { colors.Open(); list.SetColors( colors.GetBackgroundColor(), colors.GetForegroundColor(), List::REPAINT ); tree.SetColors( colors.GetBackgroundColor(), colors.GetForegroundColor(), Tree::REPAINT ); } } } nestopia-1.51.1/source/win32/NstDialogLauncher.hpp000066400000000000000000000367311411157722000217540ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIALOG_LAUNCHER_H #define NST_DIALOG_LAUNCHER_H #pragma once #include #include #include "NstCollectionBitSet.hpp" #include "NstWindowMenu.hpp" #include "NstWindowStatusBar.hpp" #include "NstWindowDialog.hpp" #include "NstDialogFind.hpp" #include "../core/api/NstApiCartridge.hpp" #include namespace Nes { using namespace Api; } namespace Nestopia { namespace Io { class File; } namespace Managers { class Paths; } namespace Window { class Launcher { public: Launcher(const Nes::Cartridge::Database&,const Managers::Paths&,const Configuration&); ~Launcher(); void Save(Configuration&,bool,bool); void Open(bool); void Synchronize(HWND) const; void Close(); private: struct Handlers; enum { STATUSBAR_SECOND_FIELD_WIDTH = 14, CMD_ENTER = 1 }; void UpdateItemCount(uint) const; void OnNoSelection() const; ibool OnInitDialog (Param&); ibool OnDropFiles (Param&); ibool OnSize (Param&); ibool OnCmdEnter (Param&); ibool OnClose (Param&); ibool OnDestroy (Param&); void OnCmdFileRun (uint=0); void OnCmdFileRefresh (uint); void OnCmdEditHeader (uint); void OnCmdViewShowGrids (uint); void OnCmdViewShowDatabaseCorrected (uint); void OnCmdViewShowOnTop (uint); void OnCmdOptionsPaths (uint); void OnCmdOptionsColors (uint); void OnListGetDisplayInfo (const NMHDR&); void OnListKeyDown (const NMHDR&); void OnListColumnClick (const NMHDR&); void OnListItemActivate (const NMHDR&); void OnListItemChanged (const NMHDR&); void OnListInsertItem (const NMHDR&); void OnListDeleteItem (const NMHDR&); void OnListDeleteAllItems (const NMHDR&); void OnTreeSelectionChanging (const NMHDR&); class List { public: List ( Dialog&, Menu::CmdHandler&, const Managers::Paths&, const Configuration&, const Nes::Cartridge::Database& ); ~List(); void operator = (const Control::ListView&); enum Updater { DONT_REPAINT, REPAINT }; void Add(wcstring); void Close(); void Save(Configuration&,bool); void Sort(uint=0); bool CanRefresh() const; void Refresh(); void Insert(const Param&); void SetColors(uint,uint,Updater=DONT_REPAINT) const; void OnGetDisplayInfo(LPARAM); class Paths { public: explicit Paths(const Configuration&); void Save(Configuration&) const; struct Settings { struct Folder { Path path; bool incSubDir; }; typedef std::vector Folders; struct Include : Collection::BitSet { enum { NES,UNF,XML,FDS,NSF,PATCH,ARCHIVE,ANY,UNIQUE }; enum { TYPES = NES|UNF|XML|FDS|NSF|PATCH, FILES = TYPES|ARCHIVE }; explicit Include(bool a=false) : Collection::BitSet( (0xFF^0x40) | uint(a) << 6 ) {} }; Include include; Folders folders; }; private: struct Handlers; enum { LIMIT = 999 }; ibool OnInitDialog (Param&); ibool OnCmdAdd (Param&); ibool OnCmdRemove (Param&); ibool OnCmdClear (Param&); ibool OnCmdOk (Param&); void OnKeyDown (const NMHDR&); void OnItemChanged (const NMHDR&); void OnInsertItem (const NMHDR&); void OnDeleteItem (const NMHDR&); Settings settings; Dialog dialog; const Control::NotificationHandler notifications; public: void Open() { dialog.Open(); } const Settings& GetSettings() const { return settings; } }; class Files { class Inserter; class Searcher; public: class Strings { HeapString container; public: explicit Strings(uint=0); typedef uint Index; enum { NONE = -1 }; int Find(GenericString) const; void Clear(); template Index operator << (const T& t) { uint pos = container.Length(); container << t << '\0'; return pos; } Index Import(cstring t) { uint pos = container.Length(); container.Import( t ); container << '\0'; return pos; } wcstring operator [] (uint i) const { return container.Ptr() + i; } uint Size() const { return container.Length() * (container.Wide() ? 2 : 1); } }; Files(); void Load(); void Save(); void Refresh(const Paths::Settings&,const Nes::Cartridge::Database&); bool Insert(const Nes::Cartridge::Database&,GenericString); void Clear(); bool ShouldDefrag() const; void Defrag(); class Entry { friend class Files; friend class Inserter; friend class Searcher; public: typedef Nes::Cartridge::Database Db; enum Type { NES = 0x01, UNF = 0x02, XML = 0x04, FDS = 0x08, NSF = 0x10, PATCH = 0x20, ARCHIVE = 0x80, ALL = NES|UNF|XML|FDS|NSF|PATCH }; enum { SYSTEM_UNKNOWN, SYSTEM_PC10, SYSTEM_VS, SYSTEM_PAL, SYSTEM_NTSC, SYSTEM_NTSC_PAL }; uint GetSystem(const Db*) const; private: explicit Entry(uint=0); Db::Entry SearchDb(const Db*) const; enum { ATR_BATTERY = 0x08, ATR_PC10 = 0x10, ATR_VS = 0x20, ATR_PAL = 0x40, ATR_NTSC = 0x80, ATR_NTSC_PAL = ATR_PAL|ATR_NTSC, ATR_DEFAULT_FDS = ATR_NTSC }; Strings::Index file; Strings::Index path; Strings::Index name; typedef Nes::Cartridge::Profile::Hash Hash; Hash hash; ushort pRom; ushort cRom; ushort wRam; ushort vRam; ushort mapper; uchar type; uchar attributes; public: uint GetType() const { return type; } wcstring GetPath(const Strings& strings) const { return strings[path]; } wcstring GetFile(const Strings& strings) const { return strings[file]; } wcstring GetName(const Strings& strings,const Db* db) const { if (const Db::Entry entry = SearchDb( db )) { wcstring title = entry.GetTitle(); if (*title) return title; } return name ? strings[name] : L"-"; } uint GetPRom(const Db* db=NULL) const { if (const Db::Entry entry = SearchDb( db )) return entry.GetPrgRom() / Nes::Core::SIZE_1K; else return pRom; } uint GetCRom(const Db* db=NULL) const { if (const Db::Entry entry = SearchDb( db )) return entry.GetChrRom() / Nes::Core::SIZE_1K; else return cRom; } uint GetWRam(const Db* db=NULL) const { if (const Db::Entry entry = SearchDb( db )) return entry.GetWram() / Nes::Core::SIZE_1K; else return wRam; } uint GetVRam(const Db* db=NULL) const { if (const Db::Entry entry = SearchDb( db )) return entry.GetVram() / Nes::Core::SIZE_1K; else return vRam; } bool GetBattery(const Db* db=NULL) const { if (const Db::Entry entry = SearchDb( db )) return entry.HasBattery(); else return (attributes & ATR_BATTERY); } uint GetMapper(const Db* db=NULL) const { if (const Db::Entry entry = SearchDb( db )) return entry.GetMapper(); else return mapper; } Nes::Cartridge::Profile::Dump::State GetDump(const Db* db=NULL) const { if (const Db::Entry entry = SearchDb( db )) return entry.GetDumpState(); else return Nes::Cartridge::Profile::Dump::UNKNOWN; } }; typedef Collection::Vector Entries; private: enum Exception { ERR_CORRUPT_DATA }; enum { MAX_ENTRIES = 0xFFFFF, GARBAGE_THRESHOLD = 127 }; ushort dirty; ushort loaded; Strings strings; Entries entries; public: uint Count() const { return entries.Size(); } const Entry& operator [] (uint i) const { return entries[i]; } void Disable(Entry* entry) { if (entry->type) { entry->type = 0; dirty = true; } } const Strings& GetStrings() const { return strings; } }; class Columns { public: explicit Columns(const Configuration&); void Update(const uchar*); void Save(Configuration&) const; enum Type { TYPE_FILE, TYPE_SYSTEM, TYPE_MAPPER, TYPE_PROM, TYPE_CROM, TYPE_WRAM, TYPE_VRAM, TYPE_BATTERY, TYPE_DUMP, TYPE_NAME, TYPE_FOLDER, NUM_TYPES, NUM_DEFAULT_SELECTED_TYPES = 9, NUM_DEFAULT_AVAILABLE_TYPES = NUM_TYPES - NUM_DEFAULT_SELECTED_TYPES }; private: struct Handlers; void Reset(); void Add(uint,uint); void UpdateButtonRemove(); void UpdateButtonAdd(); ibool OnInitDialog (Param&); ibool OnCmdSelected (Param&); ibool OnCmdAvailable (Param&); ibool OnCmdAdd (Param&); ibool OnCmdRemove (Param&); ibool OnCmdDefault (Param&); ibool OnCmdOk (Param&); typedef Collection::Vector Types; Types available; Types selected; Dialog dialog; static wcstring const cfgStrings[NUM_TYPES]; public: uint Count() const { return selected.Size(); } Type GetType(uint i) const { return Type(selected[i]); } uint GetStringId(uint i) const { return IDS_LAUNCHER_COLUMN_FILE + selected[i]; } void Open() { dialog.Open(); } }; private: class Strings { public: wcstring GetMapper(uint); wcstring GetSize(uint); void Flush(); private: struct ValueString { wchar_t string[5]; }; typedef String::Stack<10+1> SizeString; typedef std::map Sizes; typedef Collection::Vector Mappers; Sizes sizes; Mappers mappers; }; enum { STYLE = ( LVS_EX_FULLROWSELECT | LVS_EX_TWOCLICKACTIVATE | LVS_EX_HEADERDRAGDROP ) }; void ReloadListColumns() const; void UpdateColumnOrder(); void UpdateSortColumnOrder(uint); void Redraw(); int Sorter(const void*,const void*); void OnFind(GenericString,uint); bool Optimize(); void OnCmdEditFind (uint); void OnCmdEditInsert (uint); void OnCmdEditDelete (uint); void OnCmdEditClear (uint); void OnCmdViewAlignColumns (uint); void OnCmdOptionsColumns (uint); Control::ListView ctrl; const Nes::Cartridge::Database imageDatabase; const Nes::Cartridge::Database* useImageDatabase; uchar order[Columns::NUM_TYPES]; uint typeFilter; uint style; Finder finder; Paths paths; Files files; Columns columns; Strings strings; const Managers::Paths& pathManager; public: Generic GetWindow() const { return ctrl.GetWindow(); } void OpenPathDialog() { paths.Open(); } void Draw(uint type) { typeFilter = type; Redraw(); } bool DatabaseCorrectionEnabled() const { return useImageDatabase; } bool ToggleDatabase() { useImageDatabase = (useImageDatabase ? NULL : &imageDatabase); ctrl.Redraw(); return useImageDatabase; } bool ToggleGrids() { style ^= LVS_EX_GRIDLINES; ctrl.StyleEx() = style; return style & LVS_EX_GRIDLINES; } bool HitTest(const Point& point) const { return ctrl.HitTest( point.x, point.y ); } uint GetStyle() const { return ctrl.StyleEx(); } HWND GetHandle() const { return ctrl.GetHandle(); } uint NumPaths() const { return paths.GetSettings().folders.size(); } uint Size() const { return ctrl.Size(); } const Files::Entry* operator [] (uint i) const { return static_cast(static_cast( ctrl[i].Data() )); } const Files::Entry* GetSelection() const { int index = ctrl.Selection().GetIndex(); return index >= 0 ? (*this)[index] : NULL; } const Files::Strings& GetStrings() const { return files.GetStrings(); } const Managers::Paths& GetPaths() const { return pathManager; } }; class Tree { public: Tree(); void operator = (const Control::TreeView&); enum Updater {DONT_REPAINT,REPAINT}; void SetColors(uint,uint,Updater=DONT_REPAINT) const; uint GetType(HTREEITEM) const; void Close(); private: Control::TreeView ctrl; uint selection; const Control::TreeView::ImageList imageList; public: Generic GetWindow() const { return ctrl.GetWindow(); } }; class Colors { public: explicit Colors(const Configuration&); void Save(Configuration&) const; private: struct Handlers; enum { DEF_BACKGROUND_COLOR = RGB(0xFF,0xFF,0xFF), DEF_FOREGROUND_COLOR = RGB(0x00,0x00,0x00) }; struct Type { inline Type(int,int,int,int); COLORREF color; const Rect rect; }; void UpdateColor(const Type&) const; void UpdateColors() const; void ChangeColor(COLORREF&); ibool OnInitDialog (Param&); ibool OnPaint (Param&); ibool OnCmdChangeBackground (Param&); ibool OnCmdChangeForeground (Param&); ibool OnCmdDefault (Param&); Type background; Type foreground; COLORREF customColors[16]; Dialog dialog; public: COLORREF GetBackgroundColor() const { return background.color; } COLORREF GetForegroundColor() const { return foreground.color; } void Open() { dialog.Open(); } }; Dialog dialog; Menu menu; Control::NotificationHandler listNotifications; Control::NotificationHandler treeNotifications; StatusBar statusBar; Tree tree; List list; Point margin; Colors colors; Point initialSize; }; } } #endif nestopia-1.51.1/source/win32/NstDialogLauncherColors.cpp000066400000000000000000000103041411157722000231150ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstDialogLauncher.hpp" #include namespace Nestopia { namespace Window { inline Launcher::Colors::Type::Type(int l,int t,int r,int b) : rect(l,t,r,b) {} struct Launcher::Colors::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; }; const MsgHandler::Entry Launcher::Colors::Handlers::messages[] = { { WM_INITDIALOG, &Colors::OnInitDialog }, { WM_PAINT, &Colors::OnPaint } }; const MsgHandler::Entry Launcher::Colors::Handlers::commands[] = { { IDC_LAUNCHER_COLORS_BG_CHANGE, &Colors::OnCmdChangeBackground }, { IDC_LAUNCHER_COLORS_FG_CHANGE, &Colors::OnCmdChangeForeground }, { IDC_LAUNCHER_COLORS_DEFAULT, &Colors::OnCmdDefault } }; Launcher::Colors::Colors(const Configuration& cfg) : background (20,94,74,114), foreground (20,33,74,53), dialog (IDD_LAUNCHER_COLORS,this,Handlers::messages,Handlers::commands) { Configuration::ConstSection color( cfg["launcher"]["view"]["colors"] ); background.color = color["background"].Int( DEF_BACKGROUND_COLOR ); foreground.color = color["foreground"].Int( DEF_FOREGROUND_COLOR ); } void Launcher::Colors::Save(Configuration& cfg) const { Configuration::Section color( cfg["launcher"]["view"]["colors"] ); color[ "foreground" ].Str() = HexString( 32, foreground.color ); color[ "background" ].Str() = HexString( 32, background.color ); } void Launcher::Colors::UpdateColor(const Type& type) const { if (HDC const hDC = ::GetDC( dialog )) { HPEN const hPen = ::CreatePen( PS_SOLID, 1, RGB(0x00,0x00,0x00) ); HPEN const hPenOld = static_cast(::SelectObject( hDC, hPen )); HBRUSH const hBrush = ::CreateSolidBrush( type.color ); HBRUSH const hBrushOld = static_cast(::SelectObject( hDC, hBrush )); ::Rectangle( hDC, type.rect.left, type.rect.top, type.rect.right, type.rect.bottom ); ::SelectObject( hDC, hBrushOld ); ::DeleteObject( hBrush ); ::SelectObject( hDC, hPenOld ); ::DeleteObject( hPen ); ::ReleaseDC( dialog, hDC ); } } void Launcher::Colors::ChangeColor(COLORREF& color) { Object::Pod cc; cc.lStructSize = sizeof(cc); cc.hwndOwner = dialog; cc.lpCustColors = customColors; cc.rgbResult = color; cc.Flags = CC_FULLOPEN|CC_RGBINIT; if (::ChooseColor( &cc )) color = cc.rgbResult; } void Launcher::Colors::UpdateColors() const { UpdateColor( background ); UpdateColor( foreground ); } ibool Launcher::Colors::OnInitDialog(Param&) { UpdateColors(); return true; } ibool Launcher::Colors::OnPaint(Param&) { UpdateColors(); return false; } ibool Launcher::Colors::OnCmdChangeBackground(Param&) { ChangeColor( background.color ); UpdateColor( background ); return true; } ibool Launcher::Colors::OnCmdChangeForeground(Param&) { ChangeColor( foreground.color ); UpdateColor( foreground ); return true; } ibool Launcher::Colors::OnCmdDefault(Param&) { background.color = DEF_BACKGROUND_COLOR; foreground.color = DEF_FOREGROUND_COLOR; UpdateColors(); return true; } } } nestopia-1.51.1/source/win32/NstDialogLauncherColumns.cpp000066400000000000000000000203351411157722000233010ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstResourceString.hpp" #include "NstWindowParam.hpp" #include "NstDialogLauncher.hpp" namespace Nestopia { namespace Window { NST_COMPILE_ASSERT ( IDS_LAUNCHER_COLUMN_SYSTEM == IDS_LAUNCHER_COLUMN_FILE + 1 && IDS_LAUNCHER_COLUMN_MAPPER == IDS_LAUNCHER_COLUMN_FILE + 2 && IDS_LAUNCHER_COLUMN_PRG == IDS_LAUNCHER_COLUMN_FILE + 3 && IDS_LAUNCHER_COLUMN_CHR == IDS_LAUNCHER_COLUMN_FILE + 4 && IDS_LAUNCHER_COLUMN_WRAM == IDS_LAUNCHER_COLUMN_FILE + 5 && IDS_LAUNCHER_COLUMN_VRAM == IDS_LAUNCHER_COLUMN_FILE + 6 && IDS_LAUNCHER_COLUMN_BATTERY == IDS_LAUNCHER_COLUMN_FILE + 7 && IDS_LAUNCHER_COLUMN_DUMP == IDS_LAUNCHER_COLUMN_FILE + 8 && IDS_LAUNCHER_COLUMN_NAME == IDS_LAUNCHER_COLUMN_FILE + 9 && IDS_LAUNCHER_COLUMN_FOLDER == IDS_LAUNCHER_COLUMN_FILE + 10 ); wcstring const Launcher::List::Columns::cfgStrings[NUM_TYPES] = { L"file", L"system", L"mapper", L"prg", L"chr", L"wram", L"vram", L"battery", L"dump", L"name", L"folder" }; struct Launcher::List::Columns::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; }; const MsgHandler::Entry Launcher::List::Columns::Handlers::messages[] = { { WM_INITDIALOG, &Columns::OnInitDialog } }; const MsgHandler::Entry Launcher::List::Columns::Handlers::commands[] = { { IDC_LAUNCHER_COLUMNSELECT_SELECTED, &Columns::OnCmdSelected }, { IDC_LAUNCHER_COLUMNSELECT_AVAILABLE, &Columns::OnCmdAvailable }, { IDC_LAUNCHER_COLUMNSELECT_ADD, &Columns::OnCmdAdd }, { IDC_LAUNCHER_COLUMNSELECT_REMOVE, &Columns::OnCmdRemove }, { IDC_LAUNCHER_COLUMNSELECT_DEFAULT, &Columns::OnCmdDefault }, { IDOK, &Columns::OnCmdOk } }; Launcher::List::Columns::Columns(const Configuration& cfg) : available (NUM_TYPES), dialog (IDD_LAUNCHER_COLUMNS,this,Handlers::messages,Handlers::commands) { Configuration::ConstSection column( cfg["launcher"]["view"]["columns"]["column"] ); for (uint i=0; i < NUM_TYPES; ++i) available[i] = i; selected.Reserve( NUM_TYPES ); for (uint i=0; i < NUM_TYPES; ++i) { const GenericString string( column[i].Str() ); if (string.Empty()) break; for (Types::Iterator it(available.Begin()), end(available.End()); it != end; ++it) { if (string == cfgStrings[*it]) { selected.PushBack( *it ); available.Erase( it ); break; } } } if (selected.Empty()) Reset(); } void Launcher::List::Columns::Reset() { selected.Resize( NUM_DEFAULT_SELECTED_TYPES ); available.Resize( NUM_DEFAULT_AVAILABLE_TYPES ); for (uint i=0; i < NUM_DEFAULT_SELECTED_TYPES; ++i) selected[i] = i; for (uint i=0; i < NUM_DEFAULT_AVAILABLE_TYPES; ++i) available[i] = NUM_DEFAULT_SELECTED_TYPES + i; } void Launcher::List::Columns::Update(const uchar* const order) { selected.Assign( order, selected.Size() ); } void Launcher::List::Columns::Save(Configuration& cfg) const { if (const uint n=selected.Size()) { Configuration::Section column( cfg["launcher"]["view"]["columns"]["column"] ); for (uint i=0; i < n; ++i) column[i].Str() = cfgStrings[selected[i]]; } } void Launcher::List::Columns::UpdateButtonRemove() { const Control::ListBox list( dialog.ListBox(IDC_LAUNCHER_COLUMNSELECT_SELECTED) ); dialog.Control(IDC_LAUNCHER_COLUMNSELECT_REMOVE).Enable ( list.Size() > 1 && list.Selection() ); } void Launcher::List::Columns::UpdateButtonAdd() { dialog.Control(IDC_LAUNCHER_COLUMNSELECT_ADD).Enable ( dialog.ListBox(IDC_LAUNCHER_COLUMNSELECT_AVAILABLE).Selection() ); } ibool Launcher::List::Columns::OnInitDialog(Param&) { Control::ListBox list( dialog.ListBox(IDC_LAUNCHER_COLUMNSELECT_SELECTED) ); list.Reserve( selected.Size() ); for (Types::ConstIterator it(selected.Begin()), end(selected.End()); it != end; ++it) list.Add( Resource::String( IDS_LAUNCHER_COLUMN_FILE + *it ) ); list[0].Select(); list = dialog.ListBox(IDC_LAUNCHER_COLUMNSELECT_AVAILABLE); list.Reserve( available.Size() ); for (Types::ConstIterator it(available.Begin()), end(available.End()); it != end; ++it) list.Add( Resource::String( IDS_LAUNCHER_COLUMN_FILE + *it ) ); list[0].Select(); return true; } ibool Launcher::List::Columns::OnCmdSelected(Param& param) { if (param.ListBox().SelectionChanged()) UpdateButtonRemove(); return true; } ibool Launcher::List::Columns::OnCmdAvailable(Param& param) { if (param.ListBox().SelectionChanged()) UpdateButtonAdd(); return true; } ibool Launcher::List::Columns::OnCmdAdd(Param& param) { if (param.Button().Clicked()) Add( IDC_LAUNCHER_COLUMNSELECT_SELECTED, IDC_LAUNCHER_COLUMNSELECT_AVAILABLE ); return true; } ibool Launcher::List::Columns::OnCmdRemove(Param& param) { if (param.Button().Clicked()) Add( IDC_LAUNCHER_COLUMNSELECT_AVAILABLE, IDC_LAUNCHER_COLUMNSELECT_SELECTED ); return true; } ibool Launcher::List::Columns::OnCmdDefault(Param& param) { if (param.Button().Clicked()) { Control::ListBox list( dialog.ListBox(IDC_LAUNCHER_COLUMNSELECT_SELECTED) ); list.Clear(); for (uint i=0; i < NUM_DEFAULT_SELECTED_TYPES; ++i) list.Add( Resource::String( IDS_LAUNCHER_COLUMN_FILE + i) ); list[0].Select(); list = dialog.ListBox(IDC_LAUNCHER_COLUMNSELECT_AVAILABLE); list.Clear(); for (uint i=0; i < NUM_DEFAULT_AVAILABLE_TYPES; ++i) list.Add( Resource::String( IDS_LAUNCHER_COLUMN_FILE + NUM_DEFAULT_SELECTED_TYPES + i) ); list[0].Select(); dialog.Control( IDC_LAUNCHER_COLUMNSELECT_REMOVE ).Enable(); dialog.Control( IDC_LAUNCHER_COLUMNSELECT_ADD ).Enable(); } return true; } ibool Launcher::List::Columns::OnCmdOk(Param& param) { if (param.Button().Clicked()) { HeapString text; for (uint i=0; i < 2; ++i) { Control::ListBox list = dialog.ListBox ( i ? IDC_LAUNCHER_COLUMNSELECT_SELECTED : IDC_LAUNCHER_COLUMNSELECT_AVAILABLE ); Types& types = (i ? selected : available); types.Resize( list.Size() ); for (uint j=0; j < types.Size(); ++j) { list[j].Text() >> text; for (uint k=0; k < NUM_TYPES; ++k) { if (text == Resource::String( IDS_LAUNCHER_COLUMN_FILE + k)) { types[j] = k; break; } } } } dialog.Close(); } return true; } void Launcher::List::Columns::Add(const uint iDst,const uint iSrc) { const Control::ListBox cSrc( dialog.ListBox(iSrc) ); const int sSrc = cSrc.Selection().GetIndex(); if (sSrc >= 0 && (iDst == IDC_LAUNCHER_COLUMNSELECT_SELECTED || cSrc.Size() > 1)) { HeapString text; cSrc[sSrc].Text() >> text; const Control::ListBox cDst( dialog.ListBox(iDst) ); const int sDst = cDst.Selection().GetIndex(); if (sDst >= 0) cDst.Insert( sDst + 1, text.Ptr() ).Select(); else cDst.Add( text.Ptr() ); cSrc[sSrc].Remove(); if (cSrc.Size() > sSrc) cSrc[sSrc].Select(); UpdateButtonRemove(); UpdateButtonAdd(); } } } } nestopia-1.51.1/source/win32/NstDialogLauncherFileTable.cpp000066400000000000000000000033421411157722000235070ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstIoFile.hpp" #include "NstDialogLauncher.hpp" namespace Nestopia { namespace Window { Launcher::List::Files::Strings::Strings(const uint reserve) { container.Reserve( 2 + reserve ); container.Assign( L"-\0", 2 ); } int Launcher::List::Files::Strings::Find(const GenericString needle) const { wcstring it = container.Ptr(); wcstring const end = it + container.Length(); NST_ASSERT( *(end-1) == '\0' ); do { const GenericString string( it ); if (needle == string) return it - container.Ptr(); it += string.Length() + 1; } while (it != end); return -1; } void Launcher::List::Files::Strings::Clear() { container.ShrinkTo( 2 ); container.Defrag(); } } } nestopia-1.51.1/source/win32/NstDialogLauncherFiles.cpp000066400000000000000000000751131411157722000227270ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include "NstWindowUser.hpp" #include "NstIoFile.hpp" #include "NstIoArchive.hpp" #include "NstIoStream.hpp" #include "NstSystemThread.hpp" #include "NstIoLog.hpp" #include "NstManagerPaths.hpp" #include "NstDialogLauncher.hpp" #include "../core/NstCrc32.hpp" #include "../core/NstChecksum.hpp" #include "../core/NstXml.hpp" namespace Nestopia { namespace Window { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("t", on) #endif Launcher::List::Files::Entry::Entry(uint t) : file (0), path (0), name (0), pRom (0), cRom (0), wRam (0), vRam (0), mapper (0), type (t), attributes (0) {} class Launcher::List::Files::Inserter { public: typedef Paths::Settings Settings; typedef Settings::Include Include; Inserter ( Strings&, Entries&, const Include, const Nes::Cartridge::Database& ); bool Add(const GenericString); protected: void ReadFile(wcstring const,const Dialog&); enum Stop { STOP_SEARCH }; enum { PATH_NOT_ADDED }; const Include include; uint compressed; struct { Path string; bool incSubDir; uint reference; } path; Strings strings; Entries entries; Strings& saveStrings; Entries& saveEntries; private: enum Type { TYPE_INVALID, TYPE_PROCESSED }; typedef std::set FileChecksums; typedef Collection::Buffer Buffer; typedef Type (Inserter::*Parser)(); Parser GetParser() const; inline uint Crc(const uint,const uint) const; bool UniqueFile(); bool PrepareFile(const uint=1,const uint=0); Type ParseAny(); Type ParseXml(); Type ParseNes(); Type ParseUnf(); Type ParseFds(); Type ParseNsf(); Type ParsePatch(); Type ParseArchive(); void AddEntry(uint,const Nes::Cartridge::Profile&); void AddEntry(const Entry&); Buffer buffer; FileChecksums parsedFiles; const Nes::Cartridge::Database& imageDatabase; }; Launcher::List::Files::Inserter::Inserter ( Strings& v, Entries& e, const Include i, const Nes::Cartridge::Database& r ) : include ( i ), saveStrings ( v ), saveEntries ( e ), imageDatabase ( r ) {} Launcher::List::Files::Inserter::Parser Launcher::List::Files::Inserter::GetParser() const { if (const uint extension = path.string.Extension().Id()) { if (include[Include::ANY]) { if (extension == FourCC<'x','m','l'>::V) { return include[Include::XML] ? &Inserter::ParseXml : NULL; } else { return &Inserter::ParseAny; } } else { switch (extension) { case FourCC<'n','e','s'>::V: return include[Include::NES] ? &Inserter::ParseNes : NULL; case FourCC<'u','n','f'>::V: case FourCC<'u','n','i','f'>::V: return include[Include::UNF] ? &Inserter::ParseUnf : NULL; case FourCC<'x','m','l'>::V: return include[Include::XML] ? &Inserter::ParseXml : NULL; case FourCC<'f','d','s'>::V: return include[Include::FDS] ? &Inserter::ParseFds : NULL; case FourCC<'n','s','f'>::V: return include[Include::NSF] ? &Inserter::ParseNsf : NULL; case FourCC<'i','p','s'>::V: case FourCC<'u','p','s'>::V: return include[Include::PATCH] ? &Inserter::ParsePatch : NULL; case FourCC<'z','i','p'>::V: case FourCC<'r','a','r'>::V: case FourCC<'7','z'>::V: return include[Include::ARCHIVE] ? &Inserter::ParseArchive : NULL; } } } else if (include[Include::ANY]) { return &Inserter::ParseAny; } return NULL; } void Launcher::List::Files::Inserter::AddEntry(const Entry& entry) { entries.PushBack( entry ); Entry& back = entries.Back(); back.file = (strings << path.string.File()); if (path.reference == PATH_NOT_ADDED) path.reference = (strings << path.string.Directory()); NST_VERIFY( path.string.Directory() == strings[path.reference] ); back.path = path.reference; if (entries.Size() == MAX_ENTRIES) throw STOP_SEARCH; } bool Launcher::List::Files::Inserter::Add(const GenericString fileName) { NST_ASSERT( fileName.Length() && fileName.Length() <= MAX_PATH ); if (entries.Size() == MAX_ENTRIES) return false; compressed = 0; path.string = fileName; strings = saveStrings; { const int index = strings.Find( path.string.Directory() ); if (index != Strings::NONE) path.reference = index; else path.reference = PATH_NOT_ADDED; } if (Parser const parser = GetParser()) { try { (*this.*parser)(); } catch (Io::File::Exception) { return false; } catch (Stop) { // reached file count limit } if (entries.Size()) { saveEntries.PushBack( entries ); saveStrings = strings; return true; } } return false; } void Launcher::List::Files::Inserter::ReadFile(wcstring const fileName,const Dialog& dialog) { path.string.File() = fileName; if (Parser const parser = GetParser()) { if (dialog) dialog.Control( IDC_LAUNCHER_FILESEARCH_FILE ).Text() << path.string.Ptr(); compressed = 0; buffer.Clear(); try { (*this.*parser)(); } catch (Io::File::Exception) { // file I/O failure, just skip it } } path.string.File().Clear(); } inline uint Launcher::List::Files::Inserter::Crc(const uint start,const uint length) const { NST_ASSERT( buffer.Size() ); return Nes::Core::Crc32::Compute( reinterpret_cast(&buffer[start]), length ); } bool Launcher::List::Files::Inserter::UniqueFile() { NST_ASSERT( buffer.Size() ); return !include[Include::UNIQUE] || parsedFiles.insert(Crc(0,buffer.Size())).second; } bool Launcher::List::Files::Inserter::PrepareFile(const uint minSize,const uint fileId) { NST_ASSERT( path.string.Length() && minSize && minSize >= bool(fileId) * 4U ); if (buffer.Empty()) { const Io::File file( path.string, Io::File::COLLECT ); const uint size = file.Size(); if (size >= minSize && (!fileId || fileId == file.Peek32())) { buffer.Resize( size ); file.Read( buffer.Ptr(), size ); return true; } return false; } return ( buffer.Size() >= minSize && (!fileId || fileId == FourCC<>::T( buffer.Ptr() )) ); } void Launcher::List::Files::Inserter::AddEntry(const uint flags,const Nes::Cartridge::Profile& profile) { Entry entry( flags ); if (!profile.game.title.empty()) entry.name = strings << profile.game.title.c_str(); entry.pRom = profile.board.GetPrg() / Nes::Core::SIZE_1K; entry.cRom = profile.board.GetChr() / Nes::Core::SIZE_1K; entry.wRam = profile.board.GetWram() / Nes::Core::SIZE_1K; entry.vRam = profile.board.GetVram() / Nes::Core::SIZE_1K; if (profile.board.mapper != Nes::Cartridge::Profile::Board::NO_MAPPER) entry.mapper = profile.board.mapper; if (profile.board.HasBattery()) entry.attributes |= Entry::ATR_BATTERY; if (profile.multiRegion) { entry.attributes |= Entry::ATR_NTSC_PAL; } else switch (profile.system.type) { case Nes::Cartridge::Profile::System::NES_PAL: case Nes::Cartridge::Profile::System::NES_PAL_A: case Nes::Cartridge::Profile::System::NES_PAL_B: case Nes::Cartridge::Profile::System::DENDY: entry.attributes |= Entry::ATR_PAL; break; default: entry.attributes |= Entry::ATR_NTSC; break; } entry.hash = profile.hash; AddEntry( entry ); } Launcher::List::Files::Inserter::Type Launcher::List::Files::Inserter::ParseNes() { if (PrepareFile( 16, Managers::Paths::File::ID_INES )) { if (UniqueFile()) { Io::Stream::In stream( buffer ); Nes::Cartridge::Profile profile; Nes::Cartridge::ReadInes( stream, Nes::Machine::FAVORED_NES_NTSC, profile ); if (!imageDatabase.FindEntry( profile.hash, Nes::Machine::FAVORED_NES_NTSC )) { uint length = buffer.Size(); if (length >= 16+Nes::Core::SIZE_8K) { length -= 16; if (length > Nes::Cartridge::NesHeader::MAX_PRG_ROM + Nes::Cartridge::NesHeader::MAX_CHR_ROM) length = Nes::Cartridge::NesHeader::MAX_PRG_ROM + Nes::Cartridge::NesHeader::MAX_CHR_ROM; else length -= length % Nes::Core::SIZE_8K; if (length != profile.board.GetPrg() + profile.board.GetChr()) { Nes::Cartridge::Profile::Hash hash; hash.Compute( buffer.At(16), length ); if (imageDatabase.FindEntry( hash, Nes::Machine::FAVORED_NES_NTSC )) profile.hash = hash; } } } AddEntry( Entry::NES | compressed, profile ); } return TYPE_PROCESSED; } return TYPE_INVALID; } Launcher::List::Files::Inserter::Type Launcher::List::Files::Inserter::ParseUnf() { if (PrepareFile( 32, Managers::Paths::File::ID_UNIF )) { if (UniqueFile()) { Io::Stream::In stream( buffer ); Nes::Cartridge::Profile profile; Nes::Cartridge::ReadUnif( stream, Nes::Machine::FAVORED_NES_NTSC, profile ); AddEntry( Entry::UNF | compressed, profile ); } return TYPE_PROCESSED; } return TYPE_INVALID; } Launcher::List::Files::Inserter::Type Launcher::List::Files::Inserter::ParseXml() { if (PrepareFile()) { if (UniqueFile()) { Io::Stream::In stream( buffer ); Nes::Cartridge::Profile profile; if (NES_SUCCEEDED(Nes::Cartridge::ReadRomset( stream, Nes::Machine::FAVORED_NES_NTSC, Nes::Machine::DONT_ASK_PROFILE, profile ))) AddEntry( Entry::XML | compressed, profile ); } return TYPE_PROCESSED; } return TYPE_INVALID; } Launcher::List::Files::Inserter::Type Launcher::List::Files::Inserter::ParseFds() { const bool hasHeader = PrepareFile( 16, Managers::Paths::File::ID_FDS ); if (hasHeader || PrepareFile( 4, Managers::Paths::File::ID_FDS_RAW )) { if (UniqueFile()) { Entry entry( Entry::FDS | compressed ); const uint size = buffer.Size() - (hasHeader ? 16 : 0); entry.pRom = (size / Nes::Core::SIZE_1K) + (size % Nes::Core::SIZE_1K != 0); entry.wRam = 32; entry.vRam = 8; entry.attributes |= Entry::ATR_DEFAULT_FDS; AddEntry( entry ); } return TYPE_PROCESSED; } return TYPE_INVALID; } Launcher::List::Files::Inserter::Type Launcher::List::Files::Inserter::ParseNsf() { if (PrepareFile( 128, Managers::Paths::File::ID_NSF )) { if (UniqueFile()) { enum { NSF_CHIP_FDS = 0x4, NSF_CHIP_MMC5 = 0x8 }; #pragma pack(push,1) struct Header { uchar pad1[14]; char name[32]; uchar pad2[32]; char maker[32]; uchar pad3[12]; uchar mode; uchar chip; uchar pad4[4]; }; #pragma pack(pop) NST_COMPILE_ASSERT( sizeof(Header) == 128 ); Header& header = reinterpret_cast( buffer.Front() ); Entry entry( Entry::NSF | compressed ); const uint size = buffer.Size() - sizeof(Header); entry.pRom = (size / Nes::Core::SIZE_1K) + (size % Nes::Core::SIZE_1K != 0); switch (header.mode & 0x3U) { case 0x0: entry.attributes |= Entry::ATR_NTSC; break; case 0x1: entry.attributes |= Entry::ATR_PAL; break; default: entry.attributes |= Entry::ATR_NTSC_PAL; break; } switch (header.chip) { case NSF_CHIP_MMC5: entry.wRam = 8+1; break; case NSF_CHIP_FDS: entry.wRam = 8+32; break; default: entry.wRam = 8; break; } header.pad2[0] = '\0'; // in case string is not terminated entry.name = strings.Import( header.name ); AddEntry( entry ); } return TYPE_PROCESSED; } return TYPE_INVALID; } Launcher::List::Files::Inserter::Type Launcher::List::Files::Inserter::ParsePatch() { if (PrepareFile( 5, Managers::Paths::File::ID_IPS ) || PrepareFile( 4, Managers::Paths::File::ID_UPS )) { if (UniqueFile()) { Entry entry( Entry::PATCH | compressed ); AddEntry( entry ); return TYPE_PROCESSED; } } return TYPE_INVALID; } Launcher::List::Files::Inserter::Type Launcher::List::Files::Inserter::ParseArchive() { compressed = Entry::ARCHIVE; Io::File file; try { file.Open( path.string, Io::File::READ|Io::File::EXISTING ); } catch (Io::File::Exception) { return TYPE_PROCESSED; } const Io::Archive archive( file ); const uint length = path.string.Length(); for (uint i=0; i < archive.NumFiles(); ++i) { NST_VERIFY( archive[i].GetName().Length() ); // will look like: "archive.zip " path.string << " <" << archive[i].GetName(); Parser const parser = GetParser(); if (parser && parser != &Inserter::ParseArchive) { path.string << '>'; buffer.Resize( archive[i].Size() ); if (archive[i].Uncompress( buffer.Ptr() )) (*this.*parser)(); } path.string.ShrinkTo( length ); } return TYPE_PROCESSED; } Launcher::List::Files::Inserter::Type Launcher::List::Files::Inserter::ParseAny() { const bool notCompressed = buffer.Empty(); if ( (!include[Include::NES] || ParseNes() == TYPE_INVALID) && (!include[Include::UNF] || ParseUnf() == TYPE_INVALID) && (!include[Include::FDS] || ParseFds() == TYPE_INVALID) && (!include[Include::NSF] || ParseNsf() == TYPE_INVALID) && (!include[Include::PATCH] || ParsePatch() == TYPE_INVALID) && ( include[Include::ARCHIVE] && notCompressed) ) ParseArchive(); return TYPE_PROCESSED; } class Launcher::List::Files::Searcher : Inserter { public: Searcher ( Strings&, Entries&, const Settings&, const Nes::Cartridge::Database& ); void Search(); private: enum Abort { ABORT_SEARCH }; typedef std::set SearchedPaths; ibool OnInitDialog (Param&); bool UniquePath(); void Start(System::Thread::Terminator); void Search(System::Thread::Terminator); void ReadPath(wcstring const,System::Thread::Terminator); const Settings::Folders& folders; SearchedPaths searchedPaths; Dialog dialog; System::Thread thread; }; Launcher::List::Files::Searcher::Searcher ( Strings& v, Entries& e, const Settings& s, const Nes::Cartridge::Database& r ) : Inserter (v,e,s.include,r), folders (s.folders), dialog (IDD_LAUNCHER_SEARCH,WM_INITDIALOG,this,&Searcher::OnInitDialog) {} void Launcher::List::Files::Searcher::Start(System::Thread::Terminator terminator) { try { for (Settings::Folders::const_iterator it(folders.begin()), end(folders.end()); it != end; ++it) { if (it->path.Length()) { path.string = it->path; if (UniquePath()) { path.incSubDir = it->incSubDir; path.reference = PATH_NOT_ADDED; Search( terminator ); } } } } catch (Stop) { } catch (...) { static_cast(dialog).Close(); return; } static_cast(dialog).Close(); saveStrings = strings; saveEntries = entries; } ibool Launcher::List::Files::Searcher::OnInitDialog(Param&) { thread.Start( System::Thread::Callback(this,&Searcher::Start) ); return true; } void Launcher::List::Files::Searcher::Search() { if (folders.size() && (include.Word() & Include::FILES)) { bool enabled = !Application::Instance::GetMainWindow().Enable( false ); dialog.Open(); Application::Instance::GetMainWindow().Enable( enabled ); } } void Launcher::List::Files::Searcher::Search(System::Thread::Terminator terminate) { NST_ASSERT( path.string.Length() ); struct FileFinder { WIN32_FIND_DATA data; HANDLE const handle; FileFinder(wcstring path) : handle(::FindFirstFile( path, &data )) {} ~FileFinder() { if (handle != INVALID_HANDLE_VALUE) ::FindClose( handle ); } }; path.string.File() = "*.*"; FileFinder findFile( path.string.Ptr() ); path.string.File().Clear(); if (findFile.handle != INVALID_HANDLE_VALUE) { do { if (terminate) throw ABORT_SEARCH; if (!(findFile.data.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM))) { if (findFile.data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ReadPath( findFile.data.cFileName, terminate ); else ReadFile( findFile.data.cFileName, dialog ); } } while (::FindNextFile( findFile.handle, &findFile.data )); } } bool Launcher::List::Files::Searcher::UniquePath() { NST_ASSERT( path.string.Length() ); SearchedPaths::iterator it( searchedPaths.lower_bound( path.string ) ); if (it == searchedPaths.end() || *it != path.string) { searchedPaths.insert( it, path.string ); return true; } return false; } void Launcher::List::Files::Searcher::ReadPath(wcstring const subDir,System::Thread::Terminator terminator) { NST_ASSERT( subDir ); if (path.incSubDir && *subDir && *subDir != '.') { path.string.Directory() += subDir; if (UniquePath()) { const uint reference = path.reference; path.reference = PATH_NOT_ADDED; Search( terminator ); path.reference = reference; } path.string.Directory() -= 1; } } Launcher::List::Files::Files() : dirty (false), //loaded (!Application::Instance::GetExePath(L"launcher.xml").FileExists()) loaded (!Application::Instance::GetConfigPath(L"launcher.xml").FileExists())//bg { if (loaded) Io::Log() << "Launcher: database file \"launcher.xml\" not present\r\n"; } void Launcher::List::Files::Load() { if (loaded) return; loaded = true; try { typedef Nes::Core::Xml Xml; Xml xml; { //Io::Stream::In stream( Application::Instance::GetExePath(L"launcher.xml") ); Io::Stream::In stream( Application::Instance::GetConfigPath(L"launcher.xml") );//bg xml.Read( stream ); } if (!xml.GetRoot().IsType( L"launcher" ) || !xml.GetRoot().GetAttribute( L"version" ).IsValue(L"1.1")) throw 1; for (Xml::Node node(xml.GetRoot().GetFirstChild()); node; node=node.GetNextSibling()) { Entry entry; if (node.IsType( L"romset" )) { entry.type = Entry::XML; } else if (node.IsType( L"ines" )) { entry.type = Entry::NES; } else if (node.IsType( L"unif" )) { entry.type = Entry::UNF; } else if (node.IsType( L"fds" )) { entry.type = Entry::FDS; } else if (node.IsType( L"nsf" )) { entry.type = Entry::NSF; } else if (node.IsType( L"patch" )) { entry.type = Entry::PATCH; } else { throw 1; } wcstring string; if (!*(string=node.GetChild( L"file" ).GetValue())) throw 1; entry.file = strings << string; if (!*(string=node.GetChild( L"dir" ).GetValue())) throw 1; entry.path = strings << string; if (node.GetChild( L"archive" ).IsValue( L"yes" )) entry.type |= Entry::ARCHIVE; switch (entry.type & Entry::ALL) { case Entry::XML: case Entry::UNF: case Entry::NES: { if (*(string=node.GetChild( L"name" ).GetValue())) entry.name = strings << string; const Xml::Node system( node.GetChild( L"system" ) ); if (system.IsValue( L"vs" )) { entry.attributes = Entry::ATR_VS; } else if (system.IsValue( L"pc10" )) { entry.attributes = Entry::ATR_PC10; } else if (system.IsValue( L"pal" )) { entry.attributes = Entry::ATR_PAL; } else if (system.IsValue( L"ntsc/pal" )) { entry.attributes = Entry::ATR_NTSC_PAL; } else { entry.attributes = Entry::ATR_NTSC; } entry.pRom = node.GetChild( L"prg" ).GetUnsignedValue() & 0xFFFF; entry.cRom = node.GetChild( L"chr" ).GetUnsignedValue() & 0xFFFF; entry.wRam = node.GetChild( L"wram" ).GetUnsignedValue() & 0xFFFF; entry.vRam = node.GetChild( L"vram" ).GetUnsignedValue() & 0xFFFF; entry.mapper = node.GetChild( L"mapper" ).GetUnsignedValue() & 0xFFFF; if (node.GetChild( L"battery" ).IsValue( L"yes" )) entry.attributes |= Entry::ATR_BATTERY; entry.hash.Assign( node.GetChild( L"sha1" ).GetValue(), node.GetChild( L"crc" ).GetValue() ); break; } case Entry::FDS: entry.pRom = node.GetChild( L"prg" ).GetUnsignedValue() & 0xFFFF; entry.wRam = 32; entry.attributes = Entry::ATR_DEFAULT_FDS; break; case Entry::NSF: { if (*string) entry.name = strings << string; entry.pRom = node.GetChild( L"prg" ).GetUnsignedValue() & 0xFFFF; entry.wRam = node.GetChild( L"wram" ).GetUnsignedValue() & 0xFFFF; const Xml::Node system( node.GetChild( L"system" ) ); if (system.IsValue( L"pal" )) { entry.attributes = Entry::ATR_PAL; } else if (system.IsValue( L"ntsc/pal" )) { entry.attributes = Entry::ATR_NTSC_PAL; } else { entry.attributes = Entry::ATR_NTSC; } break; } } entries.PushBack( entry ); } } catch (...) { dirty = true; Clear(); User::Warn( IDS_LAUNCHER_ERR_LOAD_DB ); } Defrag(); } void Launcher::List::Files::Save() { if (dirty) { //const Path fileName( Application::Instance::GetExePath(L"launcher.xml") ); const Path fileName( Application::Instance::GetConfigPath(L"launcher.xml") );//bg if (entries.Size()) { try { typedef Nes::Core::Xml Xml; Xml xml; Xml::Node root( xml.Create(L"launcher") ); root.AddAttribute( L"version", L"1.1" ); for (Entries::ConstIterator it(entries.Begin()), end(entries.End()); it != end; ++it) { wcstring type; switch (it->type & Entry::ALL) { case Entry::NES: type = L"ines"; break; case Entry::UNF: type = L"unif"; break; case Entry::XML: type = L"romset"; break; case Entry::FDS: type = L"fds"; break; case Entry::NSF: type = L"nsf"; break; case Entry::PATCH: type = L"patch"; break; default: continue; } Xml::Node node( root.AddChild( type ) ); node.AddChild( L"file", strings[it->file] ); node.AddChild( L"dir", strings[it->path] ); if (it->type & Entry::ARCHIVE) node.AddChild( L"archive", L"yes" ); wchar_t buffer[32]; switch (it->type & Entry::ALL) { case Entry::NSF: { NST_ASSERT( !(it->attributes & ~uint(Entry::ATR_NTSC_PAL)) ); if (it->name) node.AddChild( L"name", strings[it->name] ); wcstring system = L"ntsc"; if (it->attributes & Entry::ATR_PAL) { if (it->attributes & Entry::ATR_NTSC) system = L"ntsc/pal"; else system = L"pal"; } node.AddChild( L"system", system ); if (it->pRom) { std::swprintf( buffer, L"%u", uint(it->pRom) ); node.AddChild( L"prg", buffer ); } if (it->wRam) { std::swprintf( buffer, L"%u", uint(it->wRam) ); node.AddChild( L"wram", buffer ); } break; } case Entry::FDS: if (it->pRom) { std::swprintf( buffer, L"%u", uint(it->pRom) ); node.AddChild( L"prg", buffer ); } break; case Entry::XML: case Entry::UNF: case Entry::NES: { if (it->name) node.AddChild( L"name", strings[it->name] ); wcstring system = L"ntsc"; if (it->attributes & Entry::ATR_VS) { system = L"vs"; } else if (it->attributes & Entry::ATR_PC10) { system = L"pc10"; } else if (it->attributes & Entry::ATR_PAL) { if (it->attributes & Entry::ATR_NTSC) system = L"ntsc/pal"; else system = L"pal"; } node.AddChild( L"system", system ); if (it->pRom) { std::swprintf( buffer, L"%u", uint(it->pRom) ); node.AddChild( L"prg", buffer ); } if (it->cRom) { std::swprintf( buffer, L"%u", uint(it->cRom) ); node.AddChild( L"chr", buffer ); } if (it->wRam) { std::swprintf( buffer, L"%u", uint(it->wRam) ); node.AddChild( L"wram", buffer ); } if (it->vRam) { std::swprintf( buffer, L"%u", uint(it->vRam) ); node.AddChild( L"vram", buffer ); } if (it->attributes & Entry::ATR_BATTERY) node.AddChild( L"battery", L"yes" ); if (it->mapper) { std::swprintf( buffer, L"%u", uint(it->mapper) ); node.AddChild( L"mapper", buffer ); } if (it->hash) { std::swprintf( buffer, L"%08X", uint(it->hash.GetCrc32()) ); node.AddChild( L"crc", buffer ); wchar_t sha1[Entry::Hash::SHA1_WORD_LENGTH*8+1]; sha1[Entry::Hash::SHA1_WORD_LENGTH*8] = '\0'; for (uint i=0; i < Entry::Hash::SHA1_WORD_LENGTH; ++i) std::swprintf( sha1+i*8, L"%08X", uint(it->hash.GetSha1()[i]) ); node.AddChild( L"sha1", sha1 ); } break; } } } Collection::Buffer buffer; { Io::Stream::Out stream( buffer ); xml.Write( root, stream ); } xml.Destroy(); Io::File( fileName, Io::File::DUMP ).Write( buffer.Ptr(), buffer.Size() ); Io::Log() << "Launcher: database saved to \"launcher.xml\"\r\n"; } catch (...) { User::Warn( IDS_LAUNCHER_ERR_SAVE_DB ); } } else if (fileName.FileExists()) { if (Io::File::Delete( fileName.Ptr() )) Io::Log() << "Launcher: empty database, deleted \"launcher.xml\"\r\n"; else Io::Log() << "Launcher: warning, couldn't delete \"launcher.xml\"!\r\n"; } } } void Launcher::List::Files::Defrag() { typedef std::map References; References references; if (entries.Size()) { Entries tmp; tmp.Reserve( entries.Size() ); for (Entries::ConstIterator it(entries.Begin()), end(entries.End()); it != end; ++it) { if (it->type) { if ( it->file ) references[strings[it->file]] = 0; if ( it->path ) references[strings[it->path]] = 0; if ( it->name ) references[strings[it->name]] = 0; tmp.PushBack( *it ); } } if (entries.Size() != tmp.Size()) entries = tmp; } if (entries.Size()) { Strings tmp( strings.Size() ); for (References::iterator it(references.begin()), end(references.end()); it != end; ++it) it->second = (tmp << it->first); for (Entries::Iterator it(entries.Begin()), end(entries.End()); it != end; ++it) { if ( it->file ) it->file = references.find( strings[ it->file ] )->second; if ( it->path ) it->path = references.find( strings[ it->path ] )->second; if ( it->name ) it->name = references.find( strings[ it->name ] )->second; } strings = tmp; } else { Clear(); } } bool Launcher::List::Files::Insert(const Nes::Cartridge::Database& imageDatabase,const GenericString fileName) { return dirty |= ( fileName.Length() && Inserter( strings, entries, Paths::Settings::Include(true), imageDatabase ).Add( fileName ) ); } bool Launcher::List::Files::ShouldDefrag() const { uint garbage = 0; for (Entries::ConstIterator it(entries.Begin()), end(entries.End()); it != end; ++it) { garbage += (it->type == 0); if (garbage > GARBAGE_THRESHOLD) return true; } return false; } void Launcher::List::Files::Clear() { if (entries.Size()) dirty = true; entries.Destroy(); strings.Clear(); } void Launcher::List::Files::Refresh ( const Paths::Settings& settings, const Nes::Cartridge::Database& imageDatabase ) { dirty = true; Searcher( strings, entries, settings, imageDatabase ).Search(); } Nes::Cartridge::Database::Entry Launcher::List::Files::Entry::SearchDb(const Nes::Cartridge::Database* db) const { Nes::Cartridge::Database::Entry entry; if (db && (type & (NES|UNF|XML))) entry = db->FindEntry( hash, Nes::Machine::FAVORED_NES_NTSC ); return entry; } uint Launcher::List::Files::Entry::GetSystem(const Nes::Cartridge::Database* db) const { if (const Nes::Cartridge::Database::Entry entry = SearchDb( db )) { if (entry.IsMultiRegion()) { return SYSTEM_NTSC_PAL; } else switch (entry.GetSystem()) { case Nes::Cartridge::Profile::System::NES_NTSC: case Nes::Cartridge::Profile::System::FAMICOM: return SYSTEM_NTSC; case Nes::Cartridge::Profile::System::NES_PAL: case Nes::Cartridge::Profile::System::NES_PAL_A: case Nes::Cartridge::Profile::System::NES_PAL_B: case Nes::Cartridge::Profile::System::DENDY: return SYSTEM_PAL; case Nes::Cartridge::Profile::System::VS_UNISYSTEM: case Nes::Cartridge::Profile::System::VS_DUALSYSTEM: return SYSTEM_VS; case Nes::Cartridge::Profile::System::PLAYCHOICE_10: return SYSTEM_PC10; } } else { if (attributes & ATR_VS) { return SYSTEM_VS; } else if (attributes & ATR_PC10) { return SYSTEM_PC10; } else if ((attributes & ATR_NTSC_PAL) == ATR_NTSC_PAL) { return SYSTEM_NTSC_PAL; } else if (attributes & ATR_NTSC) { return SYSTEM_NTSC; } else if (attributes & ATR_PAL) { return SYSTEM_PAL; } } return SYSTEM_UNKNOWN; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif } } nestopia-1.51.1/source/win32/NstDialogLauncherList.cpp000066400000000000000000000374411411157722000226020ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstWindowUser.hpp" #include "NstWindowDropFiles.hpp" #include "NstResourceString.hpp" #include "NstDialogFind.hpp" #include "NstManagerPaths.hpp" #include "NstDialogLauncher.hpp" #include namespace Nestopia { namespace Window { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("t", on) #endif wcstring Launcher::List::Strings::GetMapper(const uint value) { if (value-1 < 4095) { uint count = mappers.Size(); if (count <= value) { const uint size = NST_MAX(256,count+value+1); mappers.Resize( size ); do { _itow( count, mappers[count].string, 10 ); } while (++count != size); } return mappers[value].string; } else { return L"-"; } } wcstring Launcher::List::Strings::GetSize(uint value) { if (value) { SizeString& string = sizes[value]; if (string.Empty()) string << value << 'k'; return string.Ptr(); } return L"-"; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Launcher::List::Strings::Flush() { sizes.clear(); mappers.Destroy(); } Launcher::List::List ( Dialog& dialog, Menu::CmdHandler& cmdHandler, const Managers::Paths& p, const Configuration& cfg, const Nes::Cartridge::Database& database ) : imageDatabase ( database ), useImageDatabase ( NULL ), typeFilter ( 0 ), style ( STYLE ), finder ( dialog ), paths ( cfg ), columns ( cfg ), pathManager ( p ) { static const Menu::CmdHandler::Entry commands[] = { { IDM_LAUNCHER_EDIT_FIND, &List::OnCmdEditFind }, { IDM_LAUNCHER_EDIT_INSERT, &List::OnCmdEditInsert }, { IDM_LAUNCHER_EDIT_REMOVE, &List::OnCmdEditDelete }, { IDM_LAUNCHER_EDIT_CLEAR, &List::OnCmdEditClear }, { IDM_LAUNCHER_VIEW_ALIGNCOLUMNS, &List::OnCmdViewAlignColumns }, { IDM_LAUNCHER_OPTIONS_COLUMNS, &List::OnCmdOptionsColumns } }; cmdHandler.Add( this, commands ); Configuration::ConstSection show( cfg["launcher"]["view"]["show"] ); if (!show["grid-lines"].No()) style |= LVS_EX_GRIDLINES; if (!show["image-database-adjusted"].No()) useImageDatabase = &imageDatabase; } Launcher::List::~List() { } void Launcher::List::operator = (const Control::ListView& listView) { files.Load(); typeFilter = 0; ctrl = listView; ctrl.StyleEx() = style; ReloadListColumns(); ctrl.Reserve( files.Count() ); ctrl.Columns().Align(); InvalidateRect( ctrl.GetWindow(), NULL, false ); } void Launcher::List::Close() { finder.Close(); UpdateColumnOrder(); columns.Update( order ); strings.Flush(); } void Launcher::List::Insert(const Param& param) { DropFiles dropFiles( param ); if (dropFiles.Inside( ctrl.GetHandle() )) { uint anyInserted = false; for (uint i=0, n=dropFiles.Size(); i < n; ++i) anyInserted |= uint(files.Insert( imageDatabase, dropFiles[i] )); if (anyInserted && !Optimize()) Redraw(); } } void Launcher::List::Add(wcstring const fileName) { if (files.Insert( imageDatabase, fileName ) && !Optimize()) Redraw(); } void Launcher::List::Save(Configuration& cfg,bool saveFiles) { paths.Save( cfg ); columns.Save( cfg ); if (saveFiles) files.Save(); Configuration::Section show( cfg["launcher"]["view"]["show"] ); show["grid-lines"].YesNo() = style & LVS_EX_GRIDLINES; show["image-database-adjusted"].YesNo() = useImageDatabase; } void Launcher::List::SetColors(const uint bg,const uint fg,const Updater redraw) const { ctrl.SetBkColor( bg ); ctrl.SetTextBkColor( bg ); ctrl.SetTextColor( fg ); if (redraw) ctrl.Redraw(); } void Launcher::List::Redraw() { Application::Instance::Waiter wait; Generic::LockDraw lock( ctrl.GetHandle() ); ctrl.Clear(); if (const uint count = files.Count()) { uint size = 0; for (uint i=0; i < count; ++i) size += (files[i].GetType() & typeFilter) != 0; if (size) { ctrl.Reserve( size ); for (uint i=0; i < count; ++i) { if (files[i].GetType() & typeFilter) ctrl.Add( GenericString(), &files[i] ); } Sort(); ctrl.Columns().Align(); } } } bool Launcher::List::Optimize() { if (files.ShouldDefrag()) { files.Defrag(); Redraw(); return true; } return false; } bool Launcher::List::CanRefresh() const { return ( (paths.GetSettings().folders.size()) && (paths.GetSettings().include.Word() & Paths::Settings::Include::TYPES) ); } void Launcher::List::Refresh() { if (CanRefresh()) { { Application::Instance::Waiter wait; ctrl.Clear(); } files.Refresh( paths.GetSettings(), imageDatabase ); ctrl.Reserve( files.Count() ); Redraw(); } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("t", on) #endif void Launcher::List::OnGetDisplayInfo(LPARAM lParam) { LVITEM& item = reinterpret_cast(lParam)->item; if (item.mask & LVIF_TEXT) { const Files::Entry& entry = *reinterpret_cast( item.lParam ); switch (columns.GetType( item.iSubItem )) { case Columns::TYPE_FILE: item.pszText = const_cast( entry.GetFile(files.GetStrings()) ); break; case Columns::TYPE_SYSTEM: { NST_COMPILE_ASSERT ( Files::Entry::SYSTEM_UNKNOWN == 0 && Files::Entry::SYSTEM_PC10 == 1 && Files::Entry::SYSTEM_VS == 2 && Files::Entry::SYSTEM_PAL == 3 && Files::Entry::SYSTEM_NTSC == 4 && Files::Entry::SYSTEM_NTSC_PAL == 5 ); static const wchar_t lut[][9] = { L"-", L"pc10", L"vs", L"pal", L"ntsc", L"ntsc/pal" }; item.pszText = const_cast( lut[entry.GetSystem( useImageDatabase )] ); break; } case Columns::TYPE_BATTERY: item.pszText = const_cast ( (entry.GetType() & (Files::Entry::NES|Files::Entry::UNF)) ? entry.GetBattery( useImageDatabase ) ? L"yes" : L"no" : L"-" ); break; case Columns::TYPE_DUMP: { NST_COMPILE_ASSERT ( Nes::Cartridge::Profile::Dump::OK == 0 && Nes::Cartridge::Profile::Dump::BAD == 1 && Nes::Cartridge::Profile::Dump::UNKNOWN == 2 ); static const wchar_t lut[][4] = { L"ok", L"bad", L"-" }; item.pszText = const_cast( lut[entry.GetDump( useImageDatabase )] ); break; } case Columns::TYPE_NAME: item.pszText = const_cast( entry.GetName( files.GetStrings(), useImageDatabase ) ); break; case Columns::TYPE_FOLDER: item.pszText = const_cast( entry.GetPath( files.GetStrings() ) ); break; case Columns::TYPE_PROM: item.pszText = const_cast( strings.GetSize(entry.GetPRom(useImageDatabase)) ); break; case Columns::TYPE_CROM: if (const uint cRom = entry.GetCRom( useImageDatabase )) item.pszText = const_cast( strings.GetSize( cRom ) ); else item.pszText = const_cast( L"-" ); break; case Columns::TYPE_MAPPER: item.pszText = const_cast( strings.GetMapper(entry.GetMapper( useImageDatabase )) ); break; case Columns::TYPE_WRAM: if (const uint wRam = entry.GetWRam( useImageDatabase )) item.pszText = const_cast( strings.GetSize( wRam ) ); else item.pszText = const_cast( L"-" ); break; case Columns::TYPE_VRAM: if (const uint vRam = entry.GetVRam( useImageDatabase )) item.pszText = const_cast( strings.GetSize( vRam ) ); else item.pszText = const_cast( L"-" ); break; } } } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif void Launcher::List::ReloadListColumns() const { ctrl.Columns().Clear(); for (uint i=0; i < columns.Count(); ++i) ctrl.Columns().Insert( i, Resource::String(columns.GetStringId(i)).Ptr() ); } void Launcher::List::UpdateColumnOrder() { int array[Columns::NUM_TYPES]; ctrl.Columns().GetOrder( array, columns.Count() ); for (uint i=0; i < columns.Count(); ++i) order[i] = columns.GetType( array[i] ); } void Launcher::List::UpdateSortColumnOrder(const uint firstSortColumn) { int array[Columns::NUM_TYPES]; ctrl.Columns().GetOrder( array, columns.Count() ); order[0] = columns.GetType( firstSortColumn ); for (uint i=0, j=1; i < columns.Count(); ++i) { if (firstSortColumn != array[i]) order[j++] = columns.GetType( array[i] ); } } void Launcher::List::Sort(const uint firstSortColumn) { if (ctrl.Size() > 1) { UpdateSortColumnOrder( firstSortColumn ); ctrl.Sort( this, &List::Sorter ); } } int Launcher::List::Sorter(const void* obj1,const void* obj2) { const Files::Entry& a = *static_cast( obj1 ); const Files::Entry& b = *static_cast( obj2 ); for (uint i=0, n=columns.Count(); i < n; ++i) { switch (order[i]) { case Columns::TYPE_FILE: if (const int ret = ::StrCmp( a.GetFile(files.GetStrings()), b.GetFile(files.GetStrings()) )) return ret; continue; case Columns::TYPE_SYSTEM: { const uint system[] = { a.GetSystem( useImageDatabase ), b.GetSystem( useImageDatabase ) }; if (system[0] == system[1]) continue; return system[0] < system[1] ? +1 : -1; } case Columns::TYPE_MAPPER: { const uint mapper[] = { a.GetMapper( useImageDatabase ), b.GetMapper( useImageDatabase ) }; if (mapper[0] == mapper[1]) continue; return mapper[0] > mapper[1] ? +1 : -1; } case Columns::TYPE_PROM: { const uint pRom[] = { a.GetPRom( useImageDatabase ), b.GetPRom( useImageDatabase ) }; if (pRom[0] == pRom[1]) continue; return pRom[0] > pRom[1] ? +1 : -1; } case Columns::TYPE_CROM: { const uint cRom[] = { a.GetCRom( useImageDatabase ), b.GetCRom( useImageDatabase ) }; if (cRom[0] == cRom[1]) continue; return cRom[0] > cRom[1] ? +1 : -1; } case Columns::TYPE_WRAM: { const uint wRam[] = { a.GetWRam( useImageDatabase ), b.GetWRam( useImageDatabase ) }; if (wRam[0] == wRam[1]) continue; return wRam[0] > wRam[1] ? +1 : -1; } case Columns::TYPE_VRAM: { const uint vRam[] = { a.GetVRam( useImageDatabase ), b.GetVRam( useImageDatabase ) }; if (vRam[0] == vRam[1]) continue; return vRam[0] > vRam[1] ? +1 : -1; } case Columns::TYPE_BATTERY: { const uint battery[] = { a.GetBattery( useImageDatabase ) + bool(a.GetType() & (List::Files::Entry::NES|List::Files::Entry::UNF)), b.GetBattery( useImageDatabase ) + bool(b.GetType() & (List::Files::Entry::NES|List::Files::Entry::UNF)) }; if (battery[0] == battery[1]) continue; return battery[0] < battery[1] ? +1 : -1; } case Columns::TYPE_DUMP: { const uint dump[] = { a.GetDump( useImageDatabase ), b.GetDump( useImageDatabase ) }; if (dump[0] == dump[1]) continue; return dump[0] > dump[1] ? +1 : -1; } case Columns::TYPE_NAME: { wcstring const names[] = { a.GetName( files.GetStrings(), useImageDatabase ), b.GetName( files.GetStrings(), useImageDatabase ) }; if (names[0][0] != '-' && names[1][0] == '-') return -1; if (names[0][0] == '-' && names[1][0] != '-') return +1; if (const int ret = ::StrCmp( names[0], names[1] )) return ret; continue; } case Columns::TYPE_FOLDER: if (const int ret = ::StrCmp( a.GetPath(files.GetStrings()), b.GetPath(files.GetStrings()) )) return ret; continue; } } return 0; } void Launcher::List::OnFind(GenericString string,const uint flags) { const uint count = ctrl.Size(); if (count > 1 && string.Length()) { const uint column = ctrl.Columns().GetIndex(0); const int selection = ctrl.Selection().GetIndex(); const uint wrap = selection > 0 ? selection : 0; uint index = wrap; bool found; HeapString item; do { if (flags & Finder::DOWN) { if (++index == count) index = 0; } else { if (--index == ~0U) index = count - 1; } ctrl[index].Text( column ) >> item; if (flags & Finder::WHOLEWORD) { found = item.Length() == string.Length() && ::StrIsIntlEqual( (flags & Finder::MATCHCASE), item.Ptr(), string.Ptr(), string.Length() ); } else if (flags & Finder::MATCHCASE) { found = ::StrStr( item.Ptr(), string.Ptr() ); } else { found = ::StrStrI( item.Ptr(), string.Ptr() ); } } while (!found && index != wrap); if (found) { if (selection >= 0) ctrl[selection].Select( false ); ctrl[index].Select(); ctrl[index].Show(); } else { User::Inform( IDS_TEXT_SEARCH_NOT_FOUND, IDS_TEXT_FIND ); } } } void Launcher::List::OnCmdEditFind(uint) { finder.Open( this, &List::OnFind ); } void Launcher::List::OnCmdEditInsert(uint) { enum { FILE_TYPES = ( Managers::Paths::File::IMAGE | Managers::Paths::File::PATCH | Managers::Paths::File::ARCHIVE ) }; Add( pathManager.BrowseLoad( FILE_TYPES, GenericString(), Managers::Paths::DONT_CHECK_FILE ).Ptr() ); } void Launcher::List::OnCmdEditDelete(uint) { Application::Instance::Waiter wait; int last = -1; for (int index = ctrl.Selection().GetIndex(); index != -1; index = ctrl.Selection().GetIndex()) { last = index; void* const entry = ctrl[index].Data(); ctrl[index].Delete(); files.Disable( static_cast(entry) ); } if (ctrl.Size()) { if (last != -1) ctrl[last].Select(); } else if (typeFilter == Files::Entry::ALL) { files.Clear(); } } void Launcher::List::OnCmdEditClear(uint) { Application::Instance::Waiter wait; ctrl.Clear(); files.Clear(); } void Launcher::List::OnCmdViewAlignColumns(uint) { Application::Instance::Waiter wait; ctrl.Columns().Align(); } void Launcher::List::OnCmdOptionsColumns(uint) { UpdateColumnOrder(); columns.Update( order ); columns.Open(); Application::Instance::Waiter wait; Generic::LockDraw lock( ctrl.GetHandle() ); ReloadListColumns(); Sort(); ctrl.Columns().Align(); } } } nestopia-1.51.1/source/win32/NstDialogLauncherPaths.cpp000066400000000000000000000232171411157722000227420ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstWindowParam.hpp" #include "NstDialogBrowse.hpp" #include "NstDialogLauncher.hpp" namespace Nestopia { namespace Window { struct Launcher::List::Paths::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; static const Control::NotificationHandler::Entry notifications[]; }; const MsgHandler::Entry Launcher::List::Paths::Handlers::messages[] = { { WM_INITDIALOG, &Paths::OnInitDialog } }; const MsgHandler::Entry Launcher::List::Paths::Handlers::commands[] = { { IDC_LAUNCHER_PATHS_ADD, &Paths::OnCmdAdd }, { IDC_LAUNCHER_PATHS_REMOVE, &Paths::OnCmdRemove }, { IDC_LAUNCHER_PATHS_CLEAR, &Paths::OnCmdClear }, { IDOK, &Paths::OnCmdOk } }; const Control::NotificationHandler::Entry Launcher::List::Paths::Handlers::notifications[] = { { LVN_KEYDOWN, &Paths::OnKeyDown }, { LVN_ITEMCHANGED, &Paths::OnItemChanged }, { LVN_INSERTITEM, &Paths::OnInsertItem }, { LVN_DELETEITEM, &Paths::OnDeleteItem } }; Launcher::List::Paths::Paths(const Configuration& cfg) : dialog ( IDD_LAUNCHER_PATHS, this, Handlers::messages, Handlers::commands ), notifications ( IDC_LAUNCHER_PATHS_LIST, dialog.Messages(), this, Handlers::notifications ) { Configuration::ConstSection search( cfg["launcher"]["search"] ); { Configuration::ConstSection files( search["files"] ); settings.include[ Settings::Include::NES ] = !files[ "nes" ].No(); settings.include[ Settings::Include::UNF ] = !files[ "unf" ].No(); settings.include[ Settings::Include::XML ] = !files[ "xml" ].No(); settings.include[ Settings::Include::FDS ] = !files[ "fds" ].No(); settings.include[ Settings::Include::NSF ] = !files[ "nsf" ].No(); settings.include[ Settings::Include::PATCH ] = !files[ "patch" ].No(); settings.include[ Settings::Include::ARCHIVE ] = !files[ "archive" ].No(); settings.include[ Settings::Include::ANY ] = files[ "any-extension" ].Yes(); settings.include[ Settings::Include::UNIQUE ] = !files[ "duplicates" ].Yes(); } { Configuration::ConstSection directories( search["directories"] ); Path dir; for (uint i=0; i < LIMIT; ++i) { Configuration::ConstSection path( directories["path"][i] ); dir = path["directory"].Str(); if (dir.Empty()) break; dir.MakePretty( true ); settings.folders.resize( settings.folders.size() + 1 ); settings.folders.back().path = dir; settings.folders.back().incSubDir = path["sub-directories"].Yes(); } } } void Launcher::List::Paths::Save(Configuration& cfg) const { Configuration::Section search( cfg["launcher"]["search"] ); { Configuration::Section files( search["files"] ); files[ "nes" ].YesNo() = settings.include[ Settings::Include::NES ]; files[ "unf" ].YesNo() = settings.include[ Settings::Include::UNF ]; files[ "xml" ].YesNo() = settings.include[ Settings::Include::XML ]; files[ "fds" ].YesNo() = settings.include[ Settings::Include::FDS ]; files[ "nsf" ].YesNo() = settings.include[ Settings::Include::NSF ]; files[ "patch" ].YesNo() = settings.include[ Settings::Include::PATCH ]; files[ "archive" ].YesNo() = settings.include[ Settings::Include::ARCHIVE ]; files[ "any-extension" ].YesNo() = settings.include[ Settings::Include::ANY ]; files[ "duplicates" ].YesNo() = !settings.include[ Settings::Include::UNIQUE ]; } { Configuration::Section directories( search["directories"] ); for (uint i=0, n=settings.folders.size(); i < n; ++i) { Configuration::Section path( directories["path"][i] ); NST_ASSERT( settings.folders[i].path.Length() ); path["directory"].Str() = settings.folders[i].path; path["sub-directories"].YesNo() = settings.folders[i].incSubDir; } } } ibool Launcher::List::Paths::OnInitDialog(Param&) { dialog.CheckBox( IDC_LAUNCHER_PATHS_NES ).Check( settings.include[ Settings::Include::NES ] ); dialog.CheckBox( IDC_LAUNCHER_PATHS_UNF ).Check( settings.include[ Settings::Include::UNF ] ); dialog.CheckBox( IDC_LAUNCHER_PATHS_XML ).Check( settings.include[ Settings::Include::XML ] ); dialog.CheckBox( IDC_LAUNCHER_PATHS_FDS ).Check( settings.include[ Settings::Include::FDS ] ); dialog.CheckBox( IDC_LAUNCHER_PATHS_NSF ).Check( settings.include[ Settings::Include::NSF ] ); dialog.CheckBox( IDC_LAUNCHER_PATHS_PATCH ).Check( settings.include[ Settings::Include::PATCH ] ); dialog.CheckBox( IDC_LAUNCHER_PATHS_ARCHIVE ).Check( settings.include[ Settings::Include::ARCHIVE ] ); dialog.CheckBox( IDC_LAUNCHER_PATHS_ALLFILES ).Check( settings.include[ Settings::Include::ANY ] ); dialog.CheckBox( IDC_LAUNCHER_PATHS_UNIQUEFILES ).Check( settings.include[ Settings::Include::UNIQUE ] ); dialog.Control( IDC_LAUNCHER_PATHS_REMOVE ).Enable( false ); dialog.Control( IDC_LAUNCHER_PATHS_CLEAR ).Enable( settings.folders.size() ); const Control::ListView listView( dialog.ListView(IDC_LAUNCHER_PATHS_LIST) ); listView.StyleEx() = LVS_EX_CHECKBOXES; listView.Reserve( settings.folders.size() ); for (Settings::Folders::const_iterator it(settings.folders.begin()), end(settings.folders.end()); it != end; ++it) listView.Add( it->path, LPARAM(0), it->incSubDir ); return true; } ibool Launcher::List::Paths::OnCmdAdd(Param& param) { if (param.Button().Clicked() && dialog.ListView( IDC_LAUNCHER_PATHS_LIST ).Size() < LIMIT) { const Path dir( Browser::SelectDirectory() ); if (dir.Length()) dialog.ListView( IDC_LAUNCHER_PATHS_LIST ).Add( dir ); } return true; } ibool Launcher::List::Paths::OnCmdRemove(Param& param) { if (param.Button().Clicked()) dialog.ListView( IDC_LAUNCHER_PATHS_LIST ).Selection().Delete(); return true; } ibool Launcher::List::Paths::OnCmdClear(Param& param) { if (param.Button().Clicked()) dialog.ListView( IDC_LAUNCHER_PATHS_LIST ).Clear(); return true; } ibool Launcher::List::Paths::OnCmdOk(Param& param) { if (param.Button().Clicked()) { settings.include[ Settings::Include::NES ] = dialog.CheckBox( IDC_LAUNCHER_PATHS_NES ).Checked(); settings.include[ Settings::Include::UNF ] = dialog.CheckBox( IDC_LAUNCHER_PATHS_UNF ).Checked(); settings.include[ Settings::Include::XML ] = dialog.CheckBox( IDC_LAUNCHER_PATHS_XML ).Checked(); settings.include[ Settings::Include::FDS ] = dialog.CheckBox( IDC_LAUNCHER_PATHS_FDS ).Checked(); settings.include[ Settings::Include::NSF ] = dialog.CheckBox( IDC_LAUNCHER_PATHS_NSF ).Checked(); settings.include[ Settings::Include::PATCH ] = dialog.CheckBox( IDC_LAUNCHER_PATHS_PATCH ).Checked(); settings.include[ Settings::Include::ARCHIVE ] = dialog.CheckBox( IDC_LAUNCHER_PATHS_ARCHIVE ).Checked(); settings.include[ Settings::Include::ANY ] = dialog.CheckBox( IDC_LAUNCHER_PATHS_ALLFILES ).Checked(); settings.include[ Settings::Include::UNIQUE ] = dialog.CheckBox( IDC_LAUNCHER_PATHS_UNIQUEFILES ).Checked(); const Control::ListView listView( dialog.ListView(IDC_LAUNCHER_PATHS_LIST) ); settings.folders.resize( listView.Size() ); for (uint i=0, n=settings.folders.size(); i < n; ++i) { listView[i].Text() >> settings.folders[i].path; settings.folders[i].incSubDir = listView[i].Checked(); } dialog.Close(); } return true; } void Launcher::List::Paths::OnKeyDown(const NMHDR& nmhdr) { switch (reinterpret_cast(nmhdr).wVKey) { case VK_INSERT: dialog.PostCommand( IDC_LAUNCHER_PATHS_ADD ); break; case VK_DELETE: dialog.PostCommand( IDC_LAUNCHER_PATHS_REMOVE ); break; } } void Launcher::List::Paths::OnItemChanged(const NMHDR& nmhdr) { const NMLISTVIEW& nm = reinterpret_cast(nmhdr); if ((nm.uOldState ^ nm.uNewState) & LVIS_SELECTED) dialog.Control( IDC_LAUNCHER_PATHS_REMOVE ).Enable( nm.uNewState & LVIS_SELECTED ); } void Launcher::List::Paths::OnInsertItem(const NMHDR&) { dialog.Control( IDC_LAUNCHER_PATHS_CLEAR ).Enable(); } void Launcher::List::Paths::OnDeleteItem(const NMHDR&) { if (dialog.ListView( IDC_LAUNCHER_PATHS_LIST ).Size() <= 1) { dialog.Control( IDC_LAUNCHER_PATHS_CLEAR ).Disable(); dialog.Control( IDC_LAUNCHER_PATHS_REMOVE ).Disable(); } } } } nestopia-1.51.1/source/win32/NstDialogLauncherTree.cpp000066400000000000000000000052261411157722000225620ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "resource/resource.h" #include "NstResourceString.hpp" #include "NstDialogLauncher.hpp" namespace Nestopia { namespace Window { Launcher::Tree::Tree() : selection (0), imageList (16,16,IDB_LAUNCHERTREE_OPEN,IDB_LAUNCHERTREE_CLOSED) {} void Launcher::Tree::operator = (const Control::TreeView& treeCtrl) { ctrl = treeCtrl; ctrl.SetImageList( imageList ); ctrl.Add( Resource::String( IDS_LAUNCHER_SECTION_ALL ) ); ctrl.Add( Resource::String( IDS_LAUNCHER_SECTION_XML ) ); ctrl.Add( Resource::String( IDS_LAUNCHER_SECTION_NES ) ); ctrl.Add( Resource::String( IDS_LAUNCHER_SECTION_UNIF ) ); ctrl.Add( Resource::String( IDS_LAUNCHER_SECTION_FDS ) ); ctrl.Add( Resource::String( IDS_LAUNCHER_SECTION_NSF ) ); ctrl.Add( Resource::String( IDS_LAUNCHER_SECTION_PATCH ) ); ctrl.Add( Resource::String( IDS_LAUNCHER_SECTION_ARCHIVE ) ); ctrl[selection].Select(); } void Launcher::Tree::Close() { selection = ctrl.Selection().GetIndex(); } void Launcher::Tree::SetColors(const uint bg,const uint fg,const Updater redraw) const { ctrl.SetBackgroundColor( bg ); ctrl.SetTextColor( fg ); if (redraw) ctrl.Redraw(); } uint Launcher::Tree::GetType(HTREEITEM const hItem) const { switch (ctrl.GetIndex( hItem )) { case 1: return List::Files::Entry::XML; case 2: return List::Files::Entry::NES; case 3: return List::Files::Entry::UNF; case 4: return List::Files::Entry::FDS; case 5: return List::Files::Entry::NSF; case 6: return List::Files::Entry::PATCH; case 7: return List::Files::Entry::ARCHIVE; } return List::Files::Entry::ALL; } } } nestopia-1.51.1/source/win32/NstDialogLicense.cpp000066400000000000000000000040761411157722000215650ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "resource/resource.h" #include "NstWindowParam.hpp" #include "NstResourceFile.hpp" #include "NstDialogLicense.hpp" namespace Nestopia { namespace Window { struct License::Handlers { static const MsgHandler::Entry messages[]; }; const MsgHandler::Entry License::Handlers::messages[] = { { WM_INITDIALOG, &License::OnInitDialog }, { WM_CTLCOLORSTATIC, &License::OnCtlColorStatic } }; License::License() : dialog(IDD_LICENSE,this,Handlers::messages) {} ibool License::OnInitDialog(Param&) { Collection::Buffer buffer; if (Resource::File( IDR_LICENSE, L"License" ).Uncompress( buffer )) { buffer.PushBack('\0'); dialog.Control( IDC_LICENSE_EDIT ).Text() << buffer.Ptr(); } return true; } ibool License::OnCtlColorStatic(Param& param) { NST_COMPILE_ASSERT( sizeof(ibool) == sizeof(BOOL) ); if (reinterpret_cast(param.lParam) == ::GetDlgItem( param.hWnd, IDC_LICENSE_EDIT )) return reinterpret_cast(::GetSysColorBrush( COLOR_WINDOW )); else return false; } } } nestopia-1.51.1/source/win32/NstDialogLicense.hpp000066400000000000000000000026021411157722000215630ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIALOG_LICENSE_H #define NST_DIALOG_LICENSE_H #pragma once #include "NstWindowDialog.hpp" namespace Nestopia { namespace Window { class License { public: License(); private: struct Handlers; ibool OnInitDialog (Param&); ibool OnCtlColorStatic (Param&); Dialog dialog; public: void Open() { dialog.Open(); } }; } } #endif nestopia-1.51.1/source/win32/NstDialogLogfile.cpp000066400000000000000000000045571411157722000215700ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstWindowParam.hpp" #include "NstDialogLogfile.hpp" namespace Nestopia { namespace Window { struct Logfile::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; }; const MsgHandler::Entry Logfile::Handlers::messages[] = { { WM_INITDIALOG, &Logfile::OnInitDialog }, { WM_CTLCOLORSTATIC, &Logfile::OnCtlColorStatic } }; const MsgHandler::Entry Logfile::Handlers::commands[] = { { IDC_LOGFILE_CLEAR, &Logfile::OnCmdClear } }; Logfile::Logfile() : dialog(IDD_LOGFILE,this,Handlers::messages,Handlers::commands) {} bool Logfile::Open(wcstring const string) { clear = false; if (*string) { text = string; dialog.Open(); } return clear; } ibool Logfile::OnInitDialog(Param&) { dialog.Edit( IDC_LOGFILE_EDIT ) << text; return true; } ibool Logfile::OnCtlColorStatic(Param& param) { NST_COMPILE_ASSERT( sizeof(ibool) == sizeof(BOOL) ); if (reinterpret_cast(param.lParam) == ::GetDlgItem( param.hWnd, IDC_LOGFILE_EDIT )) return reinterpret_cast(::GetSysColorBrush( COLOR_WINDOW )); else return false; } ibool Logfile::OnCmdClear(Param& param) { if (param.Button().Clicked()) { dialog.Edit( IDC_LOGFILE_EDIT ).Clear(); clear = true; } return true; } } } nestopia-1.51.1/source/win32/NstDialogLogfile.hpp000066400000000000000000000026501411157722000215650ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIALOG_LOGFILE_H #define NST_DIALOG_LOGFILE_H #pragma once #include "NstWindowDialog.hpp" namespace Nestopia { namespace Window { class Logfile { public: Logfile(); bool Open(wcstring); private: struct Handlers; ibool OnInitDialog (Param&); ibool OnCtlColorStatic (Param&); ibool OnCmdClear (Param&); wcstring text; bool clear; Dialog dialog; }; } } #endif nestopia-1.51.1/source/win32/NstDialogMovie.cpp000066400000000000000000000054741411157722000212650ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstWindowParam.hpp" #include "NstManagerPaths.hpp" #include "NstApplicationInstance.hpp" #include "NstDialogMovie.hpp" namespace Nestopia { namespace Window { struct Movie::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; }; const MsgHandler::Entry Movie::Handlers::messages[] = { { WM_INITDIALOG, &Movie::OnInitDialog } }; const MsgHandler::Entry Movie::Handlers::commands[] = { { IDC_MOVIE_CLEAR, &Movie::OnCmdClear }, { IDC_MOVIE_BROWSE, &Movie::OnCmdBrowse }, { IDOK, &Movie::OnCmdOk } }; Movie::Movie(const Managers::Paths& p) : dialog(IDD_MOVIE,this,Handlers::messages,Handlers::commands), paths(p) {} Movie::~Movie() { } const Path Movie::GetMovieFile() const { return Application::Instance::GetFullPath( movieFile ); } void Movie::SetMovieFile(const Path& file) { movieFile = file; paths.FixFile( Managers::Paths::File::MOVIE, movieFile ); } ibool Movie::OnInitDialog(Param&) { dialog.Edit(IDC_MOVIE_FILE) << movieFile.Ptr(); return true; } ibool Movie::OnCmdClear(Param& param) { if (param.Button().Clicked()) dialog.Edit(IDC_MOVIE_FILE).Clear(); return true; } ibool Movie::OnCmdBrowse(Param& param) { if (param.Button().Clicked()) { Path tmp; dialog.Edit(IDC_MOVIE_FILE).Text() >> tmp; dialog.Edit(IDC_MOVIE_FILE).Try() << paths.BrowseSave( Managers::Paths::File::MOVIE, Managers::Paths::SUGGEST, Application::Instance::GetFullPath(tmp) ).Ptr(); } return true; } ibool Movie::OnCmdOk(Param& param) { if (param.Button().Clicked()) { dialog.Edit(IDC_MOVIE_FILE) >> movieFile; paths.FixFile( Managers::Paths::File::MOVIE, movieFile ); dialog.Close(); } return true; } } } nestopia-1.51.1/source/win32/NstDialogMovie.hpp000066400000000000000000000032251411157722000212620ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIALOG_MOVIE_H #define NST_DIALOG_MOVIE_H #pragma once #include "NstWindowDialog.hpp" namespace Nestopia { namespace Window { class Movie { public: explicit Movie(const Managers::Paths&); ~Movie(); void SetMovieFile(const Path&); const Path GetMovieFile() const; private: struct Handlers; ibool OnInitDialog (Param&); ibool OnCmdBrowse (Param&); ibool OnCmdClear (Param&); ibool OnCmdOk (Param&); Dialog dialog; const Managers::Paths& paths; Path movieFile; public: void Open() { dialog.Open(); } void ClearMovieFile() { movieFile.Clear(); } }; } } #endif nestopia-1.51.1/source/win32/NstDialogNetPlay.cpp000066400000000000000000000212511411157722000215510ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstIoLog.hpp" #include "NstIoStream.hpp" #include "NstIoFile.hpp" #include "NstApplicationInstance.hpp" #include "NstWindowParam.hpp" #include "NstWindowDropFiles.hpp" #include "NstManagerPaths.hpp" #include "NstDialogNetPlay.hpp" #include "../core/NstXml.hpp" #include namespace Nestopia { namespace Window { struct Netplay::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; static const Control::NotificationHandler::Entry notifications[]; }; const MsgHandler::Entry Netplay::Handlers::messages[] = { { WM_INITDIALOG, &Netplay::OnInitDialog }, { WM_DROPFILES, &Netplay::OnDropFiles } }; const MsgHandler::Entry Netplay::Handlers::commands[] = { { IDC_NETPLAY_ADD, &Netplay::OnAdd }, { IDC_NETPLAY_REMOVE, &Netplay::OnRemove }, { IDC_NETPLAY_CLEAR, &Netplay::OnClear }, { IDC_NETPLAY_DEFAULT, &Netplay::OnDefault }, { IDC_NETPLAY_LAUNCH, &Netplay::OnLaunch }, { IDC_NETPLAY_PLAY_FULLSCREEN, &Netplay::OnFullscreen } }; const Control::NotificationHandler::Entry Netplay::Handlers::notifications[] = { { LVN_KEYDOWN, &Netplay::OnKeyDown }, { LVN_ITEMCHANGED, &Netplay::OnItemChanged }, { LVN_INSERTITEM, &Netplay::OnInsertItem }, { LVN_DELETEITEM, &Netplay::OnDeleteItem } }; bool Netplay::Games::Less::operator () (const Path& a,const Path& b) const { return a.Target().File() < b.Target().File(); } Netplay::Games::Games() : state(UNINITIALIZED) {} Netplay::Netplay(Managers::Emulator& e,const Managers::Paths& p,bool fullscreen) : dialog ( IDD_NETPLAY, this, Handlers::messages, Handlers::commands ), doFullscreen ( fullscreen ), paths ( p ), emulator ( e ), notifications ( IDC_NETPLAY_GAMELIST, dialog.Messages(), this, Handlers::notifications ) { } Netplay::~Netplay() { } void Netplay::LoadFile() { try { //const Path path( Application::Instance::GetExePath(L"netplaylist.xml") ); const Path path( Application::Instance::GetConfigPath(L"netplaylist.xml") );//bg if (path.FileExists()) { typedef Nes::Core::Xml Xml; Xml xml; { Io::Stream::In stream( path ); xml.Read( stream ); } if (!xml.GetRoot().IsType( L"netplaylist" )) throw 1; for (Xml::Node node(xml.GetRoot().GetFirstChild()); node; node=node.GetNextSibling()) { if (!node.IsType( L"file" )) throw 1; Add( node.GetValue() ); } Io::Log() << "Netplay: loaded game list from \"netplaylist.xml\"\r\n"; } else { Io::Log() << "Netplay: game list file \"netplaylist.xml\" not present..\r\n"; } } catch (...) { games.state = Games::DIRTY; Io::Log() << "Netplay: warning, couldn't load game list \"netplaylist.xml\"!\r\n"; } } void Netplay::SaveFile() const { if (games.state == Games::DIRTY) { //const Path path( Application::Instance::GetExePath(L"netplaylist.xml") ); const Path path( Application::Instance::GetConfigPath(L"netplaylist.xml") );//bg if (!games.paths.empty()) { try { typedef Nes::Core::Xml Xml; Xml xml; Xml::Node root( xml.Create( L"netplaylist" ) ); root.AddAttribute( L"version", L"1.0" ); for (Games::Paths::const_iterator it(games.paths.begin()), end(games.paths.end()); it != end; ++it) root.AddChild( L"file", it->Ptr() ); Io::Stream::Out stream( path ); xml.Write( root, stream ); Io::Log() << "Netplay: saved game list to \"netplaylist.xml\"\r\n"; } catch (...) { Io::Log() << "Netplay: warning, couldn't save game list to \"netplaylist.xml\"!\r\n"; } } else if (path.FileExists()) { if (Io::File::Delete( path.Ptr() )) Io::Log() << "Netplay: game list empty, deleted \"netplaylist.xml\"\r\n"; else Io::Log() << "Netplay: warning, couldn't delete \"netplaylist.xml\"!\r\n"; } } } wcstring Netplay::GetPath(wcstring const path) const { Games::Paths::const_iterator it(games.paths.find( path )); return it != games.paths.end() ? it->Ptr() : NULL; } void Netplay::Add(Path path) { enum { TYPES = Managers::Paths::File::GAME|Managers::Paths::File::ARCHIVE }; if (path.Length() && games.paths.size() < Games::LIMIT && paths.CheckFile( path, TYPES ) && games.paths.insert( path ).second) { games.state = Games::DIRTY; if (dialog) dialog.ListView( IDC_NETPLAY_GAMELIST ).Add( path.Target().File() ); } } ibool Netplay::OnInitDialog(Param&) { dialog.CheckBox( IDC_NETPLAY_PLAY_FULLSCREEN ).Check( doFullscreen ); dialog.CheckBox( IDC_NETPLAY_REMOVE ).Disable(); if (games.state == Games::UNINITIALIZED) { LoadFile(); } else { Control::ListView list( dialog.ListView( IDC_NETPLAY_GAMELIST ) ); list.Reserve( games.paths.size() ); for (Games::Paths::const_iterator it(games.paths.begin()), end(games.paths.end()); it != end; ++it) list.Add( it->Target().File().Ptr() ); } dialog.CheckBox( IDC_NETPLAY_CLEAR ).Enable( games.paths.size() ); dialog.CheckBox( IDC_NETPLAY_LAUNCH ).Enable( games.paths.size() ); return true; } ibool Netplay::OnAdd(Param& param) { if (param.Button().Clicked()) Add( paths.BrowseLoad(Managers::Paths::File::GAME|Managers::Paths::File::ARCHIVE) ); return true; } ibool Netplay::OnRemove(Param& param) { if (param.Button().Clicked()) dialog.ListView( IDC_NETPLAY_GAMELIST ).Selection().Delete(); return true; } ibool Netplay::OnClear(Param& param) { if (param.Button().Clicked()) dialog.ListView( IDC_NETPLAY_GAMELIST ).Clear(); return true; } ibool Netplay::OnDefault(Param& param) { if (param.Button().Clicked()) { doFullscreen = false; dialog.CheckBox( IDC_NETPLAY_PLAY_FULLSCREEN ).Check( false ); } return true; } ibool Netplay::OnLaunch(Param& param) { if (param.Button().Clicked()) dialog.Close( LAUNCH ); return true; } ibool Netplay::OnFullscreen(Param& param) { if (param.Button().Clicked()) doFullscreen = dialog.CheckBox( IDC_NETPLAY_PLAY_FULLSCREEN ).Checked(); return true; } ibool Netplay::OnDropFiles(Param& param) { DropFiles dropFiles( param ); if (dropFiles.Inside( dialog.ListView( IDC_NETPLAY_GAMELIST ).GetWindow() )) { for (uint i=0, n=dropFiles.Size(); i < n; ++i) Add( dropFiles[i] ); } return true; } void Netplay::OnKeyDown(const NMHDR& nmhdr) { switch (reinterpret_cast(nmhdr).wVKey) { case VK_INSERT: dialog.PostCommand( IDC_NETPLAY_ADD ); break; case VK_DELETE: dialog.PostCommand( IDC_NETPLAY_REMOVE ); break; } } void Netplay::OnItemChanged(const NMHDR& nmhdr) { const NMLISTVIEW& nm = reinterpret_cast(nmhdr); if ((nm.uOldState ^ nm.uNewState) & LVIS_SELECTED) dialog.CheckBox( IDC_NETPLAY_REMOVE ).Enable( nm.uNewState & LVIS_SELECTED ); } void Netplay::OnInsertItem(const NMHDR&) { dialog.CheckBox( IDC_NETPLAY_CLEAR ).Enable(); dialog.CheckBox( IDC_NETPLAY_LAUNCH ).Enable(); } void Netplay::OnDeleteItem(const NMHDR& nmhdr) { Games::Paths::iterator it(games.paths.begin()); for (int i=reinterpret_cast(nmhdr).iItem; i > 0; --i) ++it; games.paths.erase( it ); games.state = Games::DIRTY; if (dialog.ListView( IDC_NETPLAY_GAMELIST ).Size() <= 1) { dialog.CheckBox( IDC_NETPLAY_CLEAR ).Disable(); dialog.CheckBox( IDC_NETPLAY_LAUNCH ).Disable(); dialog.CheckBox( IDC_NETPLAY_REMOVE ).Disable(); } } } } nestopia-1.51.1/source/win32/NstDialogNetplay.hpp000066400000000000000000000057571411157722000216330ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIALOG_NETPLAY_H #define NST_DIALOG_NETPLAY_H #pragma once #include #include "NstWindowDialog.hpp" namespace Nestopia { namespace Managers { class Paths; class Emulator; } namespace Window { class Netplay { public: Netplay(Managers::Emulator&,const Managers::Paths&,bool); ~Netplay(); void SaveFile() const; wcstring GetPath(wcstring) const; class Chat { public: typedef int (WINAPI *Callback)(char*); explicit Chat(Callback); ~Chat(); void Close(); void Open(); private: struct Handlers; ibool OnInit (Param&); ibool OnCommand (Param&); Dialog dialog; const Callback callback; String::Heap text; }; private: struct Handlers; enum { LAUNCH = 0xB00B }; struct Games { Games(); struct Less { bool operator () (const Path&,const Path&) const; }; typedef std::set Paths; enum { LIMIT = 100 }; enum State { CLEAN, DIRTY, UNINITIALIZED }; State state; Paths paths; }; public: typedef Games::Paths GamePaths; private: void LoadFile(); void Add(Path); ibool OnInitDialog (Param&); ibool OnAdd (Param&); ibool OnRemove (Param&); ibool OnClear (Param&); ibool OnDefault (Param&); ibool OnLaunch (Param&); ibool OnFullscreen (Param&); ibool OnDropFiles (Param&); void OnKeyDown (const NMHDR&); void OnItemChanged (const NMHDR&); void OnInsertItem (const NMHDR&); void OnDeleteItem (const NMHDR&); Dialog dialog; bool doFullscreen; const Managers::Paths& paths; Managers::Emulator& emulator; const Control::NotificationHandler notifications; Games games; public: bool Open() { return dialog.Open() == LAUNCH; } bool ShouldGoFullscreen() const { return doFullscreen; } const GamePaths& GetGamePaths() const { return games.paths; } }; } } #endif nestopia-1.51.1/source/win32/NstDialogNetplayChat.cpp000066400000000000000000000042441411157722000224140ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstWindowParam.hpp" #include "NstDialogNetPlay.hpp" namespace Nestopia { namespace Window { struct Netplay::Chat::Handlers { static const MsgHandler::Entry messages[]; }; const MsgHandler::Entry Netplay::Chat::Handlers::messages[] = { { WM_INITDIALOG, &Chat::OnInit }, { WM_COMMAND, &Chat::OnCommand } }; Netplay::Chat::Chat(Callback c) : dialog ( IDD_CHAT, this, Handlers::messages ), callback ( c ) {} Netplay::Chat::~Chat() { } void Netplay::Chat::Open() { dialog.Open( Dialog::MODELESS_CHILD ); } void Netplay::Chat::Close() { dialog.Close(); text.Destroy(); } ibool Netplay::Chat::OnInit(Param&) { dialog.Edit(IDC_CHAT_EDIT).Limit(255); return true; } ibool Netplay::Chat::OnCommand(Param& param) { if (param.wParam == 1 && param.lParam == 0) { HeapString wtext; const Control::Edit edit( dialog.Edit(IDC_CHAT_EDIT) ); if (edit.Text() >> wtext) { wtext.Trim(); if (wtext.Length()) { text.Clear(); callback( text.Import(wtext.Ptr()).Ptr() ); } edit.Text().Clear(); } } return false; } } } nestopia-1.51.1/source/win32/NstDialogPaletteEditor.cpp000066400000000000000000000314031411157722000227420ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstWindowUser.hpp" #include "NstWindowParam.hpp" #include "NstApplicationInstance.hpp" #include "NstManagerPaths.hpp" #include "NstDialogPaletteEditor.hpp" namespace Nestopia { namespace Window { NST_COMPILE_ASSERT ( IDC_PALETTE_EDITOR_G_SLIDER == IDC_PALETTE_EDITOR_R_SLIDER + 1 && IDC_PALETTE_EDITOR_B_SLIDER == IDC_PALETTE_EDITOR_R_SLIDER + 2 ); NST_COMPILE_ASSERT ( IDC_PALETTE_EDITOR_G_VALUE == IDC_PALETTE_EDITOR_R_VALUE + 1 && IDC_PALETTE_EDITOR_B_VALUE == IDC_PALETTE_EDITOR_R_VALUE + 2 ); bool PaletteEditor::showHex = false; struct PaletteEditor::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; }; const MsgHandler::Entry PaletteEditor::Handlers::messages[] = { { WM_INITDIALOG, &PaletteEditor::OnInitDialog }, { WM_PAINT, &PaletteEditor::OnPaint }, { WM_LBUTTONDOWN, &PaletteEditor::OnLButtonDown }, { WM_HSCROLL, &PaletteEditor::OnHScroll } }; const MsgHandler::Entry PaletteEditor::Handlers::commands[] = { { IDC_PALETTE_EDITOR_HEX, &PaletteEditor::OnCmdHex }, { IDC_PALETTE_EDITOR_UNDO, &PaletteEditor::OnCmdUndo }, { IDC_PALETTE_EDITOR_REDO, &PaletteEditor::OnCmdRedo }, { IDC_PALETTE_EDITOR_RESET, &PaletteEditor::OnCmdReset }, { IDC_PALETTE_EDITOR_SAVE, &PaletteEditor::OnCmdSave }, { IDC_PALETTE_EDITOR_CUSTOM, &PaletteEditor::OnCmdMode }, { IDC_PALETTE_EDITOR_YUV, &PaletteEditor::OnCmdMode }, { IDC_PALETTE_EDITOR_RGB, &PaletteEditor::OnCmdMode } }; PaletteEditor::Settings::Settings(Nes::Video emulator) { mode = emulator.GetPalette().GetMode(); customType = emulator.GetPalette().GetCustomType(); brightness = emulator.GetBrightness(); saturation = emulator.GetSaturation(); hue = emulator.GetHue(); emulator.GetPalette().SetMode( Nes::Video::Palette::MODE_CUSTOM ); emulator.SetBrightness( Nes::Video::DEFAULT_BRIGHTNESS ); emulator.SetSaturation( Nes::Video::DEFAULT_SATURATION ); emulator.SetHue( Nes::Video::DEFAULT_HUE ); emulator.GetPalette().GetCustom( palette, customType ); } void PaletteEditor::Settings::Restore(Nes::Video emulator) const { emulator.GetPalette().SetMode( mode ); emulator.SetBrightness( brightness ); emulator.SetSaturation( saturation ); emulator.SetHue( hue ); emulator.GetPalette().SetCustom( palette, customType ); } PaletteEditor::History::History() { Reset(); } void PaletteEditor::History::Reset() { pos = 0; data[0][0] = STOP; data[LENGTH-1][0] = STOP; } void PaletteEditor::History::Add(uint index,uint color) { data[pos][0] = index; data[pos][1] = color; pos = (pos+1) & (LENGTH-1); data[pos][0] = STOP; } bool PaletteEditor::History::CanUndo() const { return data[(pos-1) & (LENGTH-1)][0] != STOP; } bool PaletteEditor::History::CanRedo() const { return data[pos][0] != STOP; } uint PaletteEditor::History::Undo(Nes::Video emulator) { NST_ASSERT( CanUndo() ); uchar palette[64][3]; emulator.GetPalette().GetCustom( palette, Nes::Video::Palette::STD_PALETTE ); pos = (pos-1) & (LENGTH-1); const uint index = data[pos][0]; std::swap( palette[index / 3][index % 3], data[pos][1] ); emulator.GetPalette().SetCustom( palette ); return index / 3; } uint PaletteEditor::History::Redo(Nes::Video emulator) { NST_ASSERT( CanRedo() ); uchar palette[64][3]; emulator.GetPalette().GetCustom( palette, Nes::Video::Palette::STD_PALETTE ); const uint index = data[pos][0]; std::swap( palette[index / 3][index % 3], data[pos][1] ); pos = (pos+1) & (LENGTH-1); emulator.GetPalette().SetCustom( palette ); return index / 3; } PaletteEditor::PaletteEditor(Nes::Video& e,const Managers::Paths& p,const Path& d) : dialog (IDD_PALETTE_EDITOR,this,Handlers::messages,Handlers::commands), colorSelect (0), emulator (e), paths (p), path (d), sliderDragging (false), settings (e) { } PaletteEditor::~PaletteEditor() { settings.Restore( emulator ); } ibool PaletteEditor::OnInitDialog(Param&) { for (uint i=0; i < 3; ++i) dialog.Slider( IDC_PALETTE_EDITOR_R_SLIDER+i ).SetRange( 0, 255 ); dialog.RadioButton( IDC_PALETTE_EDITOR_CUSTOM ).Check(); dialog.CheckBox( IDC_PALETTE_EDITOR_HEX ).Check( showHex ); UpdateMode( true ); UpdateColors(); return true; } ibool PaletteEditor::OnPaint(Param&) { UpdateColors(); return false; } void PaletteEditor::UpdateColors() { if (HDC const hdc = ::GetDC( dialog )) { class Bitmap : BITMAPINFO { RGBQUAD nesColor; uchar pixels[BMP_COLOR_WIDTH * BMP_COLOR_HEIGHT]; public: Bitmap() { std::memset( this, 0, sizeof(*this) ); bmiHeader.biSize = sizeof(bmiHeader); bmiHeader.biWidth = BMP_COLOR_WIDTH; bmiHeader.biHeight = BMP_COLOR_HEIGHT; bmiHeader.biPlanes = 1; bmiHeader.biBitCount = 8; bmiHeader.biCompression = BI_RGB; for (uint y=BMP_COLOR_WIDTH+1; y < BMP_COLOR_WIDTH * (BMP_COLOR_HEIGHT-2); y += BMP_COLOR_WIDTH) std::memset( pixels + y, 1, BMP_COLOR_WIDTH-2 ); } void Draw(HDC const hdc,const uchar (*NST_RESTRICT palette)[3],const uint selected) { const RGBQUAD selectColors[2] = { {BMP_COLOR_UNSELECT,BMP_COLOR_UNSELECT,BMP_COLOR_UNSELECT,0}, {BMP_COLOR_SELECT,BMP_COLOR_SELECT,BMP_COLOR_SELECT,0} }; for (uint y=0; y < BMP_COLUMNS; ++y) { for (uint x=0; x < BMP_ROWS; ++x) { const uint index = y * BMP_ROWS + x; *bmiColors = selectColors[selected == index]; nesColor.rgbRed = palette[index][0]; nesColor.rgbGreen = palette[index][1]; nesColor.rgbBlue = palette[index][2]; ::SetDIBitsToDevice ( hdc, BMP_START_X + x * BMP_COLOR_WIDTH, BMP_START_Y + y * BMP_COLOR_HEIGHT, BMP_COLOR_WIDTH, BMP_COLOR_HEIGHT, 0, 0, 0, BMP_COLOR_HEIGHT, &pixels, this, DIB_RGB_COLORS ); } } } }; Bitmap bitmap; bitmap.Draw( hdc, emulator.GetPalette().GetColors(), colorSelect ); ::ReleaseDC( dialog, hdc ); Application::Instance::GetMainWindow().Redraw(); } } ibool PaletteEditor::OnLButtonDown(Param& param) { const Point point( LOWORD(param.lParam), HIWORD(param.lParam) ); if (point.x >= BMP_START_X && point.x < BMP_END_X && point.y >= BMP_START_Y && point.y < BMP_END_Y) { colorSelect = ((point.y-BMP_START_Y) / BMP_COLOR_HEIGHT * BMP_ROWS) + ((point.x-BMP_START_X) / BMP_COLOR_WIDTH); UpdateColor(); UpdateColors(); return true; } return true; } ibool PaletteEditor::OnHScroll(Param& param) { switch (uint index = param.Slider().GetId()) { case IDC_PALETTE_EDITOR_R_SLIDER: case IDC_PALETTE_EDITOR_G_SLIDER: case IDC_PALETTE_EDITOR_B_SLIDER: { index -= IDC_PALETTE_EDITOR_R_SLIDER; const uint color = dialog.Slider( IDC_PALETTE_EDITOR_R_SLIDER+index ).Position(); const uchar (*NST_RESTRICT colors)[3] = emulator.GetPalette().GetColors(); if (color != colors[colorSelect][index]) { if (!sliderDragging) { sliderDragging = true; history.Add( colorSelect * 3 + index, colors[colorSelect][index] ); } if (showHex) dialog.Control( IDC_PALETTE_EDITOR_R_VALUE+index ).Text() << HexString( 8, color, true ).Ptr(); else dialog.Control( IDC_PALETTE_EDITOR_R_VALUE+index ).Text() << color; { uchar custom[64][3]; std::memcpy( custom, colors, 64 * 3 ); custom[colorSelect][index] = color; emulator.GetPalette().SetCustom( custom ); } UpdateColors(); } if (sliderDragging && param.Slider().Released()) { sliderDragging = false; dialog.Control( IDC_PALETTE_EDITOR_REDO ).Disable(); dialog.Control( IDC_PALETTE_EDITOR_UNDO ).Enable(); } break; } } return true; } ibool PaletteEditor::OnCmdHex(Param& param) { if (param.Button().Clicked()) { showHex = dialog.CheckBox( IDC_PALETTE_EDITOR_HEX ).Checked(); UpdateColor(); } return true; } ibool PaletteEditor::OnCmdUndo(Param& param) { if (param.Button().Clicked()) { colorSelect = history.Undo( emulator ); dialog.Control( IDC_PALETTE_EDITOR_REDO ).Enable(); dialog.Control( IDC_PALETTE_EDITOR_UNDO ).Enable( history.CanUndo() ); UpdateColor(); UpdateColors(); } return true; } ibool PaletteEditor::OnCmdRedo(Param& param) { if (param.Button().Clicked()) { colorSelect = history.Redo( emulator ); dialog.Control( IDC_PALETTE_EDITOR_UNDO ).Enable(); dialog.Control( IDC_PALETTE_EDITOR_REDO ).Enable( history.CanRedo() ); UpdateColor(); UpdateColors(); } return true; } ibool PaletteEditor::OnCmdReset(Param& param) { if (param.Button().Clicked()) { history.Reset(); emulator.GetPalette().SetCustom( settings.palette ); UpdateMode( true ); } return true; } ibool PaletteEditor::OnCmdSave(Param& param) { if (param.Button().Clicked()) { const Path tmp( paths.BrowseSave( Managers::Paths::File::PALETTE, Managers::Paths::SUGGEST, path ) ); if (tmp.Length()) { uchar emphPalette[8*64][3]; const uchar (*palette)[3]; if ( settings.customType == Nes::Video::Palette::EXT_PALETTE && emulator.GetPalette().GetMode() == Nes::Video::Palette::MODE_CUSTOM && User::Confirm( IDS_VIDEO_PALETTE_SAVE_EMPH ) ) { std::memcpy( emphPalette, emulator.GetPalette().GetColors(), 1*64*3 ); std::memcpy( emphPalette + 64, settings.palette+64, 7*64*3 ); palette = emphPalette; } else { palette = emulator.GetPalette().GetColors(); } paths.Save ( palette, palette == emphPalette ? 8*64*3 : 1*64*3, Managers::Paths::File::PALETTE, tmp ); path = tmp; dialog.Close(); } } return true; } ibool PaletteEditor::OnCmdMode(Param& param) { if (param.Button().Clicked()) UpdateMode(); return true; } void PaletteEditor::UpdateMode(const bool forceUpdate) { Nes::Video::Palette::Mode mode; if (dialog.RadioButton(IDC_PALETTE_EDITOR_CUSTOM).Checked()) { mode = Nes::Video::Palette::MODE_CUSTOM; } else if (dialog.RadioButton(IDC_PALETTE_EDITOR_YUV).Checked()) { mode = Nes::Video::Palette::MODE_YUV; } else { mode = Nes::Video::Palette::MODE_RGB; } if (emulator.GetPalette().SetMode( mode ) != Nes::RESULT_NOP || forceUpdate) { const bool custom = (mode == Nes::Video::Palette::MODE_CUSTOM); for (uint i=0; i < 3; ++i) dialog.Slider( IDC_PALETTE_EDITOR_R_SLIDER+i ).Enable( custom ); dialog.Control( IDC_PALETTE_EDITOR_UNDO ).Enable( custom && history.CanUndo() ); dialog.Control( IDC_PALETTE_EDITOR_REDO ).Enable( custom && history.CanRedo() ); dialog.Control( IDC_PALETTE_EDITOR_RESET ).Enable( custom ); UpdateColor(); UpdateColors(); } } void PaletteEditor::UpdateColor() { if (showHex) dialog.Edit( IDC_PALETTE_EDITOR_INDEX ) << HexString( 8, colorSelect, true ).Ptr(); else dialog.Edit( IDC_PALETTE_EDITOR_INDEX ) << colorSelect; const uchar (&colors)[3] = emulator.GetPalette().GetColors()[colorSelect]; for (uint i=0; i < 3; ++i) { const uint color = colors[i]; dialog.Slider( IDC_PALETTE_EDITOR_R_SLIDER+i ).Position() = color; if (showHex) dialog.Control( IDC_PALETTE_EDITOR_R_VALUE+i ).Text() << HexString( 8, color, true ).Ptr(); else dialog.Control( IDC_PALETTE_EDITOR_R_VALUE+i ).Text() << color; } } } } nestopia-1.51.1/source/win32/NstDialogPaletteEditor.hpp000066400000000000000000000056431411157722000227560ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIALOG_PALETTEEDITOR_H #define NST_DIALOG_PALETTEEDITOR_H #pragma once #include "NstWindowDialog.hpp" namespace Nestopia { namespace Window { class PaletteEditor { public: PaletteEditor(Nes::Video&,const Managers::Paths&,const Path&); ~PaletteEditor(); private: struct Handlers; enum { BMP_START_X = 8, BMP_START_Y = 8, BMP_COLOR_WIDTH = 24, BMP_COLOR_HEIGHT = 24, BMP_ROWS = 16, BMP_COLUMNS = 4, BMP_END_X = BMP_START_X + BMP_COLOR_WIDTH * BMP_ROWS, BMP_END_Y = BMP_START_Y + BMP_COLOR_HEIGHT * BMP_COLUMNS, BMP_COLOR_SELECT = 0xFF, BMP_COLOR_UNSELECT = 0x50 }; struct Settings { explicit Settings(Nes::Video); void Restore(Nes::Video) const; Nes::Video::Palette::Mode mode; Nes::Video::Palette::CustomType customType; uint brightness; uint saturation; uint hue; uchar palette[8*64][3]; }; class History { public: History(); void Reset(); void Add(uint,uint); bool CanUndo() const; bool CanRedo() const; uint Undo(Nes::Video); uint Redo(Nes::Video); private: enum { LENGTH = 128, STOP = 0xFF }; uint pos; uchar data[LENGTH][2]; }; void UpdateMode(bool=false); void UpdateColor(); void UpdateColors(); ibool OnInitDialog (Param&); ibool OnPaint (Param&); ibool OnLButtonDown (Param&); ibool OnHScroll (Param&); ibool OnCmdHex (Param&); ibool OnCmdUndo (Param&); ibool OnCmdRedo (Param&); ibool OnCmdReset (Param&); ibool OnCmdSave (Param&); ibool OnCmdMode (Param&); Dialog dialog; uint colorSelect; Nes::Video emulator; const Managers::Paths& paths; Path path; ibool sliderDragging; History history; const Settings settings; static bool showHex; public: const Path& Open() { dialog.Open(); return path; } }; } } #endif nestopia-1.51.1/source/win32/NstDialogPaths.cpp000066400000000000000000000322541411157722000212610ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstResourceString.hpp" #include "NstApplicationInstance.hpp" #include "NstWindowParam.hpp" #include "NstWindowUser.hpp" #include "NstDialogPaths.hpp" #include "NstDialogBrowse.hpp" namespace Nestopia { namespace Window { NST_COMPILE_ASSERT ( IDC_PATHS_BATTERY - IDC_PATHS_IMAGE == IDC_PATHS_BATTERY_BROWSE - IDC_PATHS_IMAGE_BROWSE && IDC_PATHS_NST - IDC_PATHS_IMAGE == IDC_PATHS_NST_BROWSE - IDC_PATHS_IMAGE_BROWSE && IDC_PATHS_SAMPLES - IDC_PATHS_IMAGE == IDC_PATHS_SAMPLES_BROWSE - IDC_PATHS_IMAGE_BROWSE && IDC_PATHS_CHEATS - IDC_PATHS_IMAGE == IDC_PATHS_CHEATS_BROWSE - IDC_PATHS_IMAGE_BROWSE && IDC_PATHS_PATCHES - IDC_PATHS_IMAGE == IDC_PATHS_PATCHES_BROWSE - IDC_PATHS_IMAGE_BROWSE && IDC_PATHS_SCREENSHOTS - IDC_PATHS_IMAGE == IDC_PATHS_SCREENSHOTS_BROWSE - IDC_PATHS_IMAGE_BROWSE ); struct Paths::Lut { struct A { ushort type; ushort dlg; wcstring def; }; struct B { ushort type; ushort dlg; }; struct C { ushort type; ushort dlg; wcstring cfg; }; static const A dirs[NUM_DIRS]; static const B flags[NUM_FLAGS]; static const C screenShots[NUM_SCREENSHOTS]; }; const Paths::Lut::A Paths::Lut::dirs[NUM_DIRS] = { { DIR_IMAGE, IDC_PATHS_IMAGE, L"" }, { DIR_SAVE, IDC_PATHS_BATTERY, L"save\\" }, { DIR_STATE, IDC_PATHS_NST, L"states\\" }, { DIR_SAMPLES, IDC_PATHS_SAMPLES, L"samples\\" }, { DIR_CHEATS, IDC_PATHS_CHEATS, L"cheats\\" }, { DIR_PATCHES, IDC_PATHS_PATCHES, L"patches\\" }, { DIR_SCREENSHOT, IDC_PATHS_SCREENSHOTS, L"screenshots\\" } }; const Paths::Lut::B Paths::Lut::flags[NUM_FLAGS] = { { USE_LAST_IMAGE_DIR, IDC_PATHS_IMAGE_LAST }, { READONLY_CARTRIDGE, IDC_PATHS_BATTERY_PROTECT }, { AUTO_IMPORT_STATE_SLOTS, IDC_PATHS_NST_AUTO_IMPORT }, { AUTO_EXPORT_STATE_SLOTS, IDC_PATHS_NST_AUTO_EXPORT }, { CHEATS_AUTO_LOAD, IDC_PATHS_CHEATS_AUTO_LOAD }, { CHEATS_AUTO_SAVE, IDC_PATHS_CHEATS_AUTO_SAVE }, { PATCH_AUTO_APPLY, IDC_PATHS_PATCHES_AUTO_APPLY }, { PATCH_BYPASS_VALIDATION, IDC_PATHS_PATCHES_BYPASS_VALIDATION }, { COMPRESS_STATES, IDC_PATHS_NST_COMPRESS } }; const Paths::Lut::C Paths::Lut::screenShots[NUM_SCREENSHOTS] = { { SCREENSHOT_PNG, IDC_PATHS_SCREENSHOTS_PNG, L"png" }, { SCREENSHOT_JPEG, IDC_PATHS_SCREENSHOTS_JPEG, L"jpg" }, { SCREENSHOT_BMP, IDC_PATHS_SCREENSHOTS_BMP, L"bmp" } }; struct Paths::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; }; const MsgHandler::Entry Paths::Handlers::messages[] = { { WM_INITDIALOG, &Paths::OnInitDialog } }; const MsgHandler::Entry Paths::Handlers::commands[] = { { IDC_PATHS_IMAGE_BROWSE, &Paths::OnCmdBrowse }, { IDC_PATHS_BATTERY_BROWSE, &Paths::OnCmdBrowse }, { IDC_PATHS_NST_BROWSE, &Paths::OnCmdBrowse }, { IDC_PATHS_SAMPLES_BROWSE, &Paths::OnCmdBrowse }, { IDC_PATHS_CHEATS_BROWSE, &Paths::OnCmdBrowse }, { IDC_PATHS_PATCHES_BROWSE, &Paths::OnCmdBrowse }, { IDC_PATHS_SCREENSHOTS_BROWSE, &Paths::OnCmdBrowse }, { IDC_PATHS_IMAGE_LAST, &Paths::OnCmdLastVisited }, { IDC_PATHS_DEFAULT, &Paths::OnCmdDefault }, { IDOK, &Paths::OnCmdOk } }; inline Paths::Settings::Flags::Flags() : Collection::BitSet ( 1U << USE_LAST_IMAGE_DIR | 1U << AUTO_IMPORT_STATE_SLOTS | 1U << AUTO_EXPORT_STATE_SLOTS | 1U << COMPRESS_STATES ) {} Paths::Settings::Settings() : screenShotFormat(SCREENSHOT_PNG) {} Paths::Paths(const Configuration& cfg) : dialog(IDD_PATHS,this,Handlers::messages,Handlers::commands) { Configuration::ConstSection paths( cfg["paths"] ); { Configuration::ConstSection images( paths["images"] ); settings.dirs[DIR_IMAGE] = images["directory"].Str(); if (images["use-recent-directory"].Yes()) { settings.flags[USE_LAST_IMAGE_DIR] = true; } else if (images["use-recent-directory"].No()) { settings.flags[USE_LAST_IMAGE_DIR] = false; } } { Configuration::ConstSection saves( paths["saves"] ); settings.dirs[DIR_SAVE] = saves["directory"].Str(); if (saves["force-read-only"].Yes()) { settings.flags[READONLY_CARTRIDGE] = true; } else if (saves["force-read-only"].No()) { settings.flags[READONLY_CARTRIDGE] = false; } } { Configuration::ConstSection states( paths["states"] ); settings.dirs[DIR_STATE] = states["directory"].Str(); if (states["use-compression"].Yes()) { settings.flags[COMPRESS_STATES] = true; } else if (states["use-compression"].No()) { settings.flags[COMPRESS_STATES] = false; } if (states["auto-import"].Yes()) { settings.flags[AUTO_IMPORT_STATE_SLOTS] = true; } else if (states["auto-import"].No()) { settings.flags[AUTO_IMPORT_STATE_SLOTS] = false; } if (states["auto-export"].Yes()) { settings.flags[AUTO_EXPORT_STATE_SLOTS] = true; } else if (states["auto-export"].No()) { settings.flags[AUTO_EXPORT_STATE_SLOTS] = false; } } { Configuration::ConstSection samples( paths["samples"] ); settings.dirs[DIR_SAMPLES] = samples["directory"].Str(); } { Configuration::ConstSection patches( paths["cheats"] ); settings.dirs[DIR_CHEATS] = patches["directory"].Str(); if (patches["auto-load"].Yes()) { settings.flags[CHEATS_AUTO_LOAD] = true; } else if (patches["auto-load"].No()) { settings.flags[CHEATS_AUTO_LOAD] = false; } if (patches["auto-save"].Yes()) { settings.flags[CHEATS_AUTO_SAVE] = true; } else if (patches["auto-save"].No()) { settings.flags[CHEATS_AUTO_SAVE] = false; } } { Configuration::ConstSection patches( paths["patches"] ); settings.dirs[DIR_PATCHES] = patches["directory"].Str(); if (patches["auto-apply"].Yes()) { settings.flags[PATCH_AUTO_APPLY] = true; } else if (patches["auto-apply"].No()) { settings.flags[PATCH_AUTO_APPLY] = false; } if (patches["bypass-validation"].Yes()) { settings.flags[PATCH_BYPASS_VALIDATION] = true; } else if (patches["bypass-validation"].No()) { settings.flags[PATCH_BYPASS_VALIDATION] = false; } } { Configuration::ConstSection screenshots( paths["screenshots"] ); settings.dirs[DIR_SCREENSHOT] = screenshots["directory"].Str(); const GenericString format( screenshots["format"].Str() ); if (format.Length()) { for (uint i=0; i < NUM_SCREENSHOTS; ++i) { if (format == Lut::screenShots[i].cfg) { settings.screenShotFormat = static_cast(Lut::screenShots[i].type); break; } } } } for (uint i=0; i < NUM_DIRS; ++i) UpdateDirectory( i ); } Paths::~Paths() { } void Paths::Save(Configuration& cfg) const { Configuration::Section paths( cfg["paths"] ); { Configuration::Section images( paths["images"] ); images[ "directory" ].Str() = settings.dirs[DIR_IMAGE]; images[ "use-recent-directory" ].YesNo() = settings.flags[USE_LAST_IMAGE_DIR]; } { Configuration::Section saves( paths["saves"] ); saves[ "directory" ].Str() = settings.dirs[DIR_SAVE]; saves[ "force-read-only" ].YesNo() = settings.flags[READONLY_CARTRIDGE]; } { Configuration::Section states( paths["states"] ); states[ "directory" ].Str() = settings.dirs[DIR_STATE]; states[ "use-compression" ].YesNo() = settings.flags[COMPRESS_STATES]; states[ "auto-import" ].YesNo() = settings.flags[AUTO_IMPORT_STATE_SLOTS]; states[ "auto-export" ].YesNo() = settings.flags[AUTO_EXPORT_STATE_SLOTS]; } { Configuration::Section samples( paths["samples"] ); samples[ "directory" ].Str() = settings.dirs[DIR_SAMPLES]; } { Configuration::Section patches( paths["cheats"] ); patches[ "directory" ].Str() = settings.dirs[DIR_CHEATS]; patches[ "auto-load" ].YesNo() = settings.flags[CHEATS_AUTO_LOAD]; patches[ "auto-save" ].YesNo() = settings.flags[CHEATS_AUTO_SAVE]; } { Configuration::Section patches( paths["patches"] ); patches[ "directory" ].Str() = settings.dirs[DIR_PATCHES]; patches[ "auto-apply" ].YesNo() = settings.flags[PATCH_AUTO_APPLY]; patches[ "bypass-validation" ].YesNo() = settings.flags[PATCH_BYPASS_VALIDATION]; } { Configuration::Section screenshots( paths["screenshots"] ); screenshots[ "directory" ].Str() = settings.dirs[DIR_SCREENSHOT]; screenshots[ "format" ].Str() = Lut::screenShots[settings.screenShotFormat].cfg; } } const GenericString Paths::GetScreenShotExtension() const { switch (settings.screenShotFormat) { case SCREENSHOT_JPEG: return L"jpg"; case SCREENSHOT_BMP: return L"bmp"; default: return L"png"; } } const Path Paths::GetDirectory(Type type) const { return Application::Instance::GetFullPath( settings.dirs[type] ); } void Paths::UpdateDirectory(const uint i) { Path def( Application::Instance::GetExePath(Lut::dirs[i].def) ); Path& dir = settings.dirs[Lut::dirs[i].type]; bool useDef; if (dir.Length()) { dir.MakePretty( true ); useDef = (dir == def); } else { dir = def; useDef = true; } def = Application::Instance::GetFullPath( dir ); if (::GetFileAttributes( def.Ptr() ) == INVALID_FILE_ATTRIBUTES) { if (useDef || User::Confirm( Resource::String(IDS_FILE_ASK_CREATE_DIR).Invoke(def) )) { if (!::CreateDirectory( def.Ptr(), NULL )) { if (useDef) dir = Application::Instance::GetExePath().Directory(); else User::Fail( IDS_FILE_ERR_CREATE_DIR ); } } } } void Paths::Update(const bool reset) const { for (uint i=0; i < NUM_DIRS; ++i) dialog.Edit( Lut::dirs[i].dlg ) << (reset ? Application::Instance::GetExePath(Lut::dirs[i].def).Ptr() : settings.dirs[Lut::dirs[i].type].Ptr()); Settings::Flags flags; if (!reset) flags = settings.flags; for (uint i=0; i < NUM_FLAGS; ++i) dialog.CheckBox( Lut::flags[i].dlg ).Check( flags[Lut::flags[i].type] ); ScreenShotFormat screenShotFormat = SCREENSHOT_PNG; if (!reset) screenShotFormat = settings.screenShotFormat; for (uint i=0; i < NUM_SCREENSHOTS; ++i) dialog.RadioButton( Lut::screenShots[i].dlg ).Check( Lut::screenShots[i].type == screenShotFormat ); UpdateLastVisited(); } void Paths::UpdateLastVisited() const { bool unchecked = dialog.CheckBox( IDC_PATHS_IMAGE_LAST ).Unchecked(); dialog.Control( IDC_PATHS_IMAGE ).Enable( unchecked ); dialog.Control( IDC_PATHS_IMAGE_BROWSE ).Enable( unchecked ); } ibool Paths::OnInitDialog(Param&) { Update( false ); return true; } ibool Paths::OnCmdDefault(Param& param) { if (param.Button().Clicked()) Update( true ); return true; } ibool Paths::OnCmdBrowse(Param& param) { if (param.Button().Clicked()) { const uint id = IDC_PATHS_IMAGE + (param.Button().GetId() - IDC_PATHS_IMAGE_BROWSE); dialog.Edit( id ).Try() << Browser::SelectDirectory().Ptr(); } return true; } ibool Paths::OnCmdLastVisited(Param& param) { if (param.Button().Clicked()) UpdateLastVisited(); return true; } ibool Paths::OnCmdOk(Param& param) { if (param.Button().Clicked()) { for (uint i=0; i < NUM_DIRS; ++i) { dialog.Edit( Lut::dirs[i].dlg ) >> settings.dirs[Lut::dirs[i].type]; UpdateDirectory( i ); } for (uint i=0; i < NUM_FLAGS; ++i) settings.flags[Lut::flags[i].type] = dialog.CheckBox( Lut::flags[i].dlg ).Checked(); for (uint i=0; i < NUM_SCREENSHOTS; ++i) { if (dialog.RadioButton( Lut::screenShots[i].dlg ).Checked()) { settings.screenShotFormat = static_cast(Lut::screenShots[i].type); break; } } dialog.Close(); } return true; } } } nestopia-1.51.1/source/win32/NstDialogPaths.hpp000066400000000000000000000054021411157722000212610ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIALOG_PATHS_H #define NST_DIALOG_PATHS_H #pragma once #include "NstCollectionBitSet.hpp" #include "NstWindowDialog.hpp" namespace Nestopia { namespace Window { class Paths { public: enum Type { DIR_IMAGE, DIR_SAVE, DIR_STATE, DIR_SAMPLES, DIR_CHEATS, DIR_PATCHES, DIR_SCREENSHOT }; enum ScreenShotFormat { SCREENSHOT_PNG, SCREENSHOT_JPEG, SCREENSHOT_BMP }; enum { NUM_DIRS = DIR_SCREENSHOT + 1, NUM_SCREENSHOTS = SCREENSHOT_BMP + 1 }; enum { USE_LAST_IMAGE_DIR, READONLY_CARTRIDGE, AUTO_IMPORT_STATE_SLOTS, AUTO_EXPORT_STATE_SLOTS, CHEATS_AUTO_LOAD, CHEATS_AUTO_SAVE, PATCH_AUTO_APPLY, PATCH_BYPASS_VALIDATION, COMPRESS_STATES, NUM_FLAGS }; explicit Paths(const Configuration&); ~Paths(); void Save(Configuration&) const; const GenericString GetScreenShotExtension() const; const Path GetDirectory(Type) const; private: struct Handlers; struct Settings { Settings(); struct Flags : Collection::BitSet { inline Flags(); }; Flags flags; Path dirs[NUM_DIRS]; ScreenShotFormat screenShotFormat; }; void Update(bool) const; void UpdateDirectory(uint); void UpdateLastVisited() const; ibool OnInitDialog (Param&); ibool OnCmdBrowse (Param&); ibool OnCmdLastVisited (Param&); ibool OnCmdDefault (Param&); ibool OnCmdOk (Param&); Settings settings; Dialog dialog; struct Lut; public: void Open() { dialog.Open(); } bool GetSetting(uint flag) const { return settings.flags[flag]; } ScreenShotFormat GetScreenShotFormat() const { return settings.screenShotFormat; } }; } } #endif nestopia-1.51.1/source/win32/NstDialogPreferences.cpp000066400000000000000000000572411411157722000224460ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "resource/resource.h" #include "NstObjectPod.hpp" #include "NstSystemRegistry.hpp" #include "NstWindowUser.hpp" #include "NstApplicationInstance.hpp" #include "NstWindowParam.hpp" #include "NstManagerEmulator.hpp" #include "NstDialogPreferences.hpp" #include "NstIoLog.hpp" #include "NstResourceString.hpp" #include namespace Nestopia { namespace Window { NST_COMPILE_ASSERT ( IDC_PREFERENCES_ASSOCIATE_UNF == IDC_PREFERENCES_ASSOCIATE_NES + 1 && IDC_PREFERENCES_ASSOCIATE_FDS == IDC_PREFERENCES_ASSOCIATE_NES + 2 && IDC_PREFERENCES_ASSOCIATE_NSF == IDC_PREFERENCES_ASSOCIATE_NES + 3 ); NST_COMPILE_ASSERT ( IDS_PRIORITY_ABOVE_NORMAL == IDS_PRIORITY_NORMAL + 1 && IDS_PRIORITY_HIGH == IDS_PRIORITY_NORMAL + 2 ); struct Preferences::MenuColorWindow { COLORREF color; Rect rect; }; Preferences::MenuColorWindow Preferences::menuColorWindows[2]; class Preferences::Association { public: enum { NUM_EXTENSIONS = 4 }; explicit Association(bool=false); ~Association(); void Create(uint,uint); void Delete(uint); void Update(uint,uint); bool Enabled(uint) const; private: enum { EXTENSION, NAME, DESCRIPTION, NUM_KEYTYPES }; System::Registry registry; bool refresh; bool updated; const bool notify; static wcstring const keyNames[NUM_EXTENSIONS][NUM_KEYTYPES]; }; wcstring const Preferences::Association::keyNames[NUM_EXTENSIONS][NUM_KEYTYPES] = { { L".nes", L"Nestopia.nes", L"Nestopia iNES File" }, { L".unf", L"Nestopia.unf", L"Nestopia UNIF File" }, { L".fds", L"Nestopia.fds", L"Nestopia Famicom Disk System File" }, { L".nsf", L"Nestopia.nsf", L"Nestopia NES Sound File" } }; Preferences::Association::Association(bool n) : refresh(false), updated(false), notify(n) {} Preferences::Association::~Association() { if (refresh) System::Registry::UpdateAssociations(); if (notify && updated) { User::Inform ( IDS_DIALOG_PREFERENCES_REGISTRYUPDATED, IDS_DIALOG_PREFERENCES_REGISTRYUPDATED_TITLE ); } } bool Preferences::Association::Enabled(uint index) const { HeapString tmp; return (registry[keyNames[index][EXTENSION]] >> tmp) && (tmp == keyNames[index][NAME]); } void Preferences::Association::Update(const uint index,const uint icon) { if (Enabled( index )) { HeapString path( Application::Instance::GetExePath() ); // "nestopia.extension\DefaultIcon" <- "drive:\directory\nestopia.exe,icon" if (registry[keyNames[index][NAME]][L"DefaultIcon"] << (path << ',' << icon)) { refresh = true; updated = true; } path.ShrinkTo( Application::Instance::GetExePath().Length() ); // "nestopia.extension\Shell\Open\Command" <- "drive:\directory\nestopia.exe "%1" if (registry[keyNames[index][NAME]][L"Shell\\Open\\Command"] << (path << " \"%1\"")) updated = true; } } void Preferences::Association::Create(const uint index,const uint icon) { // ".extension" will point to "nestopia.extension" const bool tmp = updated; updated = false; if (registry[keyNames[index][EXTENSION]] << keyNames[index][NAME]) updated = true; if (registry[keyNames[index][NAME]] << keyNames[index][DESCRIPTION]) updated = true; Update( index, icon ); if (updated) { Io::Log() << "Preferences: creating registry keys: \"HKEY_CLASSES_ROOT\\" << keyNames[index][EXTENSION] << "\" and \"HKEY_CLASSES_ROOT\\" << keyNames[index][NAME] << "\"..\r\n"; } else { updated = tmp; } } void Preferences::Association::Delete(const uint index) { bool log = false; // remove ".extension" (if default) and "nestopia.extension" if (registry[keyNames[index][EXTENSION]].Delete( keyNames[index][NAME] )) refresh = updated = log = true; if (registry[keyNames[index][NAME]].Delete()) updated = log = true; if (log) { Io::Log() << "Preferences: deleting registry keys: \"HKEY_CLASSES_ROOT\\" << keyNames[index][EXTENSION] << "\" and \"HKEY_CLASSES_ROOT\\" << keyNames[index][NAME] << "\"..\r\n"; } } const ushort Preferences::icons[Preferences::Association::NUM_EXTENSIONS][5] = { { IDC_PREFERENCES_ICON_NES, IDI_NES, IDI_NES_J, 2, 3 }, { IDC_PREFERENCES_ICON_UNF, IDI_UNF, IDI_UNF_J, 4, 5 }, { IDC_PREFERENCES_ICON_FDS, IDI_FDS, IDI_FDS, 6, 6 }, { IDC_PREFERENCES_ICON_NSF, IDI_NSF, IDI_NSF_J, 7, 8 } }; struct Preferences::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; }; const MsgHandler::Entry Preferences::Handlers::messages[] = { { WM_INITDIALOG, &Preferences::OnInitDialog }, { WM_PAINT, &Preferences::OnPaint } }; const MsgHandler::Entry Preferences::Handlers::commands[] = { { IDC_PREFERENCES_STYLE_NES, &Preferences::OnCmdStyle }, { IDC_PREFERENCES_STYLE_FAMICOM, &Preferences::OnCmdStyle }, { IDC_PREFERENCES_MENUCOLOR_DESKTOP_CHANGE, &Preferences::OnCmdMenuColorChange }, { IDC_PREFERENCES_MENUCOLOR_FULLSCREEN_CHANGE, &Preferences::OnCmdMenuColorChange }, { IDC_PREFERENCES_MENUCOLOR_DESKTOP_DEFAULT, &Preferences::OnCmdMenuColorDefault }, { IDC_PREFERENCES_MENUCOLOR_FULLSCREEN_DEFAULT, &Preferences::OnCmdMenuColorDefault }, { IDC_PREFERENCES_DEFAULT, &Preferences::OnCmdDefault }, { IDOK, &Preferences::OnCmdOk } }; Preferences::Preferences(Managers::Emulator& e,const Configuration& cfg) : dialog ( IDD_PREFERENCES, this, Handlers::messages, Handlers::commands ), emulator ( e ) { NST_COMPILE_ASSERT ( START_IN_FULLSCREEN == IDC_PREFERENCES_STARTUP_FULLSCREEN - IDC_PREFERENCES_STARTUP_FULLSCREEN && SUPPRESS_WARNINGS == IDC_PREFERENCES_DISABLE_ROM_WARNINGS - IDC_PREFERENCES_STARTUP_FULLSCREEN && FIRST_UNLOAD_ON_EXIT == IDC_PREFERENCES_CLOSE_POWER_OFF - IDC_PREFERENCES_STARTUP_FULLSCREEN && CONFIRM_EXIT == IDC_PREFERENCES_CONFIRM_EXIT - IDC_PREFERENCES_STARTUP_FULLSCREEN && RUN_IN_BACKGROUND == IDC_PREFERENCES_RUN_IN_BACKGROUND - IDC_PREFERENCES_STARTUP_FULLSCREEN && AUTOSTART_EMULATION == IDC_PREFERENCES_BEGIN_EMULATION - IDC_PREFERENCES_STARTUP_FULLSCREEN && SAVE_LOGFILE == IDC_PREFERENCES_SAVE_LOGFILE - IDC_PREFERENCES_STARTUP_FULLSCREEN && ALLOW_MULTIPLE_INSTANCES == IDC_PREFERENCES_MULTIPLE_INSTANCES - IDC_PREFERENCES_STARTUP_FULLSCREEN && SAVE_LAUNCHER == IDC_PREFERENCES_SAVE_LAUNCHER - IDC_PREFERENCES_STARTUP_FULLSCREEN && CONFIRM_RESET == IDC_PREFERENCES_CONFIRM_RESET - IDC_PREFERENCES_STARTUP_FULLSCREEN && SAVE_CHEATS == IDC_PREFERENCES_SAVE_CHEATCODES - IDC_PREFERENCES_STARTUP_FULLSCREEN && SAVE_NETPLAY_GAMELIST == IDC_PREFERENCES_SAVE_NETPLAY_GAMELIST - IDC_PREFERENCES_STARTUP_FULLSCREEN && SAVE_WINDOWPOS == IDC_PREFERENCES_SAVE_WINDOWPOS - IDC_PREFERENCES_STARTUP_FULLSCREEN && SAVE_LAUNCHERSIZE == IDC_PREFERENCES_SAVE_LAUNCHERSIZE - IDC_PREFERENCES_STARTUP_FULLSCREEN ); Configuration::ConstSection preferences( cfg["preferences"] ); { Configuration::ConstSection application( preferences["application"] ); settings[ AUTOSTART_EMULATION ] = !application[ "autostart" ].No(); settings[ RUN_IN_BACKGROUND ] = application[ "run-background" ].Yes(); settings[ START_IN_FULLSCREEN ] = application[ "start-fullscreen" ].Yes(); settings[ SUPPRESS_WARNINGS ] = application[ "suppress-warnings" ].Yes(); settings[ FIRST_UNLOAD_ON_EXIT ] = application[ "exit-power-off" ].Yes(); settings[ CONFIRM_EXIT ] = !application[ "confirm-exit" ].No(); settings[ CONFIRM_RESET ] = application[ "confirm-reset" ].Yes(); settings[ ALLOW_MULTIPLE_INSTANCES ] = application[ "allow-multiple-instances" ].Yes(); { const GenericString priority( application[ "priority" ].Str() ); if (priority == L"high") { settings.priority = PRIORITY_HIGH; } else if (priority == L"above normal") { settings.priority = PRIORITY_ABOVE_NORMAL; } else { settings.priority = PRIORITY_NORMAL; } } { const GenericString favored( application[ "favored-system" ].Str() ); if (favored == L"nes-pal") { settings.favoredSystem = Nes::Machine::FAVORED_NES_PAL; } else if (favored == L"famicom") { settings.favoredSystem = Nes::Machine::FAVORED_FAMICOM; } else if (favored == L"dendy") { settings.favoredSystem = Nes::Machine::FAVORED_DENDY; } else { settings.favoredSystem = Nes::Machine::FAVORED_NES_NTSC; } } settings.alwaysAskSystem = application[ "favored-system-always-ask" ].Yes(); settings.disableStatusMsg = application[ "disable-statusmsg" ].Yes(); } { Configuration::ConstSection save( preferences["save"] ); settings[ SAVE_LOGFILE ] = !save[ "logfile" ].No(); settings[ SAVE_SETTINGS ] = !save[ "settings" ].No(); settings[ SAVE_LAUNCHER ] = !save[ "launcher" ].No(); settings[ SAVE_CHEATS ] = !save[ "cheats" ].No(); settings[ SAVE_NETPLAY_GAMELIST ] = !save[ "netplay-list" ].No(); settings[ SAVE_WINDOWPOS ] = save[ "window-main" ].Yes(); settings[ SAVE_LAUNCHERSIZE ] = save[ "window-launcher" ].Yes(); } { Configuration::ConstSection appearance( preferences["appearance"] ); settings.menuLookDesktop.enabled = appearance[ "menu-desktop" ][ "use-custom-color" ].Yes(); settings.menuLookFullscreen.enabled = appearance[ "menu-fullscreen" ][ "use-custom-color" ].Yes(); settings.menuLookDesktop.color = appearance[ "menu-desktop" ][ "custom-color" ].Int( DEFAULT_DESKTOP_MENU_COLOR ); settings.menuLookFullscreen.color = appearance[ "menu-fullscreen" ][ "custom-color" ].Int( DEFAULT_FULLSCREEN_MENU_COLOR ); Application::Instance::SetIconStyle ( appearance[ "icon-style" ].Str() == L"famicom" ? Application::Instance::ICONSTYLE_FAMICOM : Application::Instance::ICONSTYLE_NES ); } Association association; const uint iconOffset = (Application::Instance::GetIconStyle() == Application::Instance::ICONSTYLE_NES ? 3 : 4); for (uint i=0; i < Association::NUM_EXTENSIONS; ++i) association.Update( i, icons[i][iconOffset] ); } void Preferences::Save(Configuration& cfg) const { Configuration::Section preferences( cfg["preferences"] ); { Configuration::Section application( preferences["application"] ); application[ "autostart" ].YesNo() = settings[ AUTOSTART_EMULATION ]; application[ "run-background" ].YesNo() = settings[ RUN_IN_BACKGROUND ]; application[ "start-fullscreen" ].YesNo() = settings[ START_IN_FULLSCREEN ]; application[ "suppress-warnings" ].YesNo() = settings[ SUPPRESS_WARNINGS ]; application[ "exit-power-off" ].YesNo() = settings[ FIRST_UNLOAD_ON_EXIT ]; application[ "confirm-exit" ].YesNo() = settings[ CONFIRM_EXIT ]; application[ "confirm-reset" ].YesNo() = settings[ CONFIRM_RESET ]; application[ "allow-multiple-instances" ].YesNo() = settings[ ALLOW_MULTIPLE_INSTANCES ]; application[ "priority" ].Str() = ( settings.priority == PRIORITY_HIGH ? "high" : settings.priority == PRIORITY_ABOVE_NORMAL ? "above normal" : "normal" ); application[ "favored-system" ].Str() = ( settings.favoredSystem == Nes::Machine::FAVORED_NES_PAL ? "nes-pal" : settings.favoredSystem == Nes::Machine::FAVORED_FAMICOM ? "famicom" : settings.favoredSystem == Nes::Machine::FAVORED_DENDY ? "dendy" : "nes-ntsc" ); application[ "favored-system-always-ask" ].YesNo() = settings.alwaysAskSystem; application[ "disable-statusmsg" ].YesNo() = settings.disableStatusMsg; } { Configuration::Section save( preferences["save"] ); save[ "logfile" ].YesNo() = settings[ SAVE_LOGFILE ]; save[ "settings" ].YesNo() = settings[ SAVE_SETTINGS ]; save[ "launcher" ].YesNo() = settings[ SAVE_LAUNCHER ]; save[ "cheats" ].YesNo() = settings[ SAVE_CHEATS ]; save[ "netplay-list" ].YesNo() = settings[ SAVE_NETPLAY_GAMELIST ]; save[ "window-main" ].YesNo() = settings[ SAVE_WINDOWPOS ]; save[ "window-launcher" ].YesNo() = settings[ SAVE_LAUNCHERSIZE ]; } { Configuration::Section appearance( preferences["appearance"] ); appearance[ "icon-style" ].Str() = ( Application::Instance::GetIconStyle() == Application::Instance::ICONSTYLE_NES ? "nes" : "famicom" ); appearance[ "menu-desktop" ][ "use-custom-color" ].YesNo() = settings.menuLookDesktop.enabled; appearance[ "menu-fullscreen" ][ "use-custom-color" ].YesNo() = settings.menuLookFullscreen.enabled; appearance[ "menu-desktop" ][ "custom-color" ].Str() = HexString( 32, settings.menuLookDesktop.color ); appearance[ "menu-fullscreen" ][ "custom-color" ].Str() = HexString( 32, settings.menuLookFullscreen.color ); } } ibool Preferences::OnInitDialog(Param&) { for (uint i=0; i < 2; ++i) { MenuColorWindow& type = menuColorWindows[i]; type.color = i ? settings.menuLookFullscreen.color : settings.menuLookDesktop.color; type.rect = dialog.Control(i ? IDC_PREFERENCES_MENUCOLOR_FULLSCREEN_CHANGE : IDC_PREFERENCES_MENUCOLOR_DESKTOP_CHANGE).GetWindow().Coordinates(); type.rect.Position() -= Point(type.rect.Width()+8,0); type.rect.ClientTransform( dialog ); } dialog.Control( IDC_PREFERENCES_MENUCOLOR_DESKTOP_CHANGE ).Enable( settings.menuLookDesktop.enabled ); dialog.Control( IDC_PREFERENCES_MENUCOLOR_FULLSCREEN_CHANGE ).Enable( settings.menuLookFullscreen.enabled ); dialog.CheckBox( IDC_PREFERENCES_MENUCOLOR_DESKTOP_DEFAULT ).Check( !settings.menuLookDesktop.enabled ); dialog.CheckBox( IDC_PREFERENCES_MENUCOLOR_FULLSCREEN_DEFAULT ).Check( !settings.menuLookFullscreen.enabled ); for (uint i=0; i < NUM_SETTINGS; ++i) { if (i != SAVE_SETTINGS) dialog.CheckBox( IDC_PREFERENCES_STARTUP_FULLSCREEN + i ).Check( settings[i] ); } { Association association; for (uint i=0; i < Association::NUM_EXTENSIONS; ++i) dialog.CheckBox( IDC_PREFERENCES_ASSOCIATE_NES + i ).Check( association.Enabled(i) ); } dialog.RadioButton( IDC_PREFERENCES_FAVORED_NES_NTSC ).Check( settings.favoredSystem == Nes::Machine::FAVORED_NES_NTSC ); dialog.RadioButton( IDC_PREFERENCES_FAVORED_NES_PAL ).Check( settings.favoredSystem == Nes::Machine::FAVORED_NES_PAL ); dialog.RadioButton( IDC_PREFERENCES_FAVORED_FAMICOM ).Check( settings.favoredSystem == Nes::Machine::FAVORED_FAMICOM ); dialog.RadioButton( IDC_PREFERENCES_FAVORED_DENDY ).Check( settings.favoredSystem == Nes::Machine::FAVORED_DENDY ); dialog.CheckBox( IDC_PREFERENCES_FAVORED_ALWAYS_ASK ).Check( settings.alwaysAskSystem ); dialog.CheckBox( IDC_PREFERENCES_DISABLE_STATUSMSG ).Check( settings.disableStatusMsg ); { Control::ComboBox priorities( dialog.ComboBox( IDC_PREFERENCES_PRIORITY ) ); for (uint i=IDS_PRIORITY_NORMAL; i <= IDS_PRIORITY_HIGH; ++i) priorities.Add( Resource::String(i) ); priorities[settings.priority].Select(); } dialog.RadioButton( IDC_PREFERENCES_STYLE_NES ).Check( Application::Instance::GetIconStyle() == Application::Instance::ICONSTYLE_NES ); dialog.RadioButton( IDC_PREFERENCES_STYLE_FAMICOM ).Check( Application::Instance::GetIconStyle() == Application::Instance::ICONSTYLE_FAMICOM ); UpdateIconStyle(); UpdateColors(); return true; } void Preferences::UpdateIconStyle() const { const uint style = (dialog.RadioButton(IDC_PREFERENCES_STYLE_NES).Checked() ? 1 : 2); for (uint i=0; i < 5; ++i) dialog.SetItemIcon( icons[i][0], icons[i][style] ); } void Preferences::UpdateColors() const { if (HDC const hDC = ::GetDC( dialog )) { HPEN const hPen = ::CreatePen( PS_SOLID, 1, RGB(0x00,0x00,0x00) ); HPEN const hPenOld = static_cast(::SelectObject( hDC, hPen )); for (uint i=0; i < 2; ++i) { const MenuColorWindow& type = menuColorWindows[i]; HBRUSH const hBrush = ::CreateSolidBrush( type.color ); HBRUSH const hBrushOld = static_cast(::SelectObject( hDC, hBrush )); ::Rectangle( hDC, type.rect.left, type.rect.top, type.rect.right, type.rect.bottom ); ::SelectObject( hDC, hBrushOld ); ::DeleteObject( hBrush ); } ::SelectObject( hDC, hPenOld ); ::DeleteObject( hPen ); ::ReleaseDC( dialog, hDC ); } } ibool Preferences::OnPaint(Param&) { UpdateColors(); return false; } ibool Preferences::OnCmdStyle(Param& param) { if (param.Button().Clicked()) UpdateIconStyle(); return true; } ibool Preferences::OnCmdMenuColorChange(Param& param) { if (param.Button().Clicked()) { static COLORREF customColors[16] = {0}; Object::Pod cc; MenuColorWindow& type = menuColorWindows[param.Button().GetId() == IDC_PREFERENCES_MENUCOLOR_FULLSCREEN_CHANGE]; cc.lStructSize = sizeof(cc); cc.hwndOwner = dialog; cc.lpCustColors = customColors; cc.rgbResult = type.color; cc.Flags = CC_FULLOPEN|CC_RGBINIT; if (::ChooseColor( &cc )) { type.color = cc.rgbResult; UpdateColors(); } } return true; } ibool Preferences::OnCmdMenuColorDefault(Param& param) { if (param.Button().Clicked()) { uint id; if (param.Button().GetId() == IDC_PREFERENCES_MENUCOLOR_FULLSCREEN_DEFAULT) id = IDC_PREFERENCES_MENUCOLOR_FULLSCREEN_CHANGE; else id = IDC_PREFERENCES_MENUCOLOR_DESKTOP_CHANGE; dialog.Control( id ).Enable( dialog.CheckBox(param.Button().GetId()).Unchecked() ); } return true; } ibool Preferences::OnCmdDefault(Param&) { dialog.CheckBox( IDC_PREFERENCES_BEGIN_EMULATION ).Check( true ); dialog.CheckBox( IDC_PREFERENCES_RUN_IN_BACKGROUND ).Check( false ); dialog.CheckBox( IDC_PREFERENCES_STARTUP_FULLSCREEN ).Check( false ); dialog.CheckBox( IDC_PREFERENCES_DISABLE_ROM_WARNINGS ).Check( false ); dialog.CheckBox( IDC_PREFERENCES_CLOSE_POWER_OFF ).Check( false ); dialog.CheckBox( IDC_PREFERENCES_CONFIRM_EXIT ).Check( true ); dialog.CheckBox( IDC_PREFERENCES_CONFIRM_RESET ).Check( false ); dialog.CheckBox( IDC_PREFERENCES_MULTIPLE_INSTANCES ).Check( false ); dialog.CheckBox( IDC_PREFERENCES_SAVE_LOGFILE ).Check( true ); dialog.CheckBox( IDC_PREFERENCES_SAVE_LAUNCHER ).Check( true ); dialog.CheckBox( IDC_PREFERENCES_SAVE_CHEATCODES ).Check( true ); dialog.CheckBox( IDC_PREFERENCES_SAVE_NETPLAY_GAMELIST ).Check( true ); dialog.CheckBox( IDC_PREFERENCES_SAVE_WINDOWPOS ).Check( false ); dialog.CheckBox( IDC_PREFERENCES_SAVE_LAUNCHERSIZE ).Check( false ); dialog.CheckBox( IDC_PREFERENCES_DISABLE_STATUSMSG ).Check( false ); dialog.ComboBox( IDC_PREFERENCES_PRIORITY )[ PRIORITY_NORMAL ].Select(); dialog.RadioButton( IDC_PREFERENCES_FAVORED_NES_NTSC ).Check( true ); dialog.RadioButton( IDC_PREFERENCES_FAVORED_NES_PAL ).Check( false ); dialog.RadioButton( IDC_PREFERENCES_FAVORED_FAMICOM ).Check( false ); dialog.RadioButton( IDC_PREFERENCES_FAVORED_DENDY ).Check( false ); dialog.CheckBox( IDC_PREFERENCES_FAVORED_ALWAYS_ASK ).Check( false ); dialog.CheckBox( IDC_PREFERENCES_MENUCOLOR_DESKTOP_DEFAULT ).Check( true ); dialog.CheckBox( IDC_PREFERENCES_MENUCOLOR_FULLSCREEN_DEFAULT ).Check( true ); dialog.Control( IDC_PREFERENCES_MENUCOLOR_DESKTOP_CHANGE ).Enable( false ); dialog.Control( IDC_PREFERENCES_MENUCOLOR_FULLSCREEN_CHANGE ).Enable( false ); menuColorWindows[0].color = DEFAULT_DESKTOP_MENU_COLOR; menuColorWindows[1].color = DEFAULT_FULLSCREEN_MENU_COLOR; UpdateColors(); return true; } ibool Preferences::OnCmdOk(Param& param) { if (param.Button().Clicked()) { for (uint i=0; i < NUM_SETTINGS; ++i) { if (i != SAVE_SETTINGS) settings[i] = dialog.CheckBox( IDC_PREFERENCES_STARTUP_FULLSCREEN + i ).Checked(); } settings.priority = static_cast(dialog.ComboBox( IDC_PREFERENCES_PRIORITY ).Selection().GetIndex()); settings.menuLookDesktop.color = menuColorWindows[0].color; settings.menuLookFullscreen.color = menuColorWindows[1].color; settings.menuLookDesktop.enabled = dialog.CheckBox( IDC_PREFERENCES_MENUCOLOR_DESKTOP_DEFAULT ).Unchecked(); settings.menuLookFullscreen.enabled = dialog.CheckBox( IDC_PREFERENCES_MENUCOLOR_FULLSCREEN_DEFAULT ).Unchecked(); settings.favoredSystem = ( dialog.RadioButton( IDC_PREFERENCES_FAVORED_NES_PAL ).Checked() ? Nes::Machine::FAVORED_NES_PAL : dialog.RadioButton( IDC_PREFERENCES_FAVORED_FAMICOM ).Checked() ? Nes::Machine::FAVORED_FAMICOM : dialog.RadioButton( IDC_PREFERENCES_FAVORED_DENDY ).Checked() ? Nes::Machine::FAVORED_DENDY : Nes::Machine::FAVORED_NES_NTSC ); settings.alwaysAskSystem = dialog.RadioButton( IDC_PREFERENCES_FAVORED_ALWAYS_ASK ).Checked(); settings.disableStatusMsg = dialog.RadioButton( IDC_PREFERENCES_DISABLE_STATUSMSG ).Checked(); Application::Instance::SetIconStyle( dialog.RadioButton(IDC_PREFERENCES_STYLE_NES).Checked() ? Application::Instance::ICONSTYLE_NES : Application::Instance::ICONSTYLE_FAMICOM ); { Association association( true ); const uint iconOffset = (Application::Instance::GetIconStyle() == Application::Instance::ICONSTYLE_NES ? 3 : 4); for (uint i=0; i < Association::NUM_EXTENSIONS; ++i) { if (dialog.CheckBox( IDC_PREFERENCES_ASSOCIATE_NES + i ).Checked()) association.Create( i, icons[i][iconOffset] ); else association.Delete( i ); } } dialog.Close(); } return true; } } } nestopia-1.51.1/source/win32/NstDialogPreferences.hpp000066400000000000000000000057511411157722000224520ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIALOG_PREFERENCES_H #define NST_DIALOG_PREFERENCES_H #pragma once #include "NstCollectionBitSet.hpp" #include "NstWindowDialog.hpp" #include "../core/api/NstApiMachine.hpp" namespace Nestopia { namespace Window { class Preferences { public: Preferences(Managers::Emulator&,const Configuration&); void Save(Configuration&) const; enum Type { START_IN_FULLSCREEN, SUPPRESS_WARNINGS, FIRST_UNLOAD_ON_EXIT, CONFIRM_EXIT, RUN_IN_BACKGROUND, AUTOSTART_EMULATION, SAVE_LOGFILE, ALLOW_MULTIPLE_INSTANCES, SAVE_LAUNCHER, CONFIRM_RESET, SAVE_CHEATS, SAVE_NETPLAY_GAMELIST, SAVE_WINDOWPOS, SAVE_LAUNCHERSIZE, SAVE_SETTINGS, NUM_SETTINGS, DISABLE_STATUSMSG }; enum Priority { PRIORITY_NORMAL, PRIORITY_ABOVE_NORMAL, PRIORITY_HIGH }; struct MenuLook { COLORREF color; bool enabled; }; private: enum { DEFAULT_FULLSCREEN_MENU_COLOR = RGB(0x18,0xCA,0xEF), DEFAULT_DESKTOP_MENU_COLOR = RGB(0x18,0xCA,0xEF) }; struct Handlers; struct MenuColorWindow; class Association; ibool OnInitDialog (Param&); ibool OnPaint (Param&); ibool OnCmdDefault (Param&); ibool OnCmdStyle (Param&); ibool OnCmdMenuColorDefault (Param&); ibool OnCmdMenuColorChange (Param&); ibool OnCmdOk (Param&); void UpdateIconStyle() const; void UpdateColors() const; struct Settings : Collection::BitSet { Priority priority; Nes::Machine::FavoredSystem favoredSystem; bool alwaysAskSystem; bool disableStatusMsg; MenuLook menuLookDesktop; MenuLook menuLookFullscreen; }; Settings settings; Dialog dialog; Managers::Emulator& emulator; static MenuColorWindow menuColorWindows[2]; static const ushort icons[4][5]; public: void Open() { dialog.Open(); } const Settings& GetSettings() const { return settings; } }; } } #endif nestopia-1.51.1/source/win32/NstDialogSound.cpp000066400000000000000000000363111411157722000212700ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstApplicationInstance.hpp" #include "NstResourceString.hpp" #include "NstWindowParam.hpp" #include "NstManagerPaths.hpp" #include "NstDialogSound.hpp" namespace Nestopia { namespace Window { NST_COMPILE_ASSERT ( IDC_SOUND_8_BIT == IDC_SOUND_SAMPLE_RATE + 1 && IDC_SOUND_16_BIT == IDC_SOUND_SAMPLE_RATE + 2 && IDC_SOUND_LATENCY == IDC_SOUND_SAMPLE_RATE + 3 && IDC_SOUND_LATENCY_ONE == IDC_SOUND_SAMPLE_RATE + 4 && IDC_SOUND_LATENCY_TEN == IDC_SOUND_SAMPLE_RATE + 5 && IDC_SOUND_MONO == IDC_SOUND_SAMPLE_RATE + 6 && IDC_SOUND_STEREO == IDC_SOUND_SAMPLE_RATE + 7 && IDC_SOUND_POOL_SYSTEM == IDC_SOUND_SAMPLE_RATE + 8 && IDC_SOUND_POOL_HARDWARE == IDC_SOUND_SAMPLE_RATE + 9 && IDC_SOUND_ADJUST_PITCH == IDC_SOUND_SAMPLE_RATE + 10 ); const Sound::ChannelLut Sound::channelLut[NUM_CHANNELS] = { { NULL, "master", IDC_SOUND_MASTER_SLIDER, IDC_SOUND_MASTER_VALUE, IDC_SOUND_MASTER_TEXT, 0 }, { "apu", "square-1", IDC_SOUND_SQUARE1_SLIDER, IDC_SOUND_SQUARE1_VALUE, IDC_SOUND_SQUARE1_TEXT, Nes::Sound::CHANNEL_SQUARE1 }, { "apu", "square-2", IDC_SOUND_SQUARE2_SLIDER, IDC_SOUND_SQUARE2_VALUE, IDC_SOUND_SQUARE2_TEXT, Nes::Sound::CHANNEL_SQUARE2 }, { "apu", "triangle", IDC_SOUND_TRIANGLE_SLIDER, IDC_SOUND_TRIANGLE_VALUE, IDC_SOUND_TRIANGLE_TEXT, Nes::Sound::CHANNEL_TRIANGLE }, { "apu", "noise", IDC_SOUND_NOISE_SLIDER, IDC_SOUND_NOISE_VALUE, IDC_SOUND_NOISE_TEXT, Nes::Sound::CHANNEL_NOISE }, { "apu", "dpcm", IDC_SOUND_DPCM_SLIDER, IDC_SOUND_DPCM_VALUE, IDC_SOUND_DPCM_TEXT, Nes::Sound::CHANNEL_DPCM }, { "external", "fds", IDC_SOUND_FDS_SLIDER, IDC_SOUND_FDS_VALUE, IDC_SOUND_FDS_TEXT, Nes::Sound::CHANNEL_FDS }, { "external", "mmc5", IDC_SOUND_MMC5_SLIDER, IDC_SOUND_MMC5_VALUE, IDC_SOUND_MMC5_TEXT, Nes::Sound::CHANNEL_MMC5 }, { "external", "vrc6", IDC_SOUND_VRC6_SLIDER, IDC_SOUND_VRC6_VALUE, IDC_SOUND_VRC6_TEXT, Nes::Sound::CHANNEL_VRC6 }, { "external", "vrc7", IDC_SOUND_VRC7_SLIDER, IDC_SOUND_VRC7_VALUE, IDC_SOUND_VRC7_TEXT, Nes::Sound::CHANNEL_VRC7 }, { "external", "n163", IDC_SOUND_N163_SLIDER, IDC_SOUND_N163_VALUE, IDC_SOUND_N163_TEXT, Nes::Sound::CHANNEL_N163 }, { "external", "s5b", IDC_SOUND_S5B_SLIDER, IDC_SOUND_S5B_VALUE, IDC_SOUND_S5B_TEXT, Nes::Sound::CHANNEL_S5B } }; struct Sound::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; }; const MsgHandler::Entry Sound::Handlers::messages[] = { { WM_INITDIALOG, &Sound::OnInitDialog }, { WM_VSCROLL, &Sound::OnVScroll } }; const MsgHandler::Entry Sound::Handlers::commands[] = { { IDC_SOUND_DEVICE, &Sound::OnCmdDevice }, { IDC_SOUND_DEFAULT, &Sound::OnCmdDefault }, { IDC_SOUND_RESET_SLIDERS, &Sound::OnCmdResetSliders }, { IDOK, &Sound::OnCmdOk } }; Sound::Sound(Managers::Emulator& e,const Adapters& a,const Managers::Paths& paths,const Configuration& cfg) : adapters ( a ), nes ( e ), dialog ( IDD_SOUND, this, Handlers::messages, Handlers::commands ), recorder ( paths ) { Configuration::ConstSection sound( cfg["sound"] ); settings.adapter = UINT_MAX; if (adapters.size()) { const GenericString device( sound["device"].Str() ); if (device != L"none") { const Adapters::const_iterator it( std::find( adapters.begin(), adapters.end(), System::Guid(device) )); if (it != adapters.end()) settings.adapter = it - adapters.begin(); else settings.adapter = GetDefaultAdapter(); } } switch (uint rate = sound["sample-rate"].Int()) { case 11025: case 22050: case 44100: case 48000: case 88200: case 96000: nes.SetSampleRate( rate ); break; } switch (uint bits = sound["sample-bits"].Int()) { case 8: case 16: nes.SetSampleBits( bits ); break; } nes.SetAutoTranspose( sound["adjust-pitch"].Yes() ); nes.SetSpeaker( sound["speakers"].Str() == L"stereo" ? Nes::Sound::SPEAKER_STEREO : Nes::Sound::SPEAKER_MONO ); settings.pool = (sound["memory-pool"].Str() == L"hardware" ? DirectSound::POOL_HARDWARE : DirectSound::POOL_SYSTEM); settings.latency = sound["buffers"].Int( DEFAULT_LATENCY ); if (settings.latency > LATENCY_MAX) settings.latency = DEFAULT_LATENCY; Configuration::ConstSection volumes( sound["volumes"] ); for (uint i=0; i < NUM_CHANNELS; ++i) { uint volume; if (channelLut[i].cfgCategory) volume = volumes[channelLut[i].cfgCategory][channelLut[i].cfgChannel].Int( DEFAULT_VOLUME ); else volume = volumes[channelLut[i].cfgChannel].Int( DEFAULT_VOLUME ); if (volume > VOLUME_MAX) volume = DEFAULT_VOLUME; settings.volumes[i] = volume; if (channelLut[i].channel) nes.SetVolume( channelLut[i].channel, GetVolume( channelLut[i].channel ) ); } } Sound::~Sound() { } void Sound::Save(Configuration& cfg) const { Configuration::Section sound( cfg["sound"] ); if (settings.adapter < adapters.size()) sound["device"].Str() = adapters[settings.adapter].guid.GetString(); else sound["device"].Str() = "none"; sound[ "sample-rate" ].Int() = nes.GetSampleRate(); sound[ "sample-bits" ].Int() = nes.GetSampleBits(); sound[ "buffers" ].Int() = settings.latency; sound[ "speakers" ].Str() = (nes.GetSpeaker() == Nes::Sound::SPEAKER_STEREO ? "stereo" : "mono"); sound[ "adjust-pitch" ].YesNo() = nes.IsAutoTransposing(); sound[ "memory-pool" ].Str() = (settings.pool == DirectSound::POOL_SYSTEM ? "system" : "hardware"); Configuration::Section volumes( sound["volumes"] ); for (uint i=0; i < NUM_CHANNELS; ++i) { if (channelLut[i].cfgCategory) volumes[channelLut[i].cfgCategory][channelLut[i].cfgChannel].Int() = settings.volumes[i]; else volumes[channelLut[i].cfgChannel].Int() = settings.volumes[i]; } } uint Sound::GetVolume(const uint channel) const { if (settings.adapter != UINT_MAX) { for (uint i=1; i < NUM_CHANNELS; ++i) { if (channelLut[i].channel == channel) { const uint volume = (settings.volumes[i] * settings.volumes[0] + DEFAULT_VOLUME/2) / DEFAULT_VOLUME; return NST_MIN(volume,VOLUME_MAX); } } } return 0; } uint Sound::GetDefaultAdapter() const { const Adapters::const_iterator it( std::find( adapters.begin(), adapters.end(), System::Guid() ) ); return it != adapters.end() ? it - adapters.begin() : 0; } ibool Sound::OnInitDialog(Param&) { if (adapters.size()) { { const Control::ComboBox comboBox( dialog.ComboBox(IDC_SOUND_DEVICE) ); comboBox.Add( Resource::String(IDS_TEXT_NONE) ); for (Adapters::const_iterator it(adapters.begin()), end(adapters.end()); it != end; ++it) comboBox.Add( it->name.Ptr() ); comboBox[settings.adapter+1].Select(); } { static const wchar_t rates[][6] = { L"11025", L"22050", L"44100", L"48000", L"88200", L"96000" }; uint index; switch (nes.GetSampleRate()) { case 11025: index = 0; break; case 22050: index = 1; break; case 48000: index = 3; break; case 88200: index = 4; break; case 96000: index = 5; break; default: index = 2; break; } const Control::ComboBox comboBox( dialog.ComboBox(IDC_SOUND_SAMPLE_RATE) ); comboBox.Add( rates, sizeof(array(rates)) ); comboBox[index].Select(); } dialog.RadioButton( nes.GetSampleBits() == 8 ? IDC_SOUND_8_BIT : IDC_SOUND_16_BIT ).Check(); dialog.RadioButton( nes.GetSpeaker() == Nes::Sound::SPEAKER_STEREO ? IDC_SOUND_STEREO : IDC_SOUND_MONO ).Check(); dialog.RadioButton( settings.pool == DirectSound::POOL_HARDWARE ? IDC_SOUND_POOL_HARDWARE : IDC_SOUND_POOL_SYSTEM ).Check(); for (uint i=0; i < NUM_CHANNELS; ++i) { const Control::Slider control( dialog.Slider(channelLut[i].ctrlSlider) ); control.SetRange( 0, VOLUME_MAX ); control.Position() = VOLUME_MAX - settings.volumes[i]; dialog.Edit( channelLut[i].ctrlValue ) << uint(settings.volumes[i]); } { const Control::Slider control( dialog.Slider(IDC_SOUND_LATENCY) ); control.SetRange( 1, LATENCY_MAX ); control.Position() = settings.latency; } dialog.CheckBox( IDC_SOUND_ADJUST_PITCH ).Check( nes.IsAutoTransposing() ); if (settings.adapter != UINT_MAX) UpdateVolumeReset(); else Enable( false ); } else { dialog.Control( IDC_SOUND_DEVICE ).Disable(); dialog.Control( IDC_SOUND_DEFAULT ).Disable(); Enable( false ); } return true; } void Sound::Enable(const bool state) const { for (uint i=IDC_SOUND_SAMPLE_RATE; i <= IDC_SOUND_ADJUST_PITCH; ++i) dialog.Control( i ).Enable( state ); for (uint i=0; i < NUM_CHANNELS; ++i) { dialog.Control( channelLut[i].ctrlSlider ).Enable( state ); dialog.Control( channelLut[i].ctrlValue ).Enable( state ); dialog.Control( channelLut[i].ctrlText ).Enable( state ); } if (state) UpdateVolumeReset(); else dialog.Control( IDC_SOUND_RESET_SLIDERS ).Disable(); } void Sound::ResetVolumeSliders() const { for (uint i=0; i < NUM_CHANNELS; ++i) { dialog.Slider( channelLut[i].ctrlSlider ).Position() = VOLUME_MAX-DEFAULT_VOLUME; dialog.Edit( channelLut[i].ctrlValue ) << uint(DEFAULT_VOLUME); } dialog.Control( IDC_SOUND_RESET_SLIDERS ).Disable(); } void Sound::UpdateVolumeReset() const { uint reset; for (reset=0; reset < NUM_CHANNELS; ++reset) { if (dialog.Slider( channelLut[reset].ctrlSlider ).Position() != VOLUME_MAX-DEFAULT_VOLUME) break; } dialog.Control( IDC_SOUND_RESET_SLIDERS ).Enable( reset != NUM_CHANNELS ); } ibool Sound::OnVScroll(Param& param) { for (uint i=0, id=param.Slider().GetId(); i < NUM_CHANNELS; ++i) { if (id == channelLut[i].ctrlSlider) { dialog.Edit( channelLut[i].ctrlValue ) << (VOLUME_MAX - param.Slider().Scroll()); UpdateVolumeReset(); break; } } return true; } ibool Sound::OnCmdDevice(Param&) { Enable( dialog.ComboBox( IDC_SOUND_DEVICE ).Selection().GetIndex() != 0 ); return true; } ibool Sound::OnCmdResetSliders(Param& param) { if (param.Button().Clicked()) ResetVolumeSliders(); return true; } ibool Sound::OnCmdDefault(Param& param) { NST_VERIFY( adapters.size() ); if (param.Button().Clicked()) { Enable( true ); dialog.ComboBox( IDC_SOUND_DEVICE )[GetDefaultAdapter()+1].Select(); dialog.ComboBox( IDC_SOUND_SAMPLE_RATE )[1].Select(); dialog.RadioButton( IDC_SOUND_16_BIT ).Check(); dialog.RadioButton( IDC_SOUND_8_BIT ).Uncheck(); dialog.RadioButton( IDC_SOUND_MONO ).Check(); dialog.RadioButton( IDC_SOUND_STEREO ).Uncheck(); dialog.RadioButton( IDC_SOUND_POOL_HARDWARE ).Uncheck(); dialog.RadioButton( IDC_SOUND_POOL_SYSTEM ).Check(); dialog.CheckBox( IDC_SOUND_ADJUST_PITCH ).Uncheck(); dialog.Slider( IDC_SOUND_LATENCY ).Position() = DEFAULT_LATENCY; ResetVolumeSliders(); } return true; } ibool Sound::OnCmdOk(Param& param) { if (param.Button().Clicked()) { if (adapters.size()) { settings.adapter = dialog.ComboBox( IDC_SOUND_DEVICE ).Selection().GetIndex() - 1U; settings.latency = dialog.Slider( IDC_SOUND_LATENCY ).Position(); settings.pool = (dialog.RadioButton( IDC_SOUND_POOL_HARDWARE ).Checked() ? DirectSound::POOL_HARDWARE : DirectSound::POOL_SYSTEM); static const uint rates[] = {11025,22050,44100,48000,88200,96000}; nes.SetSampleRate( rates[dialog.ComboBox( IDC_SOUND_SAMPLE_RATE ).Selection().GetIndex()] ); nes.SetSampleBits( dialog.RadioButton( IDC_SOUND_8_BIT ).Checked() ? 8 : 16 ); nes.SetSpeaker( dialog.RadioButton( IDC_SOUND_STEREO ).Checked() ? Nes::Sound::SPEAKER_STEREO : Nes::Sound::SPEAKER_MONO ); nes.SetAutoTranspose( dialog.CheckBox( IDC_SOUND_ADJUST_PITCH ).Checked() ); for (uint i=0; i < NUM_CHANNELS; ++i) settings.volumes[i] = VOLUME_MAX - dialog.Slider( channelLut[i].ctrlSlider ).Position(); for (uint i=1; i < NUM_CHANNELS; ++i) nes.SetVolume( channelLut[i].channel, GetVolume( channelLut[i].channel ) ); } dialog.Close(); } return true; } struct Sound::Recorder::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; }; const MsgHandler::Entry Sound::Recorder::Handlers::messages[] = { { WM_INITDIALOG, &Recorder::OnInitDialog } }; const MsgHandler::Entry Sound::Recorder::Handlers::commands[] = { { IDC_SOUND_CAPTURE_CLEAR, &Recorder::OnCmdClear }, { IDC_SOUND_CAPTURE_BROWSE, &Recorder::OnCmdBrowse }, { IDOK, &Recorder::OnCmdOk } }; Sound::Recorder::Recorder(const Managers::Paths& p) : dialog(IDD_SOUND_RECORDER,this,Handlers::messages,Handlers::commands), paths(p) {} Sound::Recorder::~Recorder() { } const Path Sound::Recorder::WaveFile() const { return Application::Instance::GetFullPath( waveFile ); } ibool Sound::Recorder::OnInitDialog(Param&) { dialog.Edit( IDC_SOUND_CAPTURE_FILE ) << waveFile.Ptr(); dialog.Edit( IDC_SOUND_CAPTURE_FILE ).Limit( MAX_PATH ); return true; } ibool Sound::Recorder::OnCmdClear(Param& param) { if (param.Button().Clicked()) dialog.Edit(IDC_SOUND_CAPTURE_FILE).Clear(); return true; } ibool Sound::Recorder::OnCmdBrowse(Param& param) { if (param.Button().Clicked()) { Path tmp; dialog.Edit(IDC_SOUND_CAPTURE_FILE) >> tmp; dialog.Edit(IDC_SOUND_CAPTURE_FILE).Try() << paths.BrowseSave( Managers::Paths::File::WAVE, Managers::Paths::SUGGEST, Application::Instance::GetFullPath(tmp) ).Ptr(); } return true; } ibool Sound::Recorder::OnCmdOk(Param& param) { if (param.Button().Clicked()) { dialog.Edit(IDC_SOUND_CAPTURE_FILE) >> waveFile; paths.FixFile( Managers::Paths::File::WAVE, waveFile ); dialog.Close(); } return true; } } } nestopia-1.51.1/source/win32/NstDialogSound.hpp000066400000000000000000000067411411157722000213010ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIALOG_SOUND_H #define NST_DIALOG_SOUND_H #pragma once #include "NstWindowDialog.hpp" #include "NstDirectSound.hpp" namespace Nestopia { namespace Managers { class Paths; } namespace Window { class Sound { typedef DirectX::DirectSound::Adapter Adapter; typedef DirectX::DirectSound::Adapters Adapters; typedef DirectX::DirectSound DirectSound; public: Sound(Managers::Emulator&,const Adapters&,const Managers::Paths&,const Configuration&); ~Sound(); void Save(Configuration&) const; uint GetVolume(uint) const; private: enum { DEFAULT_BITS = 16, DEFAULT_RATE = 44100, LATENCY_MAX = 10, DEFAULT_LATENCY = 1, VOLUME_MAX = 100, DEFAULT_VOLUME = Nes::Sound::DEFAULT_VOLUME, DEFAULT_MONO = 0, NUM_CHANNELS = 12 }; struct Handlers; uint GetDefaultAdapter() const; void Enable(bool) const; void ResetVolumeSliders() const; void UpdateVolumeReset() const; ibool OnInitDialog (Param&); ibool OnVScroll (Param&); ibool OnCmdDevice (Param&); ibool OnCmdResetSliders (Param&); ibool OnCmdDefault (Param&); ibool OnCmdOk (Param&); const Adapters& adapters; Nes::Sound nes; struct { uint adapter; uint latency; DirectX::DirectSound::Pool pool; uchar volumes[NUM_CHANNELS]; } settings; Dialog dialog; struct ChannelLut { cstring cfgCategory; cstring cfgChannel; ushort ctrlSlider; ushort ctrlValue; ushort ctrlText; ushort channel; }; static const ChannelLut channelLut[NUM_CHANNELS]; public: class Recorder { public: explicit Recorder(const Managers::Paths&); ~Recorder(); const Path WaveFile() const; private: struct Handlers; ibool OnInitDialog (Param&); ibool OnCmdBrowse (Param&); ibool OnCmdClear (Param&); ibool OnCmdOk (Param&); Dialog dialog; const Managers::Paths& paths; Path waveFile; public: void Open() { dialog.Open(); } }; private: Recorder recorder; public: void Open() { dialog.Open(); } Recorder& GetRecorder() { return recorder; } bool SoundEnabled() const { return settings.adapter != UINT_MAX; } uint GetAdapter() const { return settings.adapter; } uint GetLatency() const { return settings.latency; } DirectX::DirectSound::Pool GetPool() const { return settings.pool; } }; } } #endif nestopia-1.51.1/source/win32/NstDialogTapeRecorder.cpp000066400000000000000000000102351411157722000225540ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstWindowParam.hpp" #include "NstManagerPaths.hpp" #include "NstDialogTapeRecorder.hpp" #include "NstApplicationInstance.hpp" namespace Nestopia { namespace Window { struct TapeRecorder::Handlers { static const MsgHandler::Entry messages[]; static const MsgHandler::Entry commands[]; }; const MsgHandler::Entry TapeRecorder::Handlers::messages[] = { { WM_INITDIALOG, &TapeRecorder::OnInitDialog } }; const MsgHandler::Entry TapeRecorder::Handlers::commands[] = { { IDC_TAPE_RECORDER_USE_IMAGENAME, &TapeRecorder::OnCmdUseImageName }, { IDC_TAPE_RECORDER_CLEAR, &TapeRecorder::OnCmdClear }, { IDC_TAPE_RECORDER_BROWSE, &TapeRecorder::OnCmdBrowse }, { IDOK, &TapeRecorder::OnCmdOk } }; TapeRecorder::TapeRecorder(const Configuration& cfg,const Managers::Paths& p) : dialog(IDD_TAPE_RECORDER,this,Handlers::messages,Handlers::commands), paths(p) { Configuration::ConstSection tapes( cfg["paths"]["tapes"] ); settings.useImageNaming = !tapes["use-image-name"].No(); settings.customFile = tapes["file"].Str(); paths.FixFile( Managers::Paths::File::TAPE, settings.customFile ); } TapeRecorder::~TapeRecorder() { } void TapeRecorder::Save(Configuration& cfg) const { Configuration::Section tapes( cfg["paths"]["tapes"] ); tapes["use-image-name"].YesNo() = settings.useImageNaming; tapes["file"].Str() = settings.customFile; } const Path TapeRecorder::GetCustomFile() const { return Application::Instance::GetFullPath( settings.customFile ); } ibool TapeRecorder::OnInitDialog(Param&) { dialog.CheckBox(IDC_TAPE_RECORDER_USE_IMAGENAME).Check( settings.useImageNaming ); dialog.Edit(IDC_TAPE_RECORDER_FILE) << settings.customFile.Ptr(); Update(); return true; } void TapeRecorder::Update() const { const bool unchecked = !dialog.CheckBox(IDC_TAPE_RECORDER_USE_IMAGENAME).Checked(); dialog.Control( IDC_TAPE_RECORDER_FILE ).Enable( unchecked ); dialog.Control( IDC_TAPE_RECORDER_BROWSE ).Enable( unchecked ); dialog.Control( IDC_TAPE_RECORDER_CLEAR ).Enable( unchecked ); } ibool TapeRecorder::OnCmdUseImageName(Param& param) { if (param.Button().Clicked()) Update(); return true; } ibool TapeRecorder::OnCmdClear(Param& param) { if (param.Button().Clicked()) dialog.Edit(IDC_TAPE_RECORDER_FILE).Clear(); return true; } ibool TapeRecorder::OnCmdBrowse(Param& param) { if (param.Button().Clicked()) { Path tmp; dialog.Edit(IDC_TAPE_RECORDER_FILE) >> tmp; dialog.Edit(IDC_TAPE_RECORDER_FILE).Try() << paths.BrowseSave( Managers::Paths::File::TAPE, Managers::Paths::SUGGEST, Application::Instance::GetFullPath(tmp) ).Ptr(); } return true; } ibool TapeRecorder::OnCmdOk(Param& param) { if (param.Button().Clicked()) { settings.useImageNaming = dialog.CheckBox(IDC_TAPE_RECORDER_USE_IMAGENAME).Checked(); dialog.Edit(IDC_TAPE_RECORDER_FILE) >> settings.customFile; paths.FixFile( Managers::Paths::File::TAPE, settings.customFile ); dialog.Close(); } return true; } } } nestopia-1.51.1/source/win32/NstDialogTapeRecorder.hpp000066400000000000000000000035471411157722000225710ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #ifndef NST_DIALOG_TAPERECORDER_H #define NST_DIALOG_TAPERECORDER_H #pragma once #include "NstWindowDialog.hpp" namespace Nestopia { namespace Window { class TapeRecorder { public: TapeRecorder(const Configuration&,const Managers::Paths&); ~TapeRecorder(); void Save(Configuration&) const; const Path GetCustomFile() const; private: struct Handlers; void Update() const; ibool OnInitDialog (Param&); ibool OnCmdUseImageName (Param&); ibool OnCmdBrowse (Param&); ibool OnCmdClear (Param&); ibool OnCmdOk (Param&); Dialog dialog; const Managers::Paths& paths; struct { bool useImageNaming; Path customFile; } settings; public: void Open() { dialog.Open(); } bool UseImageNaming() const { return settings.useImageNaming; } }; } } #endif nestopia-1.51.1/source/win32/NstDialogVideo.cpp000066400000000000000000001164471411157722000212570ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstIoLog.hpp" #include "NstWindowUser.hpp" #include "NstWindowParam.hpp" #include "NstResourceString.hpp" #include "NstManagerPaths.hpp" #include "NstApplicationInstance.hpp" #include "NstDialogPaletteEditor.hpp" #include "NstDialogVideoDecoder.hpp" #include "NstDialogVideo.hpp" namespace Nestopia { namespace Window { NST_COMPILE_ASSERT ( IDC_VIDEO_NTSC_TOP == IDC_VIDEO_NTSC_LEFT + 1 && IDC_VIDEO_NTSC_RIGHT == IDC_VIDEO_NTSC_LEFT + 2 && IDC_VIDEO_NTSC_BOTTOM == IDC_VIDEO_NTSC_LEFT + 3 && IDC_VIDEO_PAL_LEFT == IDC_VIDEO_NTSC_LEFT + 4 && IDC_VIDEO_PAL_TOP == IDC_VIDEO_NTSC_LEFT + 5 && IDC_VIDEO_PAL_RIGHT == IDC_VIDEO_NTSC_LEFT + 6 && IDC_VIDEO_PAL_BOTTOM == IDC_VIDEO_NTSC_LEFT + 7 ); NST_COMPILE_ASSERT ( IDC_VIDEO_32_BIT == IDC_VIDEO_16_BIT + 1 ); NST_COMPILE_ASSERT ( IDC_VIDEO_PALETTE_YUV == IDC_VIDEO_PALETTE_AUTO + 1 && IDC_VIDEO_PALETTE_RGB == IDC_VIDEO_PALETTE_AUTO + 2 && IDC_VIDEO_PALETTE_CUSTOM == IDC_VIDEO_PALETTE_AUTO + 3 && IDC_VIDEO_PALETTE_PATH == IDC_VIDEO_PALETTE_AUTO + 4 && IDC_VIDEO_PALETTE_BROWSE == IDC_VIDEO_PALETTE_AUTO + 5 && IDC_VIDEO_PALETTE_CLEAR == IDC_VIDEO_PALETTE_AUTO + 6 && IDC_VIDEO_PALETTE_EDITOR == IDC_VIDEO_PALETTE_AUTO + 7 ); NST_COMPILE_ASSERT ( Nes::Video::MIN_BRIGHTNESS == -100 && Nes::Video::DEFAULT_BRIGHTNESS == 0 && Nes::Video::MAX_BRIGHTNESS == +100 && Nes::Video::MIN_SATURATION == -100 && Nes::Video::DEFAULT_SATURATION == 0 && Nes::Video::MAX_SATURATION == +100 && Nes::Video::MIN_CONTRAST == -100 && Nes::Video::DEFAULT_CONTRAST == 0 && Nes::Video::MAX_CONTRAST == +100 ); struct Video::Handlers { static const MsgHandler::Entry