pax_global_header00006660000000000000000000000064134143014430014507gustar00rootroot0000000000000052 comment=1293fd6bdf8b0946e3d911cac37a2897018a6aa8 osmose-emulator-1.4/000077500000000000000000000000001341430144300145065ustar00rootroot00000000000000osmose-emulator-1.4/CHANGELOG000066400000000000000000000022761341430144300157270ustar00rootroot00000000000000version: 1.4 * Set default sound device (Thanks to Kev-J) * Change sound buffer writing method (Thanks to Kev-J) * Qt Wayland widgets alternative in gnome-shell version: 1.3 * Replaced 'strncpy' with 'memcpy' to suppress the warning * Updated files version and year * Changed alsa device to "plughw" * Added to manpage in src directory * Changed the build flag to version 'gnu++17' version: 1.2 * Fixed bug in audio alsa * Fixed installation on architectures 'arm' version: 1.1 * Changed own icon in the main window * Changed image format: xpm to png * Added SVG image * Fixed spelling in some files * Copied the files from the directory (cpu) to the directory (src) * Updated file: OsmoseEmulator.pro * Some bug fixes * Fixed build for armel/armhf architectures * Added libraries required for armel/armhf architectures version: 1.0 * Created own icon in the main window * Replaced the QT version - 4.x to 5.x * Added in the main window menu - About * Revised common misspelled words in source code * Removed embedded copy of the source code 'unzip' version: 0.9.96 * Initial version * Acquired originally from the site and holder by copyright Bruno Vedder osmose-emulator-1.4/LICENSE000066400000000000000000001045061341430144300155210ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. 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 them 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 prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. 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. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey 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; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If 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 convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU 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 that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. 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. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 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. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. {one line to give the program's name and a brief idea of what it does.} Copyright (C) {year} {name of author} This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 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, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: {project} Copyright (C) {year} {fullname} This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . osmose-emulator-1.4/OsmoseEmulator.pro000066400000000000000000000065351341430144300202170ustar00rootroot00000000000000############################################################################### # # * This file is part of Osmose, a Sega Master System/Game Gear software # * emulator. # * # * Many thanks to Vedder Bruno, the original author of Osmose Emulator. # * # * Copyright holder 2001-2011 Vedder Bruno. # * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] # * # * Osmose Emulator is free software: you can redistribute it and/or modify it # * under the terms of the GNU General Public License as published by the # * Free Software Foundation, either version 3 of the License, # * or any later version. # ############################################################################### QT += core gui opengl widgets TARGET = osmose-emulator TEMPLATE = app DEPENDPATH += src INCLUDEPATH += src LIBS += -lz -lasound -lGL -lGLU -lglut FLAGS += -Wall -Wextra -Wno-unused -Wcast-qual QMAKE_CXXFLAGS += -std=gnu++17 $$FLAGS QMAKE_CFLAGS += -Wmissing-prototypes -Wshadow $$FLAGS # Output directory OBJECTS_DIR += src MOC_DIR += src RCC_DIR += src UI_DIR += src # Input directory HEADERS += src/EmulationThread.h \ src/Joystick.h \ src/KeyMapper.h \ src/OsmoseConfigurationFile.h \ src/OsmoseEmulationThread.h \ src/OsmoseGUI.h \ src/Pthreadcpp.h \ src/QGLImage.h \ src/QLogWindow.h \ src/QOsmoseConfiguration.h \ src/TGAWriter.h \ src/WhiteNoiseEmulationThread.h \ src/BasicTypes.h \ src/Z80.h \ src/AnsiColorTerminal.h \ src/Bits.h \ src/DebugEventListener.h \ src/DebugEventThrower.h \ src/Definitions.h \ src/FIFOSoundBuffer.h \ src/IOMapper.h \ src/IOMapper_GG.h \ src/MemoryMapper.h \ src/Options.h \ src/OsmoseCore.h \ src/RomSpecificOption.h \ src/SaveState.h \ src/SmsDebugger.h \ src/SmsEnvironment.h \ src/SN76489.h \ src/SoundThread.h \ src/VDP.h \ src/VDP_GG.h \ src/Version.h \ src/WaveWriter.h FORMS += src/Configuration.ui \ src/LogWindow.ui SOURCES += src/EmulationThread.cpp \ src/Joystick.cpp \ src/KeyMapper.cpp \ src/main.cpp \ src/OsmoseConfigurationFile.cpp \ src/OsmoseEmulationThread.cpp \ src/OsmoseGUI.cpp \ src/Pthreadcpp.cpp \ src/QGLImage.cpp \ src/QLogWindow.cpp \ src/QOsmoseConfiguration.cpp \ src/TGAWriter.cpp \ src/WhiteNoiseEmulationThread.cpp \ src/Opc_cbxx.cpp \ src/Opc_dd.cpp \ src/Opc_ddcb.cpp \ src/Opc_ed.cpp \ src/Opc_fd.cpp \ src/Opc_fdcb.cpp \ src/Opc_std.cpp \ src/Z80.cpp \ src/DebugEventThrower.cpp \ src/FIFOSoundBuffer.cpp \ src/IOMapper.cpp \ src/IOMapper_GG.cpp \ src/MemoryMapper.cpp \ src/Options.cpp \ src/OsmoseCore.cpp \ src/RomSpecificOption.cpp \ src/SmsEnvironment.cpp \ src/SN76489.cpp \ src/SoundThread.cpp \ src/VDP.cpp \ src/VDP_GG.cpp \ src/WaveWriter.cpp RESOURCES += src/OsmoseResources.qrc osmose-emulator-1.4/README.md000066400000000000000000000056561341430144300160010ustar00rootroot00000000000000 _______ _______ | |.-----.--------.| |.-----.-----. | - ||__ --| || - ||__ --| -__| |_______||_____|__|__|__||_______||_____|_____| _______ __ __ | ___|.--------.--.--.| |.---.-.| |_.-----.----. | ___|| | | || || _ || _| _ | _| |_______||__|__|__|_____||__||___._||____|_____|__| Public release, re-written and continued by Carlos Donizete Froes. Holder by copyright Bruno Vedder. ### Osmose Emulator means In brief it's an Sega Master System/Game Gear emulator encapsulated into C++ classes. Many thanks to Vedder Bruno, the original author of Osmose Emulator. *What's new:* ------------- Osmose Emulator owns a clean graphical user interface based on QT version 5.x, GUI lib powerful enough to refresh display at 60hz. - Switch sound system to use ALSA. - GUI development using QT5. - Rendering/Key mapping adapted to QTOpenGL. - Configuration system rewritten. - Functional in i386, amd64 and arm architectures. *Dependencies for Debian/Ubuntu/GNU/Linux:* ------------------------------------------- # apt install freeglut3-dev libasound2-dev libqt5opengl5-dev libgl1-mesa-dev mesa-common-dev qt5-qmake qt5-default qtbase5-dev qtchooser zlib1g-dev *Compilation:* -------------- To build osmose emulator, do from the source directory. *Starting compilation:* $ qmake && make *Removing compilation:* $ make clean && make distclean *Features:* ----------- - SMS: Good compatibility. At this stage, the emulator can run **96%** of commercial games and public demos, except games that relies on codemaster mapper, which work but does not have proper video mode emulated. - Game Gear: Good compatibility. At this stage, the emulator can run **98%** of game gear ROMS. - SN76489 Sound is supported. - Support for ".sms" and ".gg" format. - Video filters: bilinear or nearest neighbour (default). - Pad(keyboard or joystick mapped) emulation. - PAL/NTSC Timing. - Japanese/Export console. - In game Screenshots, GFX rip, sound shot. - Configurable keyboard configuration. - Joystick support, congigurable button assignement. - Drag and drop your ROMS into the emulator window to run games. **Due to the huge number of game gear/master system (around 1300) roms, games have not been deeply tested.** * This file was officially downloaded from : http://bcz.asterope.fr * Continuation of the project from: https://gitlab.com/coringao/osmose-emulator **License** ----------- > **Osmose Emulator** is free software: you can redistribute it and/or modify > it under the terms of the GNU General Public License as published by > the Free Software Foundation, either version 3 of the License, or > any later version. - Copyright (c) 2001-2011 Copyright holder **Bruno Vedder** - Copyright (c) 2016-2018 Work continued by **Carlos Donizete Froes [a.k.a coringao]** osmose-emulator-1.4/src/000077500000000000000000000000001341430144300152755ustar00rootroot00000000000000osmose-emulator-1.4/src/AnsiColorTerminal.h000066400000000000000000000031741341430144300210400ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef ANSI_TERMINAL_COLORS_H #define ANSI_TERMINAL_COLORS_H #ifdef USE_ISO_IEC_6429 #define BLACK(str) "\033[0;30;49;1m"<. * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef BASICTYPES_H #define BASICTYPES_H /* basic types definitions. */ typedef unsigned char u8; typedef signed char s8; typedef unsigned short u16; typedef signed short s16; typedef unsigned int u32; typedef signed int s32; typedef float f32; typedef double f64; #endif osmose-emulator-1.4/src/Bits.h000066400000000000000000000024431341430144300163520ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef BITS_H #define BITS_H #define BIT0 0x1 #define BIT1 0x2 #define BIT2 0x4 #define BIT3 0x8 #define BIT4 0x10 #define BIT5 0x20 #define BIT6 0x40 #define BIT7 0x80 /* And with these value to force bit to zero */ #define BIT0_MASK 0xFE #define BIT1_MASK 0xFD #define BIT2_MASK 0xFB #define BIT3_MASK 0xF7 #define BIT4_MASK 0xEF #define BIT5_MASK 0xDF #define BIT6_MASK 0xBF #define BIT7_MASK 0x7F #endif osmose-emulator-1.4/src/Configuration.ui000066400000000000000000001265111341430144300204510ustar00rootroot00000000000000 Configuration Qt::NonModal true 0 0 478 291 0 0 Configuration false 0 0 0 QLayout::SetDefaultConstraint QLayout::SetDefaultConstraint 0 0 4 0 0 Files -1 9 471 221 QLayout::SetDefaultConstraint 0 BBR path: Screenshots path: Save state path: Sound rip path: Tiles rip path: ... ... ... ... ... Control P1 0 0 471 231 Pad1 UP: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Pad1 DOWN: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Pad1 LEFT: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Pad1 RIGHT: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Pad1 Button A: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Pad1 Button B: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 50 false false false Qt::LeftToRight QFrame::StyledPanel TextLabel Qt::AlignCenter QFrame::StyledPanel TextLabel Qt::AlignCenter QFrame::StyledPanel TextLabel Qt::AlignCenter QFrame::StyledPanel TextLabel Qt::AlignCenter QFrame::StyledPanel TextLabel Qt::AlignCenter QFrame::StyledPanel TextLabel Qt::AlignCenter Redefine Redefine Redefine Redefine Redefine Redefine Control P2 0 0 471 231 Pad2 UP: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Pad2 DOWN: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Pad2 LEFT: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Pad2 RIGHT: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Pad2 Button A: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Pad2 Button B: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 50 false false false Qt::LeftToRight QFrame::StyledPanel TextLabel Qt::AlignCenter QFrame::StyledPanel TextLabel Qt::AlignCenter QFrame::StyledPanel TextLabel Qt::AlignCenter QFrame::StyledPanel TextLabel Qt::AlignCenter QFrame::StyledPanel TextLabel Qt::AlignCenter QFrame::StyledPanel TextLabel Qt::AlignCenter Redefine Redefine Redefine Redefine Redefine Redefine Start/Pause 0 0 471 231 PAUSE: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter START (Gamegear): Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 50 false false false Qt::LeftToRight QFrame::StyledPanel TextLabel Qt::AlignCenter QFrame::StyledPanel TextLabel Qt::AlignCenter Redefine Redefine Qt::Vertical 20 40 403 0 Joystick1 0 0 466 192 0 4 0 0 0 None A button B button Pause (SMS) Start (Game gear) 0 0 Joystick found : 0 None A button B button Pause (SMS) Start (Game gear) 0 None A button B button Pause (SMS) Start (Game gear) 0 None A button B button Pause (SMS) Start (Game gear) false 50 false false false Qt::LeftToRight QFrame::StyledPanel Button 1 Qt::AlignCenter 50 false false false Qt::LeftToRight QFrame::StyledPanel Button 3 Qt::AlignCenter 50 false false false Qt::LeftToRight QFrame::StyledPanel Button 5 Qt::AlignCenter 50 false false false Qt::LeftToRight QFrame::StyledPanel Button 7 Qt::AlignCenter 50 false false false Qt::LeftToRight QFrame::StyledPanel Button 2 Qt::AlignCenter 0 None A button B button Pause (SMS) Start (Game gear) 0 None A button B button Pause (SMS) Start (Game gear) 50 false false false Qt::LeftToRight QFrame::StyledPanel Button 4 Qt::AlignCenter 50 false false false Qt::LeftToRight QFrame::StyledPanel Button 6 Qt::AlignCenter 0 None A button B button Pause (SMS) Start (Game gear) 50 false false false Qt::LeftToRight QFrame::StyledPanel Button 8 Qt::AlignCenter 0 None A button B button Pause (SMS) Start (Game gear) 0 0 Device: Qt::Vertical 20 40 true *need emulator restart. QLayout::SetMaximumSize Cancel Save Apply Qt::Horizontal 40 20 cancelButton clicked() Configuration reject() 188 271 166 449 osmose-emulator-1.4/src/DebugEventListener.h000066400000000000000000000026401341430144300212060ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef DEBUG_EVENT_LISTENER_H #define DEBUG_EVENT_LISTENER_H #include "DebugEventThrower.h" /* Debug Event types. */ enum { DbgEvtUserTrigger = 0, DbgEvtCpuStep = 1, DbgEvtScanlineBreakpoint = 2, DbgEvtCpuIrqAsserted = 3, DbgEvtCpuDisableInterrupt = 4, DbgEvtCpuEnableInterrupt = 5, DbgEvtGeneric = 256 }; class DebugEventListener { public: virtual void sendDebugEvent(int event_type, char *sourcec, char *message) = 0; virtual ~DebugEventListener() {}; }; #endif osmose-emulator-1.4/src/DebugEventThrower.cpp000066400000000000000000000024411341430144300214050ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "DebugEventThrower.h" void DebugEventThrower::attachDebugEventListener(DebugEventListener *el) { del = el; } void DebugEventThrower::throwDebugEvent(int type,char *source, char *msg) { if (del != NULL) { del->sendDebugEvent(type, source, msg); } else { cerr << "Trying to throw DebugEvent but the Thrower is not attached to the listener !" << endl; } } osmose-emulator-1.4/src/DebugEventThrower.h000066400000000000000000000025171341430144300210560ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef DEBUG_EVENT_THROWER_H #define DEBUG_EVENT_THROWER_H #include #include #include "DebugEventListener.h" using namespace std; class DebugEventThrower { public: DebugEventThrower() { del = NULL; } void attachDebugEventListener(DebugEventListener *el); void throwDebugEvent(int type, char *source, char *msg); private: DebugEventListener *del; }; #endif osmose-emulator-1.4/src/Definitions.h000066400000000000000000000033701341430144300177240ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef DEFINITIONS_H_ #define DEFINITIONS_H_ /* Uncomment and rebuild project for integrated debugger Don't forget to uncomment OPT_OBJS line in Makefile before compiling. */ //#define BUILT_IN_DEBUGGER //#define AUTO_SCREENSHOT /* Number of Z80 cycles for each scanline. */ #define CPU_CYCLES_PER_LINE 228 /* SDL delay every 3 frames.*/ #define DELAY_BETWEEN_FRAME 50 /* SDL Sound buffer size for samples. */ #define SAMPLE_SIZE 1024 // Sample duration is 23ms /**/ #define SND_TOGGLE 0.4026717557251908 // rest of 367.5/262. /* Uncomment this line for verbose information on PSG/VDP access */ //#define PSG_VERBOSE //#define VDP_ACCESS //#define AUTO_NAT_VERBOSE //#define PAD_VERBOSE //#define MEM_CTRL_VERBOSE /* Just uncomment this define to get trace of bank mapping operations */ //#define P_VERBOSE #endif osmose-emulator-1.4/src/EmulationThread.cpp000066400000000000000000000142651341430144300210760ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "EmulationThread.h" /** * Constructor. */ EmulationThread::EmulationThread(QGLImage *qglimage) : screen(qglimage) { // Allocate buffer of the texture size. videoBuffer = NULL; QObject::connect(this, SIGNAL(newResolution(int, int)), qglimage, SLOT(resolutionChanged(int, int))); setResolution(qglimage->getTextureWidth(), qglimage->getTextureHeight()); emulationState = EMULATION_STOPPED; // Set default refresh slow arbitrary frequency. setRefreshFrequency(1.0f); done = false; } /** * Destructor. */ EmulationThread::~EmulationThread() { delete []videoBuffer; } /** * This method overrides QThread run(). It's the thread main method. * * Return : None. */ void EmulationThread::run() { struct timeval t0, t1; struct timespec rqtp, rmtp; unsigned int deltaT_micros, remainingT; while(!done) { emulationStateQMutex.lockForRead(); switch(emulationState) { case EMULATION_STOPPED: // Free QMutex. emulationStateQMutex.unlock(); // Sleep 20ms. rqtp.tv_sec = 0; rqtp.tv_nsec = 20 * 1000 * 1000; // 20 millisecond. nanosleep(&rqtp, &rmtp); break; case EMULATION_RUNNING: // Free QMutex. emulationStateQMutex.unlock(); // Execute one emulation frame, blit texture into openGL // and calculate the duration of these operations. gettimeofday(&t0, NULL); emulateOneFrame(); screen->blit(videoBuffer); gettimeofday(&t1, NULL); // Compute duration. deltaT_micros = ((t1.tv_sec * 1000000 + t1.tv_usec) - (t0.tv_sec * 1000000 + t0.tv_usec)); // Compute remaining time to achieve the good regreshing period. remainingT = (deltaT_micros < refreshingPeriod) ? refreshingPeriod - deltaT_micros : 1; // Sleep the remaining time. rqtp.tv_sec = 0; rqtp.tv_nsec = remainingT * 1000; // microsecond to nanoseconds nanosleep(&rqtp, &rmtp); //cout << "Loop takes :" << deltaT_micros << " microseconds, sleeping "<< remainingT << " microseconds "<< endl; break; case EMULATION_ABORTED: done = true; emulationStateQMutex.unlock(); break; default: // Free QMutex. emulationStateQMutex.unlock(); break; } } } /** * This method will abort Emulation. This will cause the emulation thread * to die. * * Return : None. * */ void EmulationThread::abortEmulation() { QWriteLocker lock(&emulationStateQMutex); emulationState = EMULATION_ABORTED; } /** * This method will start Emulation. If emulation is already started, it * does nothing. * * Return : None. * */ void EmulationThread::startEmulation() { QWriteLocker lock(&emulationStateQMutex); emulationState = EMULATION_RUNNING; } /** * This method will suspends Emulation. To continue, one should call * resume() method. * * Return : None. * */ void EmulationThread::pauseEmulation() { QWriteLocker lock(&emulationStateQMutex); emulationState = EMULATION_STOPPED; } /** * This method will resume Emulation that has previously been stopped * using pauseEmulation(); * * Return : None. * */ void EmulationThread::resumeEmulation() { QWriteLocker lock(&emulationStateQMutex); startEmulation(); } /** * This method will reset/restart Emulation. It's equivalent to a * hardware reset. * * Return : None. * */ void EmulationThread::resetEmulation() { } /** * This method set the refreshing period of the emulation thread. * Important note : The QThread::run method will call repeatly the * emulateOneFrame() methods which should perform emulation stuff for * exactly one frame. The execution time of emulateOneFrame() is * calculated, and the remaining time to reach the refreshing period * is wasted in nanosleep. * * Param 1 : The refresh frequency in Hertz of the emulation. This value * should be the display original emulated refresh display. * * Return : None. */ void EmulationThread::setRefreshFrequency(float f) { float t = (1.0 / f); refreshingPeriod = (t * 1000000.0f); // to microseconds //cout << "refreshingPeriod = " << refreshingPeriod << " microsec." << endl; } /** * This method will change the textureSize that is mapped on the GL QUAD. It * usually happens on emulated video mode change. The texture buffer is * deleted and reallocated, and a signal emitted to inform QGLimage of this * event. * * Param 1 : new texture width. * * Param 2 : new texture height. * * Return : None. * */ void EmulationThread::setResolution(int w, int h) { delete []videoBuffer; int s = w * h; videoBuffer = new unsigned int[s]; memset(videoBuffer, 0, s * sizeof(unsigned int)); emit newResolution(w, h); } /** * This method is used to receive key press trigger. It's not declared * as a slot in order to avoid slot connection/deconnection on ROM change. * To implement a different behaviour from the default one, simply override * this method. * * Param 1 : QT key() value of the QKeyEvent that signal keyPressed. * * Return : None. */ void EmulationThread::keyPressed(padKey) { } /** * This method is used to receive key press trigger. It's not declared * as a slot in order to avoid slot connection/deconnection on ROM change. * To implement a different behaviour from the default one, simply override * this method. * * Param 1 : QT key() value of the QKeyEvent that signal keyPressed. * * Return : None. */ void EmulationThread::keyReleased(padKey) { } osmose-emulator-1.4/src/EmulationThread.h000066400000000000000000000036561341430144300205450ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef EMULATIONTHREAD_H #define EMULATIONTHREAD_H #include #include #include #include #include "QGLImage.h" #include "OsmoseConfigurationFile.h" using namespace std; class EmulationThread : public QThread { Q_OBJECT; enum EmulationState { EMULATION_STOPPED = 0, EMULATION_RUNNING, EMULATION_ABORTED }; public: EmulationThread(QGLImage *qglimage); virtual ~EmulationThread(); void abortEmulation(); public slots: void pauseEmulation(); void resumeEmulation(); void startEmulation(); virtual void resetEmulation(); virtual void keyPressed(padKey key); virtual void keyReleased(padKey key); signals: void newResolution(int w, int h); protected: unsigned int *videoBuffer; void run(); virtual void emulateOneFrame() = 0; void setRefreshFrequency(float usec); void setResolution(int w, int h); private: bool done; QReadWriteLock emulationStateQMutex; QGLImage *screen; unsigned int refreshingPeriod; EmulationState emulationState; }; #endif // EMULATIONTHREAD_H osmose-emulator-1.4/src/FIFOSoundBuffer.cpp000066400000000000000000000052331341430144300206720ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "FIFOSoundBuffer.h" #include FIFOSoundBuffer::FIFOSoundBuffer(u32 size) { data_ = new s16 [size]; data_size_ = size; generated_index_ = 0; played_index_ = 0; total_generated_ = 0; total_played_ = 0; } bool FIFOSoundBuffer::write(s16 value) { if ( spaceAvailable() ) { /* We have free space in our buffer. */ data_[ generated_index_++ ] = value; total_generated_++; /* Do we reach the end of the buffer ?*/ if (generated_index_ == data_size_) { generated_index_ = 0; } return true; } else { //printf("BF\n"); /* The buffer is full, cancel write operation. */ return false; } } /* read a single value if available. */ /* If no values are available return 0. */ s16 FIFOSoundBuffer::read() { if (dataAvailable()) { s16 ret = data_[played_index_++]; total_played_++; if (played_index_ == data_size_) { played_index_ = 0; } return ret; } else { //printf("BE\n"); return 0; } } //#include //using namespace std; /* Read multiple values. If there are not enough value available in the buffer */ /* Data will be filled with 00. */ void FIFOSoundBuffer::read(s16 *dst, u32 nbr) { //cout << "Asked:" << nbr << " Avail: " << numberDataAvailable() << endl; /* We have enough sample, copy them ! */ for (u32 i = 0; i < nbr; i++) { dst[i] = read(); } //printf(" Rem: %d\n",numberDataAvailable()); } /* Read multiple values. */ void FIFOSoundBuffer::reset() { generated_index_ = 0; played_index_ = 0; total_generated_ = 0; total_played_ = 0; } osmose-emulator-1.4/src/FIFOSoundBuffer.h000066400000000000000000000041771341430144300203450ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef FIFO_SOUND_BUFFER_H #define FIFO_SOUND_BUFFER_H #include "BasicTypes.h" class FIFOSoundBuffer { public: /* Constructor. */ FIFOSoundBuffer(u32 size); /* Destructor. */ ~FIFOSoundBuffer() { delete[] data_ ; } /* Write a value if buffer is not full. */ bool write(s16 value); /* read a single value if available. */ inline s16 read(); /* Read multiple values. */ void read(s16 *, u32 nbr); /* Return true if at least one sample is available. */ bool dataAvailable() { return (total_generated_ > total_played_); } /* return true is there is space for more sample. */ bool spaceAvailable() { return (total_generated_ - total_played_ < data_size_); } u32 numberDataAvailable() { return total_generated_ - total_played_; } /* Reset the FIFO. */ void reset(); private: u32 data_size_; /* Size of the circular buffer. */ s16 *data_; /* Pointer to our buffer. */ u32 generated_index_; u32 played_index_; u32 total_generated_; u32 total_played_; }; #endif osmose-emulator-1.4/src/IOMapper.cpp000066400000000000000000000203471341430144300174630ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "IOMapper.h" #include "Bits.h" /* Constructor need VDP reference */ IOMapper::IOMapper(VDP & v, SN76489 & p) : vdp( v ), psg( p ) { reset(); } /*----------------------------------------------------------------------*/ /* This method resets ports. */ /*----------------------------------------------------------------------*/ void IOMapper::reset() { if (opt.inputType == DEFAULT_PAD) { port3F = 0xFF; // Active low } else if (opt.inputType == PADDLE) { port3F = 0x30; // 00110000b } port3E = 0xA4; portPAD1 = 0xFF; portPAD2 = 0xFF; paddleValue = 0; flipFlop = false; } /*----------------------------------------------------------------------*/ /* Based on Charles MacDonald documentation, this method dispatches */ /* port write, depending on A7, A6 and A0 address line. */ /*----------------------------------------------------------------------*/ void IOMapper::out8(unsigned port, unsigned char value) { if (port <= 0x3F) { if (port & BIT0) // Write to port 3F { #ifdef AUTO_NAT_VERBOSE cout << "AUTO_NAT port 0x3F written with value " << hex << setw(2) << setfill('0') << (int)value << endl; #endif port3F = value; if ( (port3F & BIT0) && (port3F & BIT2) ) { #ifdef AUTO_NAT_VERBOSE cout << "Auto nationalisation asked." << endl; #endif if (opt.WorldVersion == EXPORT) { // Copy 3F bit7 to DD bit7 if (port3F & BIT7) { portPAD2 |= BIT7; } else { portPAD2 &= (0x7F); } // Copy 3F bit5 to DD bit6 if (port3F & BIT5) { portPAD2 |= BIT6; } else { portPAD2 &= 0xBF; } } else { portPAD2 &= 0x3F; } if ( ((value & BIT0) && (value & BIT2))== 0 ) { #ifdef AUTO_NAT_VERBOSE cout << "Auto nationalisation reset asked." << endl; #endif } } if (port3F & BIT5) { // cout << "Selecting X7-X4 value on DC" << endl; } else { // cout << "Selecting X3-X0 value on DC" << endl; } return; } else // Write to port 3E { #ifdef MEM_CTRL_VERBOSE cout << "MEM CTRL port 0x3E written with value " << hex << setw(2) << setfill('0') << (int)value << endl; #endif port3E = value; #ifdef MEM_CTRL_VERBOSE if (value & BIT2) { cout << "I/O chip Disable." << endl; } else { cout << "I/O chip Enabled." << endl; } if (value & BIT3) { cout << "BIOS ROM Disable." << endl; } else { cout << "BIOS ROM Enabled." << endl; } if (value & BIT4) { cout << "Work Ram Disable (For battery backed RAM ?)." << endl; } else { cout << "Work Ram Enable." << endl; } if (value & BIT5) { cout << "Card slot Disable." << endl; } else { cout << "Card slot Enable." << endl; } if (value & BIT6) { cout << "Cartridge slot Disable." << endl; } else { cout << "Cartridge slot Enable." << endl; } if (value & BIT7) { cout << "Expansion slot Disable." << endl; } else { cout << "Expansion slot Enable." << endl; } #endif return; } } if (port <= 0x7F) { psg.writePort(value); return; #ifdef PSG_VERBOSE cout << "PSG port 0x7F written with value " << hex << setw(2) << setfill('0') << (int)value << endl; #endif return; } if (port <= 0xBF) { if (port & BIT0) // Write on VDP Ctrl Port 0xBF { #ifdef VDP_ACCESS cout << "VDP_CTRL port 0xBF written with value " << hex << setw(2) << setfill('0') << (int)value << endl; #endif vdp.writeCtrlPort( value ); return; } else // Write on VDP Data Port 0xBE { #ifdef VDP_VERBOSE cout << "VDP_DATA port 0xBE written with value " << hex << setw(2) << setfill('0') << (int)value << endl; #endif vdp.writeDataPort( value ); return; } } #ifdef VDP_VERBOSE cout << "Unknown port "<< hex << setw(2) << setfill('0') << (int)port << " written with value " << hex << setw(2) << setfill('0') << (int)value << endl; #endif } /*----------------------------------------------------------------------*/ /* Based on Charles MacDonald documentation, this method dispatches */ /* port read, depending on A7, A6 and A0 address line. */ /*----------------------------------------------------------------------*/ unsigned char IOMapper::in8(unsigned port) { if (port == 0x3E) { return port3E; //cout << "MEM CTRL Port 0x3E: Read, value is " << hex << setw(2) << setfill('0') << (int)port3E << endl; } if (port <= 0x3F) { //cout << "NOT IMPLEMENTED / EXPERIMENTAL: Read port <=0x3f" << endl; return (port & 0xff); } if (port <= 0x7F) { if (port & BIT0) // Read H counter port. { //#ifdef VDP_VERBOSE cout << "NOT IMPLEMENTED: VDP port H COUNTER 0x7F read."<< endl; //#endif return 0xFF; } else // Read on VDP Vertical counter { #ifdef VDP_VERBOSE cout << "VDP, port V COUNTER 0x7E read."<< endl; #endif return vdp.v_counter; } } if (port <= 0xBF) // Read VDP status flag { if (port & BIT0) { #ifdef VDP_VERBOSE cout << "VDP status read."<< endl; #endif return vdp.readStatusFlag(); } else // Read VDP Data port { #ifdef VDP_VERBOSE cout << "CRAM/VRAM read."<< endl; #endif return vdp.readDataPort(); } } // Port is > 0xBF and < 0xFF if (port & BIT0) { #ifdef PAD_VERBOSE cout << "Port PAD2 0xDD read."<< endl; #endif return portPAD2; } else { #ifdef PAD_VERBOSE cout << "Port PAD1 0xDC read."<< endl; #endif if (opt.inputType == PADDLE) { flipFlop^=1; if (flipFlop == true) { portPAD1 |= BIT5; portPAD1 &= 0xf0; portPAD1 |= (paddleValue >> 4); } else { portPAD1 &= ~BIT5; portPAD1 &= 0xf0; portPAD1 |= (paddleValue & 0x0f); } } return portPAD1; } cout << "Unknown port "<< hex << setw(2) << setfill('0') << (int)port << " read."<< endl; } osmose-emulator-1.4/src/IOMapper.h000066400000000000000000000043251341430144300171260ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef IO_MAPPER_H #define IO_MAPPER_H #include "Definitions.h" #include #include #include "VDP.h" #include "SN76489.h" #include "Options.h" #include "DebugEventThrower.h" extern Options opt; using namespace std; class IOMapper : public DebugEventThrower { protected: VDP &vdp; // Reference on VDP object. SN76489 &psg; // Reference on PSG object. public: IOMapper(VDP &, SN76489 &); // Constructor. virtual ~IOMapper() {}; unsigned char paddleValue; // Paddle knob value. bool flipFlop; unsigned char port3E; // Memory control. unsigned char port3F; // Auto nationalisation port. unsigned char portPAD1; // Joypad port 1. unsigned char portPAD2; // Joypad port 2. unsigned char WorldVersion; // Sms type. virtual void reset(); virtual void out8(unsigned address, unsigned char value); virtual unsigned char in8(unsigned address); // These GAMEGEAR ports are here but not readable from IOMapper::in(). // They are readable with IOMapper_GG::in() unsigned char port0x0; unsigned char port0x1; unsigned char port0x2; unsigned char port0x3; unsigned char port0x4; unsigned char port0x5; unsigned char port0x6; }; #endif osmose-emulator-1.4/src/IOMapper_GG.cpp000066400000000000000000000104221341430144300200310ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "IOMapper_GG.h" #include // Constructor. IOMapper_GG::IOMapper_GG(VDP &v, SN76489 &p) : IOMapper(v, p) { reset(); } // Reset GAMEGEAR additionnal ports. void IOMapper_GG::reset() { IOMapper::reset(); port0x0 = 0xC0; port0x1 = 0x7F; port0x2 = 0xFF; port0x3 = 0x00; port0x4 = 0xFF; port0x5 = 0x00; port0x6 = 0xFF; } /*----------------------------------------------------------------------*/ /* Based on Charles MacDonald documentation, this method dispatches */ /* port read, depending on A7, A6 and A0 address line. */ /*----------------------------------------------------------------------*/ unsigned char IOMapper_GG::in8(unsigned port) { if (port == 0x0) return port0x0; if (port == 0x1) return port0x1; if (port == 0x2) return port0x2; if (port == 0x3) return port0x3; if (port == 0x4) return port0x4; if (port == 0x5) return port0x5; if (port == 0x6) return port0x6; if (port == 0x3E) { return port3E; cout << "MEM CTRL Port 0x3E: Read, value is " << hex << setw(2) << setfill('0') << (int)port3E << endl; } if (port <= 0x3F) { //cout << "NOT IMPLEMENTED / EXPERIMENTAL: Read port <=0x3f" << endl; return (port & 0xff); } if (port <= 0x7F) { if (port & BIT0) // Read H counter port. { #ifdef VDP_VERBOSE cout << "NOT IMPLEMENTED: VDP port H COUNTER 0x7F read."<< endl; #endif return 0xFF; } else // Read on VDP Vertical counter { #ifdef VDP_VERBOSE cout << "VDP, port V COUNTER 0x7E read."<< endl; #endif return vdp.v_counter; } } if (port <= 0xBF) // Read VDP status flag { if (port & BIT0) { #ifdef VDP_VERBOSE cout << "VDP status read."<< endl; #endif return vdp.readStatusFlag(); } else // Read VDP Data port { #ifdef VDP_VERBOSE cout << "CRAM/VRAM read."<< endl; #endif return vdp.readDataPort(); } } // Port is > 0xBF and < 0xFF if (port & BIT0) { #ifdef PAD_VERBOSE cout << "Port PAD2 0xDD read."<< endl; #endif return portPAD2; } else { #ifdef PAD_VERBOSE cout << "Port PAD1 0xDC read."<< endl; #endif if (opt.inputType == PADDLE) { flipFlop^=1; if (flipFlop == true) { portPAD1 |= BIT5; portPAD1 &= 0xf0; portPAD1 |= (paddleValue >> 4); } else { portPAD1 &= ~BIT5; portPAD1 &= 0xf0; portPAD1 |= (paddleValue & 0x0f); } } return portPAD1; } cout << "Unknown port "<< hex << setw(2) << setfill('0') << (int)port << " read."<< endl; } void IOMapper_GG::out8(unsigned address, unsigned char data) { /* Call parent method. */ if (address == 0) { port0x0 = data; return; } if (address == 1) { port0x1 = data; return; } if (address == 2) { port0x2 = data; return; } if (address == 3) { port0x3 = data; return; } if (address == 4) { port0x4 = data; return; } if (address == 5) { port0x5 = data; return; } IOMapper::out8( address, data); } osmose-emulator-1.4/src/IOMapper_GG.h000066400000000000000000000024121341430144300174760ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef IO_MAPPER_GG_H #define IO_MAPPER_GG_H #include "IOMapper.h" using namespace std; class IOMapper_GG : public IOMapper { public: IOMapper_GG(VDP &, SN76489 &); // Constructor. virtual ~IOMapper_GG() {}; void reset(); unsigned char in8(unsigned address); void out8(unsigned address, unsigned char data); private: }; #endif osmose-emulator-1.4/src/Joystick.cpp000066400000000000000000000106601341430144300176030ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include #include "Joystick.h" #include #include #include /** * Constructor. Throw an exception in case of failure. * * Param1 : The device name to read from. e.g: /dev/input/js0 * Param2 : The JoystickListener that will be notified with jostick events * */ Joystick::Joystick(const char *dev_name, JoystickListener *lstnr) { // Try to open the device. joystickFD = ::open(dev_name, O_RDONLY | O_NONBLOCK); if (joystickFD < 0) { string err = "Unable to open device '"; err = err + dev_name; err = err + "' : "; err = err + strerror(errno); throw err; } // Device successfully opened. Keep track of device name. ::memcpy(deviceName, dev_name, MAX_DEVNAME_LEN); // Now get Joystick ID. if (::ioctl(joystickFD, JSIOCGNAME(MAX_JOYID_LEN), joystickID) < 0) { ::strncpy(joystickID, "Unknown", MAX_JOYID_LEN); } // Now get button number. if (::ioctl(joystickFD, JSIOCGBUTTONS, &buttonNbr) < 0) { buttonNbr = 0; } // Now get Axis number. if (::ioctl(joystickFD, JSIOCGAXES, &axisNbr) < 0) { axisNbr = 0; } // Now get driver version. if (::ioctl(joystickFD, JSIOCGVERSION, &driverVersion) < 0) { driverVersion = 0xFFFFFFFF; } // Keep track of listener for upcoming events. setListener(lstnr); // Set default polling period. setPollingPeriod(DEFAULT_POLLING_PERIOD); // in milliseconds. // Start device polling. done = false; this->start(); } /** * setPollingPeriod: * * Param1 : the delay between two non blocking read on the device file. * Unit is millisecond. If value is negative or equal to zero, the default * polling period will be used. * */ void Joystick::setPollingPeriod(int pp_ms) { pollingPeriod = (pp_ms <= 0) ? DEFAULT_POLLING_PERIOD: pp_ms; } /** * This method reads the joystick file descriptor for new events. * return true if an event has been read, false otherwise. Unfortunatelly, * no data, and joystick unplugged return the same error 11 : * 'Resource temporarily unavailable'. We cannot simply detect if joystick * is present or not. */ bool Joystick::readDevice(struct js_event *jse) { int bytes_read; bytes_read = ::read(joystickFD, jse, sizeof(*jse)); // Handle errors !!! if (bytes_read == -1) { return false; } return true; } /** * Thread main loop : * This is the polling routine of the joystick handler. */ void *Joystick::run(void *) { struct timespec rqtp, rmtp; struct js_event jse; while(!done) { // read the Joystick file descriptor until no more events are available. while (readDevice(&jse) == true) { if (jse.type & 0x80) continue; // Skip JS_EVENT_INIT (0x80) events. switch(jse.type) { case JS_EVENT_BUTTON: { // Inform the listener that button event occurs. bool pressed = (jse.value != 0); listener->buttonChanged(jse.number, pressed); } break; case JS_EVENT_AXIS: { // Inform the listener that axis event occurs. switch(jse.number) { case 0: listener->xAxisChanged(jse.value); break; case 1: listener->yAxisChanged(jse.value); break; } } break; default: break; } } // No more event to handle. // Sleep for the polling period. rqtp.tv_sec = 0; rqtp.tv_nsec = pollingPeriod * 1000 * 1000; nanosleep(&rqtp, &rmtp); } return NULL; } /** * * Destructor. Throw an exception in case of failure. * */ Joystick::~Joystick() { done = true; this->join(NULL); ::close(joystickFD); } osmose-emulator-1.4/src/Joystick.h000066400000000000000000000050531341430144300172500ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef JOYSTICK_H #define JOYSTICK_H #include #include #include #include #include #include #include #include "Pthreadcpp.h" using namespace std; #define MAX_DEVNAME_LEN 128 #define MAX_JOYID_LEN 128 #define DEFAULT_POLLING_PERIOD 3 /** * Joystick listener interface. * Inherit this class and provide virtual methods in order to be a full Joystick listener. */ class JoystickListener { public: virtual void buttonChanged(unsigned int button, bool pressed) = 0; /* True when pressed */ virtual void xAxisChanged(int value) = 0; virtual void yAxisChanged(int value) = 0; virtual void joystickError() = 0; }; class Joystick : public Thread { public: Joystick(const char *dev_name, JoystickListener *l); const char * getStrID() { return joystickID; } const char * getDeviceName() { return deviceName; } void setListener(JoystickListener *lstnr) { listener = lstnr; } void setPollingPeriod(int ms); int getPollingPeriod() { return pollingPeriod; } unsigned int getAxisNumber() { return (unsigned int)axisNbr; } unsigned int getButtonNumber() { return (unsigned int)buttonNbr; } unsigned int getDriverVersion() {return driverVersion; } ~Joystick(); protected: void *run(void *); private: char deviceName[MAX_DEVNAME_LEN]; char joystickID[MAX_JOYID_LEN]; int joystickFD; unsigned char axisNbr; unsigned char buttonNbr; unsigned int driverVersion; // Unused-Major-Minor-Lower 8 bits packed. JoystickListener *listener; int pollingPeriod; bool done; bool readDevice(struct js_event *jse); }; #endif // JOYSTICK_H osmose-emulator-1.4/src/KeyMapper.cpp000066400000000000000000000322441341430144300177030ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "KeyMapper.h" KeyMapper * KeyMapper::instance = NULL; const key_map KeyMapper::keymap[KEY_NBR] = { {"Escape", 0x01000000}, {"Tab", 0x01000001}, {"Backtab", 0x01000002}, {"Backspace", 0x01000003}, {"Return", 0x01000004}, {"Enter", 0x01000005}, {"Insert", 0x01000006}, {"Delete", 0x01000007}, {"Pause", 0x01000008}, {"Print", 0x01000009}, {"SysReq", 0x0100000a}, {"Clear", 0x0100000b}, {"Home", 0x01000010}, {"End", 0x01000011}, {"Left", 0x01000012}, {"Up", 0x01000013}, {"Right", 0x01000014}, {"Down", 0x01000015}, {"PageUp", 0x01000016}, {"PageDown", 0x01000017}, {"Shift", 0x01000020}, {"Control", 0x01000021}, {"Meta", 0x01000022}, {"Alt", 0x01000023}, {"AltGr", 0x01001103}, {"CapsLock", 0x01000024}, {"NumLock", 0x01000025}, {"ScrollLock", 0x01000026}, {"F1", 0x01000030}, {"F2", 0x01000031}, {"F3", 0x01000032}, {"F4", 0x01000033}, {"F5", 0x01000034}, {"F6", 0x01000035}, {"F7", 0x01000036}, {"F8", 0x01000037}, {"F9", 0x01000038}, {"F10", 0x01000039}, {"F11", 0x0100003a}, {"F12", 0x0100003b}, {"F13", 0x0100003c}, {"F14", 0x0100003d}, {"F15", 0x0100003e}, {"F16", 0x0100003f}, {"F17", 0x01000040}, {"F18", 0x01000041}, {"F19", 0x01000042}, {"F20", 0x01000043}, {"F21", 0x01000044}, {"F22", 0x01000045}, {"F23", 0x01000046}, {"F24", 0x01000047}, {"F25", 0x01000048}, {"F26", 0x01000049}, {"F27", 0x0100004a}, {"F28", 0x0100004b}, {"F29", 0x0100004c}, {"F30", 0x0100004d}, {"F31", 0x0100004e}, {"F32", 0x0100004f}, {"F33", 0x01000050}, {"F34", 0x01000051}, {"F35", 0x01000052}, {"Super_L", 0x01000053}, {"Super_R", 0x01000054}, {"Menu", 0x01000055}, {"Hyper_L", 0x01000056}, {"Hyper_R", 0x01000057}, {"Help", 0x01000058}, {"Direction_L", 0x01000059}, {"Direction_R", 0x01000060}, {"Space", 0x20}, {"Exclam", 0x21}, {"QuoteDbl", 0x22}, {"NumberSign", 0x23}, {"Dollar", 0x24}, {"Percent", 0x25}, {"Ampersand", 0x26}, {"Apostrophe", 0x27}, {"ParenLeft", 0x28}, {"ParenRight", 0x29}, {"Asterisk", 0x2a}, {"Plus", 0x2b}, {"Comma", 0x2c}, {"Minus", 0x2d}, {"Period", 0x2e}, {"Slash", 0x2f}, {"0", 0x30}, {"1", 0x31}, {"2", 0x32}, {"3", 0x33}, {"4", 0x34}, {"5", 0x35}, {"6", 0x36}, {"7", 0x37}, {"8", 0x38}, {"9", 0x39}, {"Colon", 0x3a}, {"Semicolon", 0x3b}, {"Less", 0x3c}, {"Equal", 0x3d}, {"Greater", 0x3e}, {"Question", 0x3f}, {"At", 0x40}, {"A", 0x41}, {"B", 0x42}, {"C", 0x43}, {"D", 0x44}, {"E", 0x45}, {"F", 0x46}, {"G", 0x47}, {"H", 0x48}, {"I", 0x49}, {"J", 0x4a}, {"K", 0x4b}, {"L", 0x4c}, {"M", 0x4d}, {"N", 0x4e}, {"O", 0x4f}, {"P", 0x50}, {"Q", 0x51}, {"R", 0x52}, {"S", 0x53}, {"T", 0x54}, {"U", 0x55}, {"V", 0x56}, {"W", 0x57}, {"X", 0x58}, {"Y", 0x59}, {"Z", 0x5a}, {"BracketLeft", 0x5b}, {"Backslash", 0x5c}, {"BracketRight", 0x5d}, {"AsciiCircum", 0x5e}, {"Underscore", 0x5f}, {"QuoteLeft", 0x60}, {"BraceLeft", 0x7b}, {"Bar", 0x7c}, {"BraceRight", 0x7d}, {"AsciiTilde", 0x7e}, {"nobreakspace", 0x0a0}, {"exclamdown", 0x0a1}, {"cent", 0x0a2}, {"sterling", 0x0a3}, {"currency", 0x0a4}, {"yen", 0x0a5}, {"brokenbar", 0x0a6}, {"section", 0x0a7}, {"diaeresis", 0x0a8}, {"copyright", 0x0a9}, {"ordfeminine", 0x0aa}, {"guillemotleft", 0x0ab}, {"notsign", 0x0ac}, {"hyphen", 0x0ad}, {"registered", 0x0ae}, {"macron", 0x0af}, {"degree", 0x0b0}, {"plusminus", 0x0b1}, {"twosuperior", 0x0b2}, {"threesuperior", 0x0b3}, {"acute", 0x0b4}, {"mu", 0x0b5}, {"paragraph", 0x0b6}, {"periodcentered", 0x0b7}, {"cedilla", 0x0b8}, {"onesuperior", 0x0b9}, {"masculine", 0x0ba}, {"guillemotright", 0x0bb}, {"onequarter", 0x0bc}, {"onehalf", 0x0bd}, {"threequarters", 0x0be}, {"questiondown", 0x0bf}, {"Agrave", 0x0c0}, {"Aacute", 0x0c1}, {"Acircumflex ", 0x0c2}, {"Atilde", 0x0c3}, {"Adiaeresis", 0x0c4}, {"Aring", 0x0c5}, {"AE", 0x0c6}, {"Ccedilla", 0x0c7}, {"Egrave", 0x0c8}, {"Eacute", 0x0c9}, {"Ecircumflex", 0x0ca}, {"Ediaeresis", 0x0cb}, {"Igrave", 0x0cc}, {"Iacute", 0x0cd}, {"Icircumflex", 0x0ce}, {"Idiaeresis", 0x0cf}, {"ETH", 0x0d0}, {"Ntilde", 0x0d1}, {"Ograve", 0x0d2}, {"Oacute", 0x0d3}, {"Ocircumflex", 0x0d4}, {"Otilde", 0x0d5}, {"Odiaeresis", 0x0d6}, {"multiply", 0x0d7}, {"Ooblique", 0x0d8}, {"Ugrave", 0x0d9}, {"Uacute", 0x0da}, {"Ucircumflex", 0x0db}, {"Udiaeresis", 0x0dc}, {"Yacute", 0x0dd}, {"THORN", 0x0de}, {"ssharp", 0x0df}, {"division", 0x0f7}, {"ydiaeresis", 0x0ff}, {"Multi_key", 0x01001120}, {"Codeinput", 0x01001137}, {"SingleCandidate", 0x0100113c}, {"MultipleCandidate", 0x0100113d}, {"PreviousCandidate", 0x0100113e}, {"Mode_switch", 0x0100117e}, {"Kanji", 0x01001121}, {"Muhenkan", 0x01001122}, {"Henkan", 0x01001123}, {"Romaji", 0x01001124}, {"Hiragana", 0x01001125}, {"Katakana", 0x01001126}, {"Hiragana_Katakana", 0x01001127}, {"Zenkaku", 0x01001128}, {"Hankaku", 0x01001129}, {"Zenkaku_Hankaku", 0x0100112a}, {"Touroku", 0x0100112b}, {"Massyo", 0x0100112c}, {"Kana_Lock", 0x0100112d}, {"Kana_Shift", 0x0100112e}, {"Eisu_Shift", 0x0100112f}, {"Eisu_toggle", 0x01001130}, {"Hangul", 0x01001131}, {"Hangul_Start", 0x01001132}, {"Hangul_End", 0x01001133}, {"Hangul_Hanja", 0x01001134}, {"Hangul_Jamo", 0x01001135}, {"Hangul_Romaja", 0x01001136}, {"Hangul_Jeonja", 0x01001138}, {"Hangul_Banja", 0x01001139}, {"Hangul_PreHanja", 0x0100113a}, {"Hangul_PostHanja", 0x0100113b}, {"Hangul_Special", 0x0100113f}, {"Dead_Grave", 0x01001250}, {"Dead_Acute", 0x01001251}, {"Dead_Circumflex", 0x01001252}, {"Dead_Tilde", 0x01001253}, {"Dead_Macron", 0x01001254}, {"Dead_Breve", 0x01001255}, {"Dead_Abovedot", 0x01001256}, {"Dead_Diaeresis", 0x01001257}, {"Dead_Abovering", 0x01001258}, {"Dead_Doubleacute", 0x01001259}, {"Dead_Caron", 0x0100125a}, {"Dead_Cedilla", 0x0100125b}, {"Dead_Ogonek", 0x0100125c}, {"Dead_Iota", 0x0100125d}, {"Dead_Voiced_Sound", 0x0100125e}, {"Dead_Semivoiced_Sound", 0x0100125f}, {"Dead_Belowdot", 0x01001260}, {"Dead_Hook", 0x01001261}, {"Dead_Horn", 0x01001262}, {"Back", 0x01000061}, {"Forward", 0x01000062}, {"Stop", 0x01000063}, {"Refresh", 0x01000064}, {"VolumeDown", 0x01000070}, {"VolumeMute", 0x01000071}, {"VolumeUp", 0x01000072}, {"BassBoost", 0x01000073}, {"BassUp", 0x01000074}, {"BassDown", 0x01000075}, {"TrebleUp", 0x01000076}, {"TrebleDown", 0x01000077}, {"MediaPlay", 0x01000080}, {"MediaStop", 0x01000081}, {"MediaPrevious", 0x01000082}, {"MediaNext", 0x01000083}, {"MediaRecord", 0x01000084}, {"MediaPause", 0x1000085}, {"MediaTogglePlayPause", 0x1000086}, {"HomePage", 0x01000090}, {"Favorites", 0x01000091}, {"Search", 0x01000092}, {"Standby", 0x01000093}, {"OpenUrl", 0x01000094}, {"LaunchMail", 0x010000a0}, {"LaunchMedia", 0x010000a1}, {"Launch0", 0x010000a2}, {"Launch1", 0x010000a3}, {"Launch2", 0x010000a4}, {"Launch3", 0x010000a5}, {"Launch4", 0x010000a6}, {"Launch5", 0x010000a7}, {"Launch6", 0x010000a8}, {"Launch7", 0x010000a9}, {"Launch8", 0x010000aa}, {"Launch9", 0x010000ab}, {"LaunchA", 0x010000ac}, {"LaunchB", 0x010000ad}, {"LaunchC", 0x010000ae}, {"LaunchD", 0x010000af}, {"LaunchE", 0x010000b0}, {"LaunchF", 0x010000b1}, {"LaunchG", 0x0100010e}, {"LaunchH", 0x0100010f}, {"MonBrightnessUp", 0x010000b2}, {"MonBrightnessDown", 0x010000b3}, {"KeyboardLightOnOff", 0x010000b4}, {"KeyboardBrightnessUp", 0x010000b5}, {"KeyboardBrightnessDown", 0x010000b6}, {"PowerOff", 0x010000b7}, {"WakeUp", 0x010000b8}, {"Eject", 0x010000b9}, {"ScreenSaver", 0x010000ba}, {"WWW", 0x010000bb}, {"Memo", 0x010000bc}, {"LightBulb", 0x010000bd}, {"Shop", 0x010000be}, {"History", 0x010000bf}, {"AddFavorite", 0x010000c0}, {"HotLinks", 0x010000c1}, {"BrightnessAdjust", 0x010000c2}, {"Finance", 0x010000c3}, {"Community", 0x010000c4}, {"AudioRewind", 0x010000c5}, {"BackForward", 0x010000c6}, {"ApplicationLeft", 0x010000c7}, {"ApplicationRight", 0x010000c8}, {"Book", 0x010000c9}, {"CD", 0x010000ca}, {"Calculator", 0x010000cb}, {"ToDoList", 0x010000cc}, {"ClearGrab", 0x010000cd}, {"Close", 0x010000ce}, {"Copy", 0x010000cf}, {"Cut", 0x010000d0}, {"Display", 0x010000d1}, {"DOS", 0x010000d2}, {"Documents", 0x010000d3}, {"Excel", 0x010000d4}, {"Explorer", 0x010000d5}, {"Game", 0x010000d6}, {"Go", 0x010000d7}, {"iTouch", 0x010000d8}, {"LogOff", 0x010000d9}, {"Market", 0x010000da}, {"Meeting", 0x010000db}, {"MenuKB", 0x010000dc}, {"MenuPB", 0x010000dd}, {"MySites", 0x010000de}, {"News", 0x010000df}, {"OfficeHome", 0x010000e0}, {"Option", 0x010000e1}, {"Paste", 0x010000e2}, {"Phone", 0x010000e3}, {"Calendar", 0x010000e4}, {"Reply", 0x010000e5}, {"Reload", 0x010000e6}, {"RotateWindows", 0x010000e7}, {"RotationPB", 0x010000e8}, {"RotationKB", 0x010000e9}, {"Save", 0x010000ea}, {"Send", 0x010000eb}, {"Spell", 0x010000ec}, {"SplitScreen", 0x010000ed}, {"Support", 0x010000ee}, {"TaskPane", 0x010000ef}, {"Terminal", 0x010000f0}, {"Tools", 0x010000f1}, {"Travel", 0x010000f2}, {"Video", 0x010000f3}, {"Word", 0x010000f4}, {"Xfer", 0x010000f5}, {"ZoomIn", 0x010000f6}, {"ZoomOut", 0x010000f7}, {"Away", 0x010000f8}, {"Messenger", 0x010000f9}, {"WebCam", 0x010000fa}, {"MailForward", 0x010000fb}, {"Pictures", 0x010000fc}, {"Music", 0x010000fd}, {"Battery", 0x010000fe}, {"Bluetooth", 0x010000ff}, {"WLAN", 0x01000100}, {"UWB", 0x01000101}, {"AudioForward", 0x01000102}, {"AudioRepeat", 0x01000103}, {"AudioRandomPlay", 0x01000104}, {"Subtitle", 0x01000105}, {"AudioCycleTrack", 0x01000106}, {"Time", 0x01000107}, {"Hibernate", 0x01000108}, {"View", 0x01000109}, {"TopMenu", 0x0100010a}, {"PowerDown", 0x0100010b}, {"Suspend", 0x0100010c}, {"ContrastAdjust", 0x0100010d}, {"MediaLast", 0x0100ffff}, {"unknown", 0x01ffffff}, {"Call", 0x01100004}, {"Camera", 0x01100020}, {"CameraFocus", 0x01100021}, {"Context1", 0x01100000}, {"Context2", 0x01100001}, {"Context3", 0x01100002}, {"Context4", 0x01100003}, {"Flip", 0x01100006}, {"Hangup", 0x01100005}, {"No", 0x01010002}, {"Select", 0x01010000}, {"Yes", 0x01010001}, {"ToggleCallHangup", 0x01100007}, {"VoiceDial", 0x01100008}, {"LastNumberRedial", 0x01100009}, {"Execute", 0x01020003}, {"Printer", 0x01020002}, {"Play", 0x01020005}, {"Sleep", 0x01020004}, {"Zoom", 0x01020006}, {"Cancel", 0x01020001} }; /** * Singleton method to get unique instance of te KeyMapper object. * returns a pointer on KeyMapper. */ KeyMapper * KeyMapper::getInstance() { if (instance == NULL) { instance = new KeyMapper(); } return instance; } /** * This method take a qtkey in input and returns const char * describing * the key, a keyname. If the qtkey is not found, NULL is returned. */ const char * KeyMapper::getKeyDescription(unsigned int qtkey) { for (unsigned int i=0; i < KEY_NBR; i++) { if (keymap[i].qtkey == qtkey) { return keymap[i].keyname; } } return NULL; } /** * Constructor. */ KeyMapper::KeyMapper() { } /** * Destructor. */ KeyMapper::~KeyMapper() { } osmose-emulator-1.4/src/KeyMapper.h000066400000000000000000000024571341430144300173530ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef KEYMAPPER_H #define KEYMAPPER_H #include #define KEY_NBR 417 typedef struct { const char *keyname; unsigned int qtkey; } key_map; class KeyMapper { public: ~KeyMapper(); static KeyMapper* getInstance(); static const char* getKeyDescription(unsigned int qtkey); protected: private: static const key_map keymap[KEY_NBR]; static KeyMapper *instance; KeyMapper(); }; #endif // KEYMAPPER_H osmose-emulator-1.4/src/LogWindow.ui000066400000000000000000000042741341430144300175540ustar00rootroot00000000000000 LogWindow 0 0 497 345 0 0 Log window 0 2 QLayout::SetDefaultConstraint 1 1 1 1 QPlainTextEdit::NoWrap true Clear logs 1 0 Hide logs osmose-emulator-1.4/src/MemoryMapper.cpp000066400000000000000000000703511341430144300204240ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "MemoryMapper.h" #include "Options.h" #include "RomSpecificOption.h" #include #include #include #include "AnsiColorTerminal.h" extern Options opt; /*--------------------------------------------------------------------*/ /* Class constructor. It immediately load a given rom, and updates */ /* Memory mapper variables. */ /*--------------------------------------------------------------------*/ MemoryMapper::MemoryMapper(const char *rom_file, OsmoseConfigurationFile *conf) { configuration = conf; save_bbr = false; string n = string(rom_file); string ext; int last_separator_index = -1; unsigned int rom_crc; if (n.length() >=5) { ext = n.substr(n.length()-3,3); } else { string error_message = "Invalid ROM name.\nValid name is at least one letter, and extension. Ex: a.sms or b.zip"; throw error_message; } // Load SMS unzipped file. if (ext == "sms" || ext == "SMS") { rom_crc = LoadSMSRom(rom_file); string msg = "Switching emulator to SMS mode."; QLogWindow::getInstance()->appendLog(msg); } else if (ext == ".gg" || ext == ".GG") // Load GAMEGEAR unzipped file. { rom_crc = LoadSMSRom(rom_file); opt.MachineType = GAMEGEAR; string msg = "Switching emulator to GAMEGEAR mode."; QLogWindow::getInstance()->appendLog(msg); } else { string error_message = "Unknown file extension: " + ext + ". \nKnown extensions supported by Osmose are: .sms or .gg"; throw error_message; } /* Print the ROM CRC. */ //cout << "CRC32 = 0x"<< hex << setfill('0') << setw(8) << rom_crc << endl; /* Now check in RomSpecificDataBase if we need specific option to run the rom. */ SpecificRomOptionDatabase::getOptions( rom_crc, &opt ); // Now extract the rom name. for (unsigned int i=0; i < n.length(); i++) { if (n[i] == '\\' || n[i] == '/') { last_separator_index =i; } } int ext_lenght = 4; if (opt.MachineType == GAMEGEAR) ext_lenght = 3; rom_name = n.substr(last_separator_index+1, n.length() - (last_separator_index+1) - ext_lenght); // Allocate Central RAM (0xC000-0xDFFF mirrored) ram = new unsigned char[0x2000]; // Clear this RAM. for (int i=0; i<0x2000; i++) { ram[i] = 0; } // Allocate 32Ko RAM banks, (2*16 opt banks) for games that use it. sram = new unsigned char[0x8000]; bool restored_old_bbr = false; // Are there any battery backed memory save ? ostringstream oss; oss << configuration->getBBRPath() << "/" << rom_name << ".bbr"; ifstream file(oss.str().c_str(), ios::in | ios::binary); if (file.is_open() == true ) { // Now load 2*16Ko banks. file.read((char *)sram,0x8000); file.close(); restored_old_bbr = true; string msg ="Restored Battery Backed Ram (.bbr) file:"+ oss.str(); QLogWindow::getInstance()->appendLog(msg); } if (restored_old_bbr != true) { // No battery backed memory, clear this Optional RAM. for (int i=0; i<0x8000; i++) { sram[i] = 0x0; } } //dump_smem(0, 16*20); // Allocate 8Ko of ram for writes in rom. null_rom = new unsigned char[0x2000]; /* Init wr8_method pointer on default sega mapper. */ wr8_method = &MemoryMapper::wr8_sega_mapper; mapperType = SegaMapper; /* Rom is loaded, reset the MemoryMapper. */ reset(); } /*------------------------------------------------------------*/ /* This method reset paging to it's supposed initial value: */ /* page 0 on first rom bank, page1 on bank1 and so on. */ /*------------------------------------------------------------*/ void MemoryMapper::reset() { // Init Read map and Write map. read_map[0] = &cartridge[0x0000]; // 0x0000-0x1FFF rd_area_type[0] = Cartridge; block_in_rd_area[0] = 0; read_map[1] = &cartridge[0x2000]; // 0x2000-0x3FFF rd_area_type[1] = Cartridge; block_in_rd_area[1] = 1; read_map[2] = &cartridge[0x4000]; // 0x4000-0x5FFF rd_area_type[2] = Cartridge; block_in_rd_area[2] = 2; read_map[3] = &cartridge[0x6000]; // 0x6000-0x7FFF rd_area_type[3] = Cartridge; block_in_rd_area[3] = 3; read_map[4] = &cartridge[0x8000]; // 0x8000-0x9FFF rd_area_type[4] = Cartridge; block_in_rd_area[4] = 4; read_map[5] = &cartridge[0xA000]; // 0xA000-0xBFFF rd_area_type[5] = Cartridge; block_in_rd_area[5] = 5; read_map[6] = &ram[0]; // 0xC000-0xDFFF rd_area_type[6] = Ram; block_in_rd_area[6] = 0; read_map[7] = &ram[0]; // 0xE000-0xFFFF mirror of 0xC000-0xDFFF rd_area_type[7] = Ram; block_in_rd_area[7] = 0; write_map[0] = &null_rom[0]; // 0x0000-0x1FFF wr_area_type[0] = Null; block_in_wr_area[0] = 0; write_map[1] = &null_rom[0]; // 0x2000-0x3FFF wr_area_type[1] = Null; block_in_wr_area[1] = 0; write_map[2] = &null_rom[0]; // 0x4000-0x5FFF wr_area_type[2] = Null; block_in_wr_area[2] = 0; write_map[3] = &null_rom[0]; // 0x6000-0x7FFF wr_area_type[3] = Null; block_in_wr_area[3] = 0; write_map[4] = &null_rom[0]; // 0x8000-0x9FFF wr_area_type[4] = Null; block_in_wr_area[4] = 0; write_map[5] = &null_rom[0]; // 0xA000-0xBFFF wr_area_type[5] = Null; block_in_wr_area[5] = 0; write_map[6] = &ram[0]; // 0xC000-0xDFFF wr_area_type[6] = Ram; block_in_wr_area[6] = 0; write_map[7] = &ram[0]; // 0xE000-0xFFFF mirror of 0xC000-0xDFFF wr_area_type[7] = Ram; block_in_wr_area[7] = 0; // Init pagin registers From FFFC-FFFF. paging_regs[0] = 0; paging_regs[1] = 0; paging_regs[2] = 1; paging_regs[3] = 2; } /*------------------------------------------------------------*/ /* This is a debugging purpose function. */ /* Note that this method will dump banks without any banking */ /* purpose. It's not affected by paging. To dump paged bank */ /* use dump_page method. */ /*------------------------------------------------------------*/ void MemoryMapper::dump(unsigned char bank_n) { int address = 0; if (bank_n >= bank_nbr) { cout << "Warning, cannot dump bank " << bank_n << " This bank does not exists." << endl; return; } cout << "***Dumping rom bank[" << (int)bank_n << "] (File offset is 0x" << hex << setw(8) << setfill('0') << (bank_n * 16384) << ")." << endl; for (int i=0; i<1024; i++) { cout << hex << setw(4) << setfill('0') << (i*16) << ": "; for (int o=0;o<16;o++) { cout << hex << setw(2) << setfill('0') <<(int) read_map[bank_n][address++] << " "; } cout << endl; } } /*------------------------------------------------------------*/ /* This is a debugging purpose function. */ /* Note that this method will dump banks with banking purpose.*/ /* It dumps data mapped into pages. */ /*------------------------------------------------------------*/ void MemoryMapper::dump_page(unsigned char bank_n) { int address = 0; if (bank_n > 2) { cout << "Warning, cannot dump page " << bank_n << " This page does not exists." << endl; return; } cout << "Dumping rom page " << (int)bank_n << endl; for (int i=0; i<1024; i++) { cout << hex << setw(4) << setfill('0') << (i*16) << ": "; for (int o=0;o<8;o++) { cout << hex << setw(2) << setfill('0') <<(int) read_map[bank_n][address++] << " "; } cout << endl; } } /*------------------------------------------------------------*/ /* This is a debugging purpose function. */ /* Note that this method will memory using env rd functions. */ /*------------------------------------------------------------*/ void MemoryMapper::dump_mem(unsigned add, unsigned short nb_line) { for (int i=0; i*wr8_method)( address, value); } /*------------------------------------------------------------*/ /* This method handle every write operations done by the CPU */ /* accordingly to korean memory mapper. */ /* It handles bank switching, RAM/ROM writes. */ /* */ /* Note that address is already anded with 0xFFFF */ /*------------------------------------------------------------*/ void MemoryMapper::wr8_sega_mapper(unsigned address, unsigned char value) { int bnk = (address >> 13); write_map[bnk][address & 0x1FFF] = value; if (address >= 0xFFFC) { write_standard_paging_reg(address & 3, value); } } /*------------------------------------------------------------*/ /* This method handle every write operations done by the CPU */ /* accordingly to codeemaster memory mapper. */ /* It handles bank switching, RAM/ROM writes. */ /* write at 0x8000 changes rom banking. */ /* */ /* Note that address is already anded with 0xFFFF */ /*------------------------------------------------------------*/ void MemoryMapper::wr8_codemaster_mapper(unsigned address, unsigned char value) { int bnk = (address >> 13); if (address != 0x8000) { write_map[bnk][address & 0x1FFF] = value; } else { write_codemaster_paging_reg(value); } } /*------------------------------------------------------------*/ /* This method handle every write operations done by the CPU */ /* accordingly to korean memory mapper. */ /* It handles bank switching, RAM/ROM writes. */ /* write at 0xA000 changes rom banking page 2. */ /* */ /* Note that address is already anded with 0xFFFF */ /*------------------------------------------------------------*/ void MemoryMapper::wr8_korean_mapper(unsigned address, unsigned char value) { int bnk = (address >> 13); if (address != 0xA000) { write_map[bnk][address & 0x1FFF] = value; } else { int page = value % bank16Ko_nbr; /* Keep copy of 0xA000 paging reg, swap banks.*/ paging_regs[0] = value; read_map[4] = &cartridge[(page<<14)]; rd_area_type[4] = Cartridge; block_in_rd_area[4] = page * 2; read_map[5] = &cartridge[(page<<14)+0x2000]; rd_area_type[5] = Cartridge; block_in_rd_area[5] = page * 2 + 1; write_map[4] = null_rom; wr_area_type[4] = Null; block_in_wr_area[4] = 0; write_map[5] = null_rom; wr_area_type[5] = Null; block_in_wr_area[5] = 0; } } /*------------------------------------------------------------*/ /* This method handle every read operations done by the CPU. */ /* It handles bank switching, RAM/ROM reads. */ /* Note that address is already anded with 0xFFFF */ /*------------------------------------------------------------*/ unsigned char MemoryMapper::rd8(unsigned address) { unsigned char r=0; int bnk = address>> 13; // bnk is 0-7. if (address < 0x400) { r = cartridge[address & 0x1FFF]; } else { r = read_map[bnk][address & 0x1FFF]; } return r; } /*------------------------------------------------------------*/ /* This method is in charge of memory mapping. */ /* reg is the mapping register from FFFC-FFFF */ /* Value is the value written to this register. */ /*------------------------------------------------------------*/ void MemoryMapper::write_standard_paging_reg(int reg, unsigned char value) { int page; page = (value % bank16Ko_nbr); paging_regs[reg] = value; // Save paging registers. switch (reg) { // 0xFFFC is written. case 0: if (value & 8) // If true, An additionnal 32 Ko ram is mapped at 0x8000-BFFF { // If value & bit 4 is true, we map second 16 Bank. // else, it's the first. save_bbr = true; // Save flag for BBR. read_map[4] = &sram[(value & 4) ? 0x4000 : 0x0000]; rd_area_type[4] = SRam; block_in_rd_area[4] = (value & 4) ? 2 : 0; read_map[5] = &sram[(value & 4) ? 0x6000 : 0x2000]; rd_area_type[5] = SRam; block_in_rd_area[5] = (value & 4) ? 3 : 1; write_map[4] = &sram[(value & 4) ? 0x4000 : 0x0000]; wr_area_type[4] = SRam; block_in_wr_area[4] = (value & 4) ? 2 : 0; write_map[5] = &sram[(value & 4) ? 0x6000 : 0x2000]; wr_area_type[5] = SRam; block_in_wr_area[5] = (value & 4) ? 3 : 1; } else { // We are mapping rom from 0xFFFF register. int bloc = paging_regs[3] % bank16Ko_nbr; read_map[4] = &cartridge[(bloc << 14) + 0x0000]; rd_area_type[4] = Cartridge; block_in_rd_area[4] = bloc *2; read_map[5] = &cartridge[(bloc << 14) + 0x2000]; rd_area_type[5] = Cartridge; block_in_rd_area[5] = bloc *2 + 1; write_map[4] = null_rom; wr_area_type[4] = Null; block_in_wr_area[4] = 0; write_map[5] = null_rom; wr_area_type[5] = Null; block_in_wr_area[5] = 0; } break; // 0xFFFD is written, changing Page 0 case 1: #ifdef P_VERBOSE cout << "Mapping page0 on rom bank " << (unsigned int)(page) << endl; #endif read_map[0] = &cartridge[(page<<14)]; rd_area_type[0] = Cartridge; block_in_rd_area[0] = page *2; read_map[1] = &cartridge[(page<<14)+0x2000]; rd_area_type[1] = Cartridge; block_in_rd_area[1] = page *2 +1; break; // 0xFFFE is written. case 2: #ifdef P_VERBOSE cout << "Mapping page1 on rom bank " << (unsigned int)(page) << endl; #endif read_map[2] = &cartridge[(page<<14)]; rd_area_type[2] = Cartridge; block_in_rd_area[2] = page *2; read_map[3] = &cartridge[(page<<14)+0x2000]; rd_area_type[3] = Cartridge; block_in_rd_area[3] = page *2 +1; break; // 0xFFFF is written. case 3: if (!(paging_regs[0] & 0x08)) { #ifdef P_VERBOSE cout << "Mapping page2 on rom bank " << (unsigned int)(page) << endl; #endif read_map[4] = &cartridge[(page<<14)]; rd_area_type[4] = Cartridge; block_in_rd_area[4] = page *2; read_map[5] = &cartridge[(page<<14)+0x2000]; rd_area_type[5] = Cartridge; block_in_rd_area[5] = page *2 +1; } break; } } /*------------------------------------------------------------*/ /* This method is in charge of codemaster memory mapping. */ /* To use this mapping, emu must be called with -cm option. */ /* Value is the value written to this register. */ /*------------------------------------------------------------*/ void MemoryMapper::write_codemaster_paging_reg(unsigned char value) { int page = value % bank16Ko_nbr; /* Keep a copy of 0x8000, swap banks. */ paging_regs[0] = value; read_map[4] = &cartridge[(page<<14)]; rd_area_type[4] = Cartridge; block_in_rd_area[4] = page *2; read_map[5] = &cartridge[(page<<14)+0x2000]; rd_area_type[5] = Cartridge; block_in_rd_area[5] = page *2 +1; write_map[4] = null_rom; wr_area_type[4] = Null; block_in_wr_area[4] = 0; write_map[5] = null_rom; wr_area_type[5] = Null; block_in_wr_area[5] = 0; } /*------------------------------------------------------------*/ /* This method returns RAM Select Register mapped at 0xFFFC */ /*------------------------------------------------------------*/ unsigned char MemoryMapper::getRSR() { return paging_regs[0]; } /*------------------------------------------------------------*/ /* This method returns bank selector apped at 0xFFFD */ /*------------------------------------------------------------*/ unsigned char MemoryMapper::getFFFD() { return paging_regs[1]; } /*------------------------------------------------------------*/ /* This method returns bank selector apped at 0xFFFE */ /*------------------------------------------------------------*/ unsigned char MemoryMapper::getFFFE() { return paging_regs[2]; } /*------------------------------------------------------------*/ /* This method returns bank selector apped at 0xFFFF */ /*------------------------------------------------------------*/ unsigned char MemoryMapper::getFFFF() { return paging_regs[3]; } /*------------------------------------------------------------*/ /* This is a debug method, not used during normal emulation. */ /*------------------------------------------------------------*/ void MemoryMapper::DumpMappingPtr() { // for (int i=0; i <8;i++) // { // cout << "readMap[" << i << "]=" << (unsigned)read_map[i] << endl; // } } /*------------------------------------------------------------*/ /* This method loads not zipped Rom into cartridge memory. */ /*------------------------------------------------------------*/ unsigned int MemoryMapper::LoadSMSRom(const char *rom_file) { /* Open ROM with file pointer at the end of ROM. */ ifstream file(rom_file, ios::in | ios::binary | ios::ate); if (file.is_open() == false ) { string error_msg = "Unable to load cartridge from " + string(rom_file) + " archive file."; throw error_msg; } // Get the ROM size. rom_size = file.tellg(); /* Some rom seems to have a 512byte header. Skip it. */ if ((rom_size %1024) == 512) { string msg = "512 bytes ROM header Skipped."; QLogWindow::getInstance()->appendLog(msg); file.seekg(512, ios::beg); rom_size -= 512; } else { file.seekg(0, ios::beg); } DisplayROMSize(); // Save size of rom, in 8Ko bank units. bank_nbr = (rom_size / 8192); // Get at least 4 bank to handle all Z80 memory space. if (bank_nbr < 8) bank_nbr = 8; bank16Ko_nbr = bank_nbr /2; ostringstream oss; oss << "Cartdrige contains " << (int)bank16Ko_nbr << " 16Ko banks."; QLogWindow::getInstance()->appendLog(oss.str().c_str()); // Allocate RAM for the whole cartridge. if (rom_size < 65536) { // Allocate at least 64Ko of ROM cartridge = new unsigned char[65536]; memset(cartridge, 0, 65536); } else { cartridge = new unsigned char[rom_size]; memset(cartridge, 0, rom_size); } // Now load the ROM. file.read((char*)cartridge, rom_size); if (file.good()== false) { string error_msg = "Unable to load .sms file !"; throw error_msg; } file.close(); unsigned int crc = getCRC32(cartridge, rom_size); return crc; } /*------------------------------------------------------------*/ /* This method displays roms size in mb or kb. */ /*------------------------------------------------------------*/ void MemoryMapper::DisplayROMSize() { ostringstream oss; /* 128 is equivalent (romsize*8)/1024 */ if ((rom_size/128)> 1024) { oss << "ROM size is " << rom_size << " bytes (" << ((rom_size*8)/(1024*1024))<< " mbits)."; } else { oss << "ROM size is " << rom_size << " bytes (" << ((rom_size * 8)/1024)<< " kbits)."; } QLogWindow::getInstance()->appendLog(oss.str().c_str()); } /*------------------------------------------------------------*/ /* This method return Rom name, based on Rom name, but with */ /* no extension. */ /*------------------------------------------------------------*/ string MemoryMapper::getROMName() { return rom_name; } void MemoryMapper::save_battery_backed_memory(string filename) { // If bbr has been written: if (save_bbr) { ofstream file(filename.c_str(), ios::out | ios::binary); if (file.is_open() == false ) { string msg = "Unable to create .bbr file !"; QLogWindow::getInstance()->appendLog(msg); return; } // Now save 2*16Ko banks. file.write((const char*)sram,0x8000); file.flush(); file.close(); string msg = "Battery Backed Ram saved."; QLogWindow::getInstance()->appendLog(msg); } } /*------------------------------------------------------------*/ /* This method computes CRC32 calculation on an uncompressed */ /* ROM. It will be use for ROM that need special options, e.g */ /* -cm CodeMaster Mapper etc... */ /*------------------------------------------------------------*/ unsigned int MemoryMapper::getCRC32(unsigned char *buffer, unsigned int len) { unsigned int crc32_; unsigned long crc_table[256]; unsigned long c; unsigned int n, k; for (n = 0; n < 256; n++) { c = (unsigned long) n; for (k = 0; k < 8; k++) { if (c & 1) c = 0xedb88320L ^ (c >> 1); else c = c >> 1; } crc_table[n] = c; } crc32_ = 0xFFFFFFFF; for (n = 0; n < len; n++) { crc32_ = crc_table[(crc32_ ^ buffer[n]) & 0xff] ^ (crc32_ >> 8); } return crc32_; } void MemoryMapper::setMapperType(Mapper m) { switch (m) { case SegaMapper: wr8_method = &MemoryMapper::wr8_sega_mapper; break; case CodemasterMapper: wr8_method = &MemoryMapper::wr8_codemaster_mapper; break; case KoreanMapper: wr8_method = &MemoryMapper::wr8_korean_mapper; break; } /* Keep a copy for save states. */ mapperType = m; } /* Implemetntation of ImplementsSaveState. */ bool MemoryMapper::saveState( ofstream &ofs) { MemoryMapperSaveState mss; mss.mapperType = mapperType; for (int i=0; i < 4; i++) mss.paging_regs[i] = paging_regs[i]; // Save area types and bloc of the memory mapping for reading. for (int i=0; i < 8; i++) mss.rd_area_type[i] = rd_area_type[i]; for (int i=0; i < 8; i++) mss.block_in_rd_area[i] = block_in_rd_area[i]; // Save area types and bloc of the memory mapping for writing. for (int i=0; i < 8; i++) mss.wr_area_type[i] = wr_area_type[i]; for (int i=0; i < 8; i++) mss.block_in_wr_area[i] = block_in_wr_area[i]; // cout << "Saved Mapper Type =" << (unsigned int)mapperType << endl; // cout << "Saved paging_regs[0] =" << (unsigned int)paging_regs[0] << endl; // cout << "Saved paging_regs[1] =" << (unsigned int)paging_regs[1] << endl; // cout << "Saved paging_regs[2] =" << (unsigned int)paging_regs[2] << endl; // cout << "Saved paging_regs[3] =" << (unsigned int)paging_regs[3] << endl; /* Save 8Ko Ram from 0xC000-0xDFFF. */ ofs.write((char *)&ram[0], 0x2000); if (!ofs.good()) return false; /* Save 32Ko Battery Backed Memory. */ ofs.write((char *)&sram[0], 0x8000); if (!ofs.good()) return false; /* Save Paging Registers. */ ofs.write((char *)&mss, sizeof(mss)); if (!ofs.good()) return false; return true; } bool MemoryMapper::loadState( ifstream &ifs) { MemoryMapperSaveState mss; /* Load 8Ko Ram from 0xC000-0xDFFF. */ ifs.read((char *)&ram[0], 0x2000); if (!ifs.good()) return false; /* Load 32Ko Battery Backed Memory. */ ifs.read((char *)&sram[0], 0x8000); if (!ifs.good()) return false; /* Load Paging Registers. */ ifs.read((char *)&mss, sizeof(mss)); if (!ifs.good()) return false; mapperType = mss.mapperType; for (int i=0; i < 4; i++) paging_regs[i] = mss.paging_regs[i]; // Load area types and bloc of the memory mapping for reading. for (int i=0; i < 8; i++) rd_area_type[i] = mss.rd_area_type[i]; for (int i=0; i < 8; i++) block_in_rd_area[i] = mss.block_in_rd_area[i]; // Load area types and bloc of the memory mapping for writing. for (int i=0; i < 8; i++) wr_area_type[i] = mss.wr_area_type[i]; for (int i=0; i < 8; i++) block_in_wr_area[i] = mss.block_in_wr_area[i]; // Now rebuild read_maps pointers. for (int i=0; i < 8; i++) { unsigned char *base_ptr = NULL; switch (rd_area_type[i]) { case Cartridge: base_ptr = cartridge; break; case Ram: base_ptr = ram; break; case SRam: base_ptr = sram; break; case Null: // Everything is readable ! { string msg ="Warning : Wrong area_type for read_map !"; QLogWindow::getInstance()->appendLog(msg); } break; default: { string message ="Warning : Unknown area_type for read_map !"; QLogWindow::getInstance()->appendLog(message); } break; } read_map[i] = base_ptr + (block_in_rd_area[i] * 0x2000); } // Now rebuild write_maps pointers. for (int i=0; i < 8; i++) { unsigned char *base_ptr = NULL; switch (wr_area_type[i]) { case Cartridge: // Cartridge are read only ! { string msg ="Warning : Wrong area_type for write_map !"; QLogWindow::getInstance()->appendLog(msg); } break; case Ram: base_ptr = ram; break; case SRam: base_ptr = sram; break; case Null: base_ptr = null_rom; break; default: { string msg ="Warning : Unknown area_type for write_map !"; QLogWindow::getInstance()->appendLog(msg); } break; } write_map[i] = base_ptr + (block_in_wr_area[i] * 0x2000); } // cout << "Loaded Mapper Type =" << (unsigned int)mapperType << endl; // cout << "Loaded paging_regs[0] =" << (unsigned int)paging_regs[0] << endl; // cout << "Loaded paging_regs[1] =" << (unsigned int)paging_regs[1] << endl; // cout << "Loaded paging_regs[2] =" << (unsigned int)paging_regs[2] << endl; // cout << "Loaded paging_regs[3] =" << (unsigned int)paging_regs[3] << endl; return true; } osmose-emulator-1.4/src/MemoryMapper.h000066400000000000000000000124121341430144300200630ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef MEMORY_MAPPER_H #define MEMORY_MAPPER_H #include #include #include #include #include "Options.h" #include "Definitions.h" #include "DebugEventThrower.h" #include "SaveState.h" #include "OsmoseConfigurationFile.h" #include "QLogWindow.h" extern Options opt; using namespace std; enum Mapper { SegaMapper =0, CodemasterMapper, KoreanMapper }; /* Enumeration of addressing space areas types that could be read/written. */ enum Area_type { Cartridge, Ram, SRam, Null // Rom write attemps are redirected to null. }; /*---------------------------------------------------------------------------*/ /* Structure to save Memory mapper state. */ /* It's necessary to save paging registers, but it's Also required to save */ /* the bank mapping, instead of doing fake wr8 on address 0xFFFC-0xFFFF to */ /* get the correct mapping (order dependent for FFFC). As RAM pointer are */ /* not identical from different process, we save the area type of memory */ /* plus the bloc (8Ko) number inside the area. */ /* e.g: read_map[0] pointing to cartridge 0x2000 will be saved as : */ /* rd_area_type = Cartridge, block_in_rd_area = 1 */ /*---------------------------------------------------------------------------*/ typedef struct { unsigned char paging_regs[4]; // Paging registers. Area_type rd_area_type[8]; unsigned int block_in_rd_area[8]; Area_type wr_area_type[8]; unsigned int block_in_wr_area[8]; Mapper mapperType; } MemoryMapperSaveState; class MemoryMapper : public DebugEventThrower, public ImplementsSaveState { public: MemoryMapper(const char *rom_file, OsmoseConfigurationFile *c); void save_battery_backed_memory(string f); void reset(); void dump(unsigned char bnk_nbr); void dump_page(unsigned char page); void dump_mem(unsigned add, unsigned short nb_line); void dump_smem(unsigned add, unsigned short nb_line); void wr8(unsigned address, unsigned char value); unsigned char rd8(unsigned address); unsigned char getRSR(); unsigned char getFFFD(); unsigned char getFFFE(); unsigned char getFFFF(); string getROMName(); void setMapperType (Mapper map); /* Implemetntation of ImplementsSaveState. */ bool saveState( ofstream &ofs); bool loadState( ifstream &ifs); private: bool have_bbr; // Battery backed ram flag presence string rom_name; // Rom name without extension. unsigned rom_size; // ROM size in bytes unsigned bank_nbr; // How much 8k block in our rom unsigned bank16Ko_nbr; // How much 16k bank in our rom unsigned char *null_rom; // Ptr on Garbage (use for ROM writes). unsigned char *sram; // Ptr on Optionnal SRAM unsigned char *ram; // Central RAM unsigned char *cartridge; // Ptr on ROM cartridge. unsigned char paging_regs[4]; // Paging registers. unsigned char *write_map[8]; // 8ko bank ptr for CPU writes. Area_type wr_area_type[8]; // actual wr_map area type. unsigned int block_in_wr_area[8]; // 8ko block inside the area. unsigned char *read_map[8]; // 8ko bank ptr for CPU reads. Area_type rd_area_type[8]; // actual read_map area type. unsigned int block_in_rd_area[8]; // 8ko block inside the area. bool save_bbr; // Flag for Battery Backed Memory. Mapper mapperType; unsigned int LoadZippedRom(const char *rom_file); unsigned int LoadSMSRom(const char *rom_file); void DumpMappingPtr(); void wr8_sega_mapper(unsigned int add, unsigned char data); void wr8_codemaster_mapper(unsigned int add, unsigned char data); void wr8_korean_mapper(unsigned int add, unsigned char data); void write_standard_paging_reg(int reg, unsigned char value); void write_codemaster_paging_reg(unsigned char value); void DisplayROMSize(); unsigned int getCRC32(unsigned char *buffer, unsigned int len); void (MemoryMapper::*wr8_method)(unsigned int add, unsigned char data); OsmoseConfigurationFile *configuration; }; #endif osmose-emulator-1.4/src/Opc_cbxx.cpp000066400000000000000000000677751341430144300175740ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "Z80.h" /* Opcodes prefixed with 0xCB */ void Z80::exec_cb() { u8 instruction; R++; // Prefixed instruction increments R by one. instruction = env.rd8( PC++ ); (this->*(Opc_cbxx[instruction]))(); #ifdef OPCODES_STATS CB_Prefix[ instruction ]++; #endif } /* RLC B */ void Z80::Opc_cbxx_00() { B = rlc8( B ); cycleCount += 8; } /* RLC C */ void Z80::Opc_cbxx_01() { C = rlc8( C ); cycleCount += 8; } /* RLC D */ void Z80::Opc_cbxx_02() { D = rlc8( D ); cycleCount += 8; } /* RLC E */ void Z80::Opc_cbxx_03() { E = rlc8( E ); cycleCount += 8; } /* RLC H */ void Z80::Opc_cbxx_04() { H = rlc8( H ); cycleCount += 8; } /* RLC L */ void Z80::Opc_cbxx_05() { L = rlc8( L ); cycleCount += 8; } /* RLC (HL) */ void Z80::Opc_cbxx_06() { env.wr8( getHL(), rlc8( getHLi())); cycleCount += 15; } /* RLC A */ void Z80::Opc_cbxx_07() { A = rlc8( A ); cycleCount += 8; } /* RRC B */ void Z80::Opc_cbxx_08() { B = rrc8( B ); cycleCount += 8; } /* RRC C */ void Z80::Opc_cbxx_09() { C = rrc8( C ); cycleCount += 8; } /* RRC D */ void Z80::Opc_cbxx_0a() { D = rrc8( D ); cycleCount += 8; } /* RRC E */ void Z80::Opc_cbxx_0b() { E = rrc8( E ); cycleCount += 8; } /* RRC H */ void Z80::Opc_cbxx_0c() { H = rrc8( H ); cycleCount += 8; } /* RRC L */ void Z80::Opc_cbxx_0d() { L = rrc8( L ); cycleCount += 8; } /* RRC (HL) */ void Z80::Opc_cbxx_0e() { env.wr8( getHL(), rrc8( getHLi())); cycleCount += 15; } /* RRC A */ void Z80::Opc_cbxx_0f() { A = rrc8( A ); cycleCount += 8; } /* RL B */ void Z80::Opc_cbxx_10() { B = rl8( B ); cycleCount += 8; } /* RL C */ void Z80::Opc_cbxx_11() { C = rl8( C ); cycleCount += 8; } /* RL D */ void Z80::Opc_cbxx_12() { D = rl8( D ); cycleCount += 8; } /* RL E */ void Z80::Opc_cbxx_13() { E = rl8( E ); cycleCount += 8; } /* RL H */ void Z80::Opc_cbxx_14() { H = rl8( H ); cycleCount += 8; } /* RL L */ void Z80::Opc_cbxx_15() { L = rl8( L ); cycleCount += 8; } /* RL (HL) */ void Z80::Opc_cbxx_16() { env.wr8( getHL(), rl8( getHLi())); cycleCount += 15; } /* RL A */ void Z80::Opc_cbxx_17() { A = rl8( A ); cycleCount += 8; } /* RR B */ void Z80::Opc_cbxx_18() { B = rr8( B ); cycleCount += 8; } /* RR C */ void Z80::Opc_cbxx_19() { C = rr8( C ); cycleCount += 8; } /* RR D */ void Z80::Opc_cbxx_1a() { D = rr8( D ); cycleCount += 8; } /* RR E */ void Z80::Opc_cbxx_1b() { E = rr8( E ); cycleCount += 8; } /* RR H */ void Z80::Opc_cbxx_1c() { H = rr8( H ); cycleCount += 8; } /* RR L */ void Z80::Opc_cbxx_1d() { L = rr8( L ); cycleCount += 8; } /* RR (HL) */ void Z80::Opc_cbxx_1e() { env.wr8( getHL(), rr8( getHLi())); cycleCount += 15; } /* RR A */ void Z80::Opc_cbxx_1f() { A = rr8( A ); cycleCount += 8; } /* SLA B */ void Z80::Opc_cbxx_20() { B = sla8( B ); cycleCount += 8; } /* SLA C */ void Z80::Opc_cbxx_21() { C = sla8( C ); cycleCount += 8; } /* SLA D */ void Z80::Opc_cbxx_22() { D = sla8( D ); cycleCount += 8; } /* SLA E */ void Z80::Opc_cbxx_23() { E = sla8( E ); cycleCount += 8; } /* SLA H */ void Z80::Opc_cbxx_24() { H = sla8( H ); cycleCount += 8; } /* SLA L */ void Z80::Opc_cbxx_25() { L = sla8( L ); cycleCount += 8; } /* SLA (HL) */ void Z80::Opc_cbxx_26() { env.wr8( getHL(), sla8( getHLi())); cycleCount += 15; } /* SLA A */ void Z80::Opc_cbxx_27() { A = sla8( A ); cycleCount += 8; } /* SRA B */ void Z80::Opc_cbxx_28() { B = sra8( B ); cycleCount += 8; } /* SRA C */ void Z80::Opc_cbxx_29() { C = sra8( C ); cycleCount += 8; } /* SRA D */ void Z80::Opc_cbxx_2a() { D = sra8( D ); cycleCount += 8; } /* SRA E */ void Z80::Opc_cbxx_2b() { E = sra8( E ); cycleCount += 8; } /* SRA H */ void Z80::Opc_cbxx_2c() { H = sra8( H ); cycleCount += 8; } /* SRA L */ void Z80::Opc_cbxx_2d() { L = sra8( L ); cycleCount += 8; } /* SRA (HL) */ void Z80::Opc_cbxx_2e() { env.wr8( getHL(), sra8( getHLi())); cycleCount += 15; } /* SRA A */ void Z80::Opc_cbxx_2f() { A = sra8( A ); cycleCount += 8; } /* SLL B */ void Z80::Opc_cbxx_30() { B = sll8( B ); cycleCount += 8; } /* SLL C */ void Z80::Opc_cbxx_31() { C = sll8( C ); cycleCount += 8; } /* SLL D */ void Z80::Opc_cbxx_32() { D = sll8( D ); cycleCount += 8; } /* SLL E */ void Z80::Opc_cbxx_33() { E = sll8( E ); cycleCount += 8; } /* SLL H */ void Z80::Opc_cbxx_34() { H = sll8( H ); cycleCount += 8; } /* SLL L */ void Z80::Opc_cbxx_35() { L = sll8( L ); cycleCount += 8; } /* SLL (HL) */ void Z80::Opc_cbxx_36() { env.wr8( getHL(), sll8( getHLi())); cycleCount += 15; } /* SLL A */ void Z80::Opc_cbxx_37() { A = sll8( A ); cycleCount += 8; } /* SRL B */ void Z80::Opc_cbxx_38() { B = srl8( B ); cycleCount += 8; } /* SRL C */ void Z80::Opc_cbxx_39() { C = srl8( C ); cycleCount += 8; } /* SRL D */ void Z80::Opc_cbxx_3a() { D = srl8( D ); cycleCount += 8; } /* SRL E */ void Z80::Opc_cbxx_3b() { E = srl8( E ); cycleCount += 8; } /* SRL H */ void Z80::Opc_cbxx_3c() { H = srl8( H ); cycleCount += 8; } /* SRL L */ void Z80::Opc_cbxx_3d() { L = srl8( L ); cycleCount += 8; } /* SRL (HL) */ void Z80::Opc_cbxx_3e() { env.wr8( getHL(), srl8( getHLi())); cycleCount += 15; } /* SRL A */ void Z80::Opc_cbxx_3f() { A = srl8( A ); cycleCount += 8; } /* BIT 0, B */ void Z80::Opc_cbxx_40() { bit(0, B); cycleCount += 8; } /* BIT 0, C */ void Z80::Opc_cbxx_41() { bit(0, C); cycleCount += 8; } /* BIT 0, D */ void Z80::Opc_cbxx_42() { bit(0, D); cycleCount += 8; } /* BIT 0, E */ void Z80::Opc_cbxx_43() { bit(0, E); cycleCount += 8; } /* BIT 0, H */ void Z80::Opc_cbxx_44() { bit(0, H); cycleCount += 8; } /* BIT 0, L */ void Z80::Opc_cbxx_45() { bit(0, L); cycleCount += 8; } /* BIT 0, (HL) */ void Z80::Opc_cbxx_46() { bit(0, getHLi()); cycleCount += 12; } /* BIT 0, A */ void Z80::Opc_cbxx_47() { bit(0, A); cycleCount += 8; } /* BIT 1, B */ void Z80::Opc_cbxx_48() { bit(1, B); cycleCount += 8; } /* BIT 1, C */ void Z80::Opc_cbxx_49() { bit(1, C); cycleCount += 8; } /* BIT 1, D */ void Z80::Opc_cbxx_4a() { bit(1, D); cycleCount += 8; } /* BIT 1, E */ void Z80::Opc_cbxx_4b() { bit(1, E); cycleCount += 8; } /* BIT 1, H */ void Z80::Opc_cbxx_4c() { bit(1, H); cycleCount += 8; } /* BIT 1, L */ void Z80::Opc_cbxx_4d() { bit(1, L); cycleCount += 8; } /* BIT 1, (HL) */ void Z80::Opc_cbxx_4e() { bit(1, getHLi()); cycleCount += 12; } /* BIT 1, A */ void Z80::Opc_cbxx_4f() { bit(1, A); cycleCount += 8; } /* BIT 2, B */ void Z80::Opc_cbxx_50() { bit(2, B); cycleCount += 8; } /* BIT 2, C */ void Z80::Opc_cbxx_51() { bit(2, C); cycleCount += 8; } /* BIT 2, D */ void Z80::Opc_cbxx_52() { bit(2, D); cycleCount += 8; } /* BIT 2, E */ void Z80::Opc_cbxx_53() { bit(2, E); cycleCount += 8; } /* BIT 2, H */ void Z80::Opc_cbxx_54() { bit(2, H); cycleCount += 8; } /* BIT 2, L */ void Z80::Opc_cbxx_55() { bit(2, L); cycleCount += 8; } /* BIT 2, (HL) */ void Z80::Opc_cbxx_56() { bit(2, getHLi()); cycleCount += 12; } /* BIT 2, A */ void Z80::Opc_cbxx_57() { bit(2, A); cycleCount += 8; } /* BIT 3, B */ void Z80::Opc_cbxx_58() { bit(3, B); cycleCount += 8; } /* BIT 3, C */ void Z80::Opc_cbxx_59() { bit(3, C); cycleCount += 8; } /* BIT 3, D */ void Z80::Opc_cbxx_5a() { bit(3, D); cycleCount += 8; } /* BIT 3, E */ void Z80::Opc_cbxx_5b() { bit(3, E); cycleCount += 8; } /* BIT 3, H */ void Z80::Opc_cbxx_5c() { bit(3, H); cycleCount += 8; } /* BIT 3, L */ void Z80::Opc_cbxx_5d() { bit(3, L); cycleCount += 8; } /* BIT 3, (HL) */ void Z80::Opc_cbxx_5e() { bit(3, getHLi()); cycleCount += 12; } /* BIT 3, A */ void Z80::Opc_cbxx_5f() { bit(3, A); cycleCount += 8; } /* BIT 4, B */ void Z80::Opc_cbxx_60() { bit(4, B); cycleCount += 8; } /* BIT 4, C */ void Z80::Opc_cbxx_61() { bit(4, C); cycleCount += 8; } /* BIT 4, D */ void Z80::Opc_cbxx_62() { bit(4, D); cycleCount += 8; } /* BIT 4, E */ void Z80::Opc_cbxx_63() { bit(4, E); cycleCount += 8; } /* BIT 4, H */ void Z80::Opc_cbxx_64() { bit(4, H); cycleCount += 8; } /* BIT 4, L */ void Z80::Opc_cbxx_65() { bit(4, L); cycleCount += 8; } /* BIT 4, (HL) */ void Z80::Opc_cbxx_66() { bit(4, getHLi()); cycleCount += 12; } /* BIT 4, A */ void Z80::Opc_cbxx_67() { bit(4, A); cycleCount += 8; } /* BIT 5, B */ void Z80::Opc_cbxx_68() { bit(5, B); cycleCount += 8; } /* BIT 5, C */ void Z80::Opc_cbxx_69() { bit(5, C); cycleCount += 8; } /* BIT 5, D */ void Z80::Opc_cbxx_6a() { bit(5, D); cycleCount += 8; } /* BIT 5, E */ void Z80::Opc_cbxx_6b() { bit(5, E); cycleCount += 8; } /* BIT 5, H */ void Z80::Opc_cbxx_6c() { bit(5, H); cycleCount += 8; } /* BIT 5, L */ void Z80::Opc_cbxx_6d() { bit(5, L); cycleCount += 8; } /* BIT 5, (HL) */ void Z80::Opc_cbxx_6e() { bit(5, getHLi()); cycleCount += 12; } /* BIT 5, A */ void Z80::Opc_cbxx_6f() { bit(5, A); cycleCount += 8; } /* BIT 6, B */ void Z80::Opc_cbxx_70() { bit(6, B); cycleCount += 8; } /* BIT 6, C */ void Z80::Opc_cbxx_71() { bit(6, C); cycleCount += 8; } /* BIT 6, D */ void Z80::Opc_cbxx_72() { bit(6, D); cycleCount += 8; } /* BIT 6, E */ void Z80::Opc_cbxx_73() { bit(6, E); cycleCount += 8; } /* BIT 6, H */ void Z80::Opc_cbxx_74() { bit(6, H); cycleCount += 8; } /* BIT 6, L */ void Z80::Opc_cbxx_75() { bit(6, L); cycleCount += 8; } /* BIT 6, (HL) */ void Z80::Opc_cbxx_76() { bit(6, getHLi()); cycleCount += 12; } /* BIT 6, A */ void Z80::Opc_cbxx_77() { bit(6, A); cycleCount += 8; } /* BIT 7, B */ void Z80::Opc_cbxx_78() { bit(7, B); cycleCount += 8; } /* BIT 7, C */ void Z80::Opc_cbxx_79() { bit(7, C); cycleCount += 8; } /* BIT 7, D */ void Z80::Opc_cbxx_7a() { bit(7, D); cycleCount += 8; } /* BIT 7, E */ void Z80::Opc_cbxx_7b() { bit(7, E); cycleCount += 8; } /* BIT 7, H */ void Z80::Opc_cbxx_7c() { bit(7, H); cycleCount += 8; } /* BIT 7, L */ void Z80::Opc_cbxx_7d() { bit(7, L); cycleCount += 8; } /* BIT 7, (HL) */ void Z80::Opc_cbxx_7e() { bit(7, getHLi()); cycleCount += 12; } /* BIT 7, A */ void Z80::Opc_cbxx_7f() { bit(7, A); cycleCount += 8; } /* RES 0, B */ void Z80::Opc_cbxx_80() { B = res(0, B); cycleCount += 8; } /* RES 0, C */ void Z80::Opc_cbxx_81() { C = res(0, C); cycleCount += 8; } /* RES 0, D */ void Z80::Opc_cbxx_82() { D = res(0, D); cycleCount += 8; } /* RES 0, E */ void Z80::Opc_cbxx_83() { E = res(0, E); cycleCount += 8; } /* RES 0, H */ void Z80::Opc_cbxx_84() { H = res(0, H); cycleCount += 8; } /* RES 0, L */ void Z80::Opc_cbxx_85() { L = res(0, L); cycleCount += 8; } /* RES 0, (HL) */ void Z80::Opc_cbxx_86() { setHLi(res(0, getHLi())); cycleCount += 15; } /* RES 0, A */ void Z80::Opc_cbxx_87() { A = res(0, A); cycleCount += 8; } /* RES 1, B */ void Z80::Opc_cbxx_88() { B = res(1, B); cycleCount += 8; } /* RES 1, C */ void Z80::Opc_cbxx_89() { C = res(1, C); cycleCount += 8; } /* RES 1, D */ void Z80::Opc_cbxx_8a() { D = res(1, D); cycleCount += 8; } /* RES 1, E */ void Z80::Opc_cbxx_8b() { E = res(1, E); cycleCount += 8; } /* RES 1, H */ void Z80::Opc_cbxx_8c() { H = res(1, H); cycleCount += 8; } /* RES 1, L */ void Z80::Opc_cbxx_8d() { L = res(1, L); cycleCount += 8; } /* RES 1, (HL) */ void Z80::Opc_cbxx_8e() { setHLi(res(1, getHLi())); cycleCount += 15; } /* RES 1, A */ void Z80::Opc_cbxx_8f() { A = res(1, A); cycleCount += 8; } /* RES 2, B */ void Z80::Opc_cbxx_90() { B = res(2, B); cycleCount += 8; } /* RES 2, C */ void Z80::Opc_cbxx_91() { C = res(2, C); cycleCount += 8; } /* RES 2, D */ void Z80::Opc_cbxx_92() { D = res(2, D); cycleCount += 8; } /* RES 2, E */ void Z80::Opc_cbxx_93() { E = res(2, E); cycleCount += 8; } /* RES 2, H */ void Z80::Opc_cbxx_94() { H = res(2, H); cycleCount += 8; } /* RES 2, L */ void Z80::Opc_cbxx_95() { L = res(2, L); cycleCount += 8; } /* RES 2, (HL) */ void Z80::Opc_cbxx_96() { setHLi(res(2, getHLi())); cycleCount += 15; } /* RES 2, A */ void Z80::Opc_cbxx_97() { A = res(2, A); cycleCount += 8; } /* RES 3, B */ void Z80::Opc_cbxx_98() { B = res(3, B); cycleCount += 8; } /* RES 3, C */ void Z80::Opc_cbxx_99() { C = res(3, C); cycleCount += 8; } /* RES 3, D */ void Z80::Opc_cbxx_9a() { D = res(3, D); cycleCount += 8; } /* RES 3, E */ void Z80::Opc_cbxx_9b() { E = res(3, E); cycleCount += 8; } /* RES 3, H */ void Z80::Opc_cbxx_9c() { H = res(3, H); cycleCount += 8; } /* RES 3, L */ void Z80::Opc_cbxx_9d() { L = res(3, L); cycleCount += 8; } /* RES 3, (HL) */ void Z80::Opc_cbxx_9e() { setHLi(res(3, getHLi())); cycleCount += 15; } /* RES 3, A */ void Z80::Opc_cbxx_9f() { A = res(3, A); cycleCount += 8; } /* RES 4, B */ void Z80::Opc_cbxx_a0() { B = res(4, B); cycleCount += 8; } /* RES 4, C */ void Z80::Opc_cbxx_a1() { C = res(4, C); cycleCount += 8; } /* RES 4, D */ void Z80::Opc_cbxx_a2() { D = res(4, D); cycleCount += 8; } /* RES 4, E */ void Z80::Opc_cbxx_a3() { E = res(4, E); cycleCount += 8; } /* RES 4, H */ void Z80::Opc_cbxx_a4() { H = res(4, H); cycleCount += 8; } /* RES 4, L */ void Z80::Opc_cbxx_a5() { L = res(4, L); cycleCount += 8; } /* RES 4, (HL) */ void Z80::Opc_cbxx_a6() { setHLi(res(4, getHLi())); cycleCount += 15; } /* RES 4, A */ void Z80::Opc_cbxx_a7() { A = res(4, A); cycleCount += 8; } /* RES 5, B */ void Z80::Opc_cbxx_a8() { B = res(5, B); cycleCount += 8; } /* RES 5, C */ void Z80::Opc_cbxx_a9() { C = res(5, C); cycleCount += 8; } /* RES 5, D */ void Z80::Opc_cbxx_aa() { D = res(5, D); cycleCount += 8; } /* RES 5, E */ void Z80::Opc_cbxx_ab() { E = res(5, E); cycleCount += 8; } /* RES 5, H */ void Z80::Opc_cbxx_ac() { H = res(5, H); cycleCount += 8; } /* RES 5, L */ void Z80::Opc_cbxx_ad() { L = res(5, L); cycleCount += 8; } /* RES 5, (HL) */ void Z80::Opc_cbxx_ae() { setHLi(res(5, getHLi())); cycleCount += 15; } /* RES 5, A */ void Z80::Opc_cbxx_af() { A = res(5, A); cycleCount += 8; } /* RES 6, B */ void Z80::Opc_cbxx_b0() { B = res(6, B); cycleCount += 8; } /* RES 6, C */ void Z80::Opc_cbxx_b1() { C = res(6, C); cycleCount += 8; } /* RES 6, D */ void Z80::Opc_cbxx_b2() { D = res(6, D); cycleCount += 8; } /* RES 6, E */ void Z80::Opc_cbxx_b3() { E = res(6, E); cycleCount += 8; } /* RES 6, H */ void Z80::Opc_cbxx_b4() { H = res(6, H); cycleCount += 8; } /* RES 6, L */ void Z80::Opc_cbxx_b5() { L = res(6, L); cycleCount += 8; } /* RES 6, (HL) */ void Z80::Opc_cbxx_b6() { setHLi(res(6, getHLi())); cycleCount += 15; } /* RES 6, A */ void Z80::Opc_cbxx_b7() { A = res(6, A); cycleCount += 8; } /* RES 7, B */ void Z80::Opc_cbxx_b8() { B = res(7, B); cycleCount += 8; } /* RES 7, C */ void Z80::Opc_cbxx_b9() { C = res(7, C); cycleCount += 8; } /* RES 7, D */ void Z80::Opc_cbxx_ba() { D = res(7, D); cycleCount += 8; } /* RES 7, E */ void Z80::Opc_cbxx_bb() { E = res(7, E); cycleCount += 8; } /* RES 7, H */ void Z80::Opc_cbxx_bc() { H = res(7, H); cycleCount += 8; } /* RES 7, L */ void Z80::Opc_cbxx_bd() { L = res(7, L); cycleCount += 8; } /* RES 7, (HL) */ void Z80::Opc_cbxx_be() { setHLi(res(7, getHLi())); cycleCount += 15; } /* RES 7, A */ void Z80::Opc_cbxx_bf() { A = res(7, A); cycleCount += 8; } /* SET 0, B */ void Z80::Opc_cbxx_c0() { B = set(0, B); cycleCount += 8; } /* SET 0, C */ void Z80::Opc_cbxx_c1() { C = set(0, C); cycleCount += 8; } /* SET 0, D */ void Z80::Opc_cbxx_c2() { D = set(0, D); cycleCount += 8; } /* SET 0, E */ void Z80::Opc_cbxx_c3() { E = set(0, E); cycleCount += 8; } /* SET 0, H */ void Z80::Opc_cbxx_c4() { H = set(0, H); cycleCount += 8; } /* SET 0, L */ void Z80::Opc_cbxx_c5() { L = set(0, L); cycleCount += 8; } /* SET 0, (HL) */ void Z80::Opc_cbxx_c6() { setHLi(set(0, getHLi())); cycleCount += 15; } /* SET 0, A */ void Z80::Opc_cbxx_c7() { A = set(0, A); cycleCount += 8; } /* SET 1, B */ void Z80::Opc_cbxx_c8() { B = set(1, B); cycleCount += 8; } /* SET 1, C */ void Z80::Opc_cbxx_c9() { C = set(1, C); cycleCount += 8; } /* SET 1, D */ void Z80::Opc_cbxx_ca() { D = set(1, D); cycleCount += 8; } /* SET 1, E */ void Z80::Opc_cbxx_cb() { E = set(1, E); cycleCount += 8; } /* SET 1, H */ void Z80::Opc_cbxx_cc() { H = set(1, H); cycleCount += 8; } /* SET 1, L */ void Z80::Opc_cbxx_cd() { L = set(1, L); cycleCount += 8; } /* SET 1, (HL) */ void Z80::Opc_cbxx_ce() { setHLi(set(1, getHLi())); cycleCount += 15; } /* SET 1, A */ void Z80::Opc_cbxx_cf() { A = set(1, A); cycleCount += 8; } /* SET 2, B */ void Z80::Opc_cbxx_d0() { B = set(2, B); cycleCount += 8; } /* SET 2, C */ void Z80::Opc_cbxx_d1() { C = set(2, C); cycleCount += 8; } /* SET 2, D */ void Z80::Opc_cbxx_d2() { D = set(2, D); cycleCount += 8; } /* SET 2, E */ void Z80::Opc_cbxx_d3() { E = set(2, E); cycleCount += 8; } /* SET 2, H */ void Z80::Opc_cbxx_d4() { H = set(2, H); cycleCount += 8; } /* SET 2, L */ void Z80::Opc_cbxx_d5() { L = set(2, L); cycleCount += 8; } /* SET 2, (HL) */ void Z80::Opc_cbxx_d6() { setHLi(set(2, getHLi())); cycleCount += 15; } /* SET 2, A */ void Z80::Opc_cbxx_d7() { A = set(2, A); cycleCount += 8; } /* SET 3, B */ void Z80::Opc_cbxx_d8() { B = set(3, B); cycleCount += 8; } /* SET 3, C */ void Z80::Opc_cbxx_d9() { C = set(3, C); cycleCount += 8; } /* SET 3, D */ void Z80::Opc_cbxx_da() { D = set(3, D); cycleCount += 8; } /* SET 3, E */ void Z80::Opc_cbxx_db() { E = set(3, E); cycleCount += 8; } /* SET 3, H */ void Z80::Opc_cbxx_dc() { H = set(3, H); cycleCount += 8; } /* SET 3, L */ void Z80::Opc_cbxx_dd() { L = set(3, L); cycleCount += 8; } /* SET 3, (HL) */ void Z80::Opc_cbxx_de() { setHLi(set(3, getHLi())); cycleCount += 15; } /* SET 3, A */ void Z80::Opc_cbxx_df() { A = set(3, A); cycleCount += 8; } /* SET 4, B */ void Z80::Opc_cbxx_e0() { B = set(4, B); cycleCount += 8; } /* SET 4, C */ void Z80::Opc_cbxx_e1() { C = set(4, C); cycleCount += 8; } /* SET 4, D */ void Z80::Opc_cbxx_e2() { D = set(4, D); cycleCount += 8; } /* SET 4, E */ void Z80::Opc_cbxx_e3() { E = set(4, E); cycleCount += 8; } /* SET 4, H */ void Z80::Opc_cbxx_e4() { H = set(4, H); cycleCount += 8; } /* SET 4, L */ void Z80::Opc_cbxx_e5() { L = set(4, L); cycleCount += 8; } /* SET 4, (HL) */ void Z80::Opc_cbxx_e6() { setHLi(set(4, getHLi())); cycleCount += 15; } /* SET 4, A */ void Z80::Opc_cbxx_e7() { A = set(4, A); cycleCount += 8; } /* SET 5, B */ void Z80::Opc_cbxx_e8() { B = set(5, B); cycleCount += 8; } /* SET 5, C */ void Z80::Opc_cbxx_e9() { C = set(5, C); cycleCount += 8; } /* SET 5, D */ void Z80::Opc_cbxx_ea() { D = set(5, D); cycleCount += 8; } /* SET 5, E */ void Z80::Opc_cbxx_eb() { E = set(5, E); cycleCount += 8; } /* SET 5, H */ void Z80::Opc_cbxx_ec() { H = set(5, H); cycleCount += 8; } /* SET 5, L */ void Z80::Opc_cbxx_ed() { L = set(5, L); cycleCount += 8; } /* SET 5, (HL) */ void Z80::Opc_cbxx_ee() { setHLi(set(5, getHLi())); cycleCount += 15; } /* SET 5, A */ void Z80::Opc_cbxx_ef() { A = set(5, A); cycleCount += 8; } /* SET 6, B */ void Z80::Opc_cbxx_f0() { B = set(6, B); cycleCount += 8; } /* SET 6, C */ void Z80::Opc_cbxx_f1() { C = set(6, C); cycleCount += 8; } /* SET 6, D */ void Z80::Opc_cbxx_f2() { D = set(6, D); cycleCount += 8; } /* SET 6, E */ void Z80::Opc_cbxx_f3() { E = set(6, E); cycleCount += 8; } /* SET 6, H */ void Z80::Opc_cbxx_f4() { H = set(6, H); cycleCount += 8; } /* SET 6, L */ void Z80::Opc_cbxx_f5() { L = set(6, L); cycleCount += 8; } /* SET 6, (HL) */ void Z80::Opc_cbxx_f6() { setHLi(set(6, getHLi())); cycleCount += 15; } /* SET 6, A */ void Z80::Opc_cbxx_f7() { A = set(6, A); cycleCount += 8; } /* SET 7, B */ void Z80::Opc_cbxx_f8() { B = set(7, B); cycleCount += 8; } /* SET 7, C */ void Z80::Opc_cbxx_f9() { C = set(7, C); cycleCount += 8; } /* SET 7, D */ void Z80::Opc_cbxx_fa() { D = set(7, D); cycleCount += 8; } /* SET 7, E */ void Z80::Opc_cbxx_fb() { E = set(7, E); cycleCount += 8; } /* SET 7, H */ void Z80::Opc_cbxx_fc() { H = set(7, H); cycleCount += 8; } /* SET 7, L */ void Z80::Opc_cbxx_fd() { L = set(7, L); cycleCount += 8; } /* SET 7, (HL) */ void Z80::Opc_cbxx_fe() { setHLi(set(7, getHLi())); cycleCount += 15; } /* SET 7, A */ void Z80::Opc_cbxx_ff() { A = set(7, A); cycleCount += 8; } Z80::Opc_handler Z80::Opc_cbxx[256] = { &Z80::Opc_cbxx_00, &Z80::Opc_cbxx_01, &Z80::Opc_cbxx_02, &Z80::Opc_cbxx_03, &Z80::Opc_cbxx_04, &Z80::Opc_cbxx_05, &Z80::Opc_cbxx_06, &Z80::Opc_cbxx_07, &Z80::Opc_cbxx_08, &Z80::Opc_cbxx_09, &Z80::Opc_cbxx_0a, &Z80::Opc_cbxx_0b, &Z80::Opc_cbxx_0c, &Z80::Opc_cbxx_0d, &Z80::Opc_cbxx_0e, &Z80::Opc_cbxx_0f, &Z80::Opc_cbxx_10, &Z80::Opc_cbxx_11, &Z80::Opc_cbxx_12, &Z80::Opc_cbxx_13, &Z80::Opc_cbxx_14, &Z80::Opc_cbxx_15, &Z80::Opc_cbxx_16, &Z80::Opc_cbxx_17, &Z80::Opc_cbxx_18, &Z80::Opc_cbxx_19, &Z80::Opc_cbxx_1a, &Z80::Opc_cbxx_1b, &Z80::Opc_cbxx_1c, &Z80::Opc_cbxx_1d, &Z80::Opc_cbxx_1e, &Z80::Opc_cbxx_1f, &Z80::Opc_cbxx_20, &Z80::Opc_cbxx_21, &Z80::Opc_cbxx_22, &Z80::Opc_cbxx_23, &Z80::Opc_cbxx_24, &Z80::Opc_cbxx_25, &Z80::Opc_cbxx_26, &Z80::Opc_cbxx_27, &Z80::Opc_cbxx_28, &Z80::Opc_cbxx_29, &Z80::Opc_cbxx_2a, &Z80::Opc_cbxx_2b, &Z80::Opc_cbxx_2c, &Z80::Opc_cbxx_2d, &Z80::Opc_cbxx_2e, &Z80::Opc_cbxx_2f, &Z80::Opc_cbxx_30, &Z80::Opc_cbxx_31, &Z80::Opc_cbxx_32, &Z80::Opc_cbxx_33, &Z80::Opc_cbxx_34, &Z80::Opc_cbxx_35, &Z80::Opc_cbxx_36, &Z80::Opc_cbxx_37, &Z80::Opc_cbxx_38, &Z80::Opc_cbxx_39, &Z80::Opc_cbxx_3a, &Z80::Opc_cbxx_3b, &Z80::Opc_cbxx_3c, &Z80::Opc_cbxx_3d, &Z80::Opc_cbxx_3e, &Z80::Opc_cbxx_3f, &Z80::Opc_cbxx_40, &Z80::Opc_cbxx_41, &Z80::Opc_cbxx_42, &Z80::Opc_cbxx_43, &Z80::Opc_cbxx_44, &Z80::Opc_cbxx_45, &Z80::Opc_cbxx_46, &Z80::Opc_cbxx_47, &Z80::Opc_cbxx_48, &Z80::Opc_cbxx_49, &Z80::Opc_cbxx_4a, &Z80::Opc_cbxx_4b, &Z80::Opc_cbxx_4c, &Z80::Opc_cbxx_4d, &Z80::Opc_cbxx_4e, &Z80::Opc_cbxx_4f, &Z80::Opc_cbxx_50, &Z80::Opc_cbxx_51, &Z80::Opc_cbxx_52, &Z80::Opc_cbxx_53, &Z80::Opc_cbxx_54, &Z80::Opc_cbxx_55, &Z80::Opc_cbxx_56, &Z80::Opc_cbxx_57, &Z80::Opc_cbxx_58, &Z80::Opc_cbxx_59, &Z80::Opc_cbxx_5a, &Z80::Opc_cbxx_5b, &Z80::Opc_cbxx_5c, &Z80::Opc_cbxx_5d, &Z80::Opc_cbxx_5e, &Z80::Opc_cbxx_5f, &Z80::Opc_cbxx_60, &Z80::Opc_cbxx_61, &Z80::Opc_cbxx_62, &Z80::Opc_cbxx_63, &Z80::Opc_cbxx_64, &Z80::Opc_cbxx_65, &Z80::Opc_cbxx_66, &Z80::Opc_cbxx_67, &Z80::Opc_cbxx_68, &Z80::Opc_cbxx_69, &Z80::Opc_cbxx_6a, &Z80::Opc_cbxx_6b, &Z80::Opc_cbxx_6c, &Z80::Opc_cbxx_6d, &Z80::Opc_cbxx_6e, &Z80::Opc_cbxx_6f, &Z80::Opc_cbxx_70, &Z80::Opc_cbxx_71, &Z80::Opc_cbxx_72, &Z80::Opc_cbxx_73, &Z80::Opc_cbxx_74, &Z80::Opc_cbxx_75, &Z80::Opc_cbxx_76, &Z80::Opc_cbxx_77, &Z80::Opc_cbxx_78, &Z80::Opc_cbxx_79, &Z80::Opc_cbxx_7a, &Z80::Opc_cbxx_7b, &Z80::Opc_cbxx_7c, &Z80::Opc_cbxx_7d, &Z80::Opc_cbxx_7e, &Z80::Opc_cbxx_7f, &Z80::Opc_cbxx_80, &Z80::Opc_cbxx_81, &Z80::Opc_cbxx_82, &Z80::Opc_cbxx_83, &Z80::Opc_cbxx_84, &Z80::Opc_cbxx_85, &Z80::Opc_cbxx_86, &Z80::Opc_cbxx_87, &Z80::Opc_cbxx_88, &Z80::Opc_cbxx_89, &Z80::Opc_cbxx_8a, &Z80::Opc_cbxx_8b, &Z80::Opc_cbxx_8c, &Z80::Opc_cbxx_8d, &Z80::Opc_cbxx_8e, &Z80::Opc_cbxx_8f, &Z80::Opc_cbxx_90, &Z80::Opc_cbxx_91, &Z80::Opc_cbxx_92, &Z80::Opc_cbxx_93, &Z80::Opc_cbxx_94, &Z80::Opc_cbxx_95, &Z80::Opc_cbxx_96, &Z80::Opc_cbxx_97, &Z80::Opc_cbxx_98, &Z80::Opc_cbxx_99, &Z80::Opc_cbxx_9a, &Z80::Opc_cbxx_9b, &Z80::Opc_cbxx_9c, &Z80::Opc_cbxx_9d, &Z80::Opc_cbxx_9e, &Z80::Opc_cbxx_9f, &Z80::Opc_cbxx_a0, &Z80::Opc_cbxx_a1, &Z80::Opc_cbxx_a2, &Z80::Opc_cbxx_a3, &Z80::Opc_cbxx_a4, &Z80::Opc_cbxx_a5, &Z80::Opc_cbxx_a6, &Z80::Opc_cbxx_a7, &Z80::Opc_cbxx_a8, &Z80::Opc_cbxx_a9, &Z80::Opc_cbxx_aa, &Z80::Opc_cbxx_ab, &Z80::Opc_cbxx_ac, &Z80::Opc_cbxx_ad, &Z80::Opc_cbxx_ae, &Z80::Opc_cbxx_af, &Z80::Opc_cbxx_b0, &Z80::Opc_cbxx_b1, &Z80::Opc_cbxx_b2, &Z80::Opc_cbxx_b3, &Z80::Opc_cbxx_b4, &Z80::Opc_cbxx_b5, &Z80::Opc_cbxx_b6, &Z80::Opc_cbxx_b7, &Z80::Opc_cbxx_b8, &Z80::Opc_cbxx_b9, &Z80::Opc_cbxx_ba, &Z80::Opc_cbxx_bb, &Z80::Opc_cbxx_bc, &Z80::Opc_cbxx_bd, &Z80::Opc_cbxx_be, &Z80::Opc_cbxx_bf, &Z80::Opc_cbxx_c0, &Z80::Opc_cbxx_c1, &Z80::Opc_cbxx_c2, &Z80::Opc_cbxx_c3, &Z80::Opc_cbxx_c4, &Z80::Opc_cbxx_c5, &Z80::Opc_cbxx_c6, &Z80::Opc_cbxx_c7, &Z80::Opc_cbxx_c8, &Z80::Opc_cbxx_c9, &Z80::Opc_cbxx_ca, &Z80::Opc_cbxx_cb, &Z80::Opc_cbxx_cc, &Z80::Opc_cbxx_cd, &Z80::Opc_cbxx_ce, &Z80::Opc_cbxx_cf, &Z80::Opc_cbxx_d0, &Z80::Opc_cbxx_d1, &Z80::Opc_cbxx_d2, &Z80::Opc_cbxx_d3, &Z80::Opc_cbxx_d4, &Z80::Opc_cbxx_d5, &Z80::Opc_cbxx_d6, &Z80::Opc_cbxx_d7, &Z80::Opc_cbxx_d8, &Z80::Opc_cbxx_d9, &Z80::Opc_cbxx_da, &Z80::Opc_cbxx_db, &Z80::Opc_cbxx_dc, &Z80::Opc_cbxx_dd, &Z80::Opc_cbxx_de, &Z80::Opc_cbxx_df, &Z80::Opc_cbxx_e0, &Z80::Opc_cbxx_e1, &Z80::Opc_cbxx_e2, &Z80::Opc_cbxx_e3, &Z80::Opc_cbxx_e4, &Z80::Opc_cbxx_e5, &Z80::Opc_cbxx_e6, &Z80::Opc_cbxx_e7, &Z80::Opc_cbxx_e8, &Z80::Opc_cbxx_e9, &Z80::Opc_cbxx_ea, &Z80::Opc_cbxx_eb, &Z80::Opc_cbxx_ec, &Z80::Opc_cbxx_ed, &Z80::Opc_cbxx_ee, &Z80::Opc_cbxx_ef, &Z80::Opc_cbxx_f0, &Z80::Opc_cbxx_f1, &Z80::Opc_cbxx_f2, &Z80::Opc_cbxx_f3, &Z80::Opc_cbxx_f4, &Z80::Opc_cbxx_f5, &Z80::Opc_cbxx_f6, &Z80::Opc_cbxx_f7, &Z80::Opc_cbxx_f8, &Z80::Opc_cbxx_f9, &Z80::Opc_cbxx_fa, &Z80::Opc_cbxx_fb, &Z80::Opc_cbxx_fc, &Z80::Opc_cbxx_fd, &Z80::Opc_cbxx_fe, &Z80::Opc_cbxx_ff }; osmose-emulator-1.4/src/Opc_dd.cpp000066400000000000000000000432621341430144300172000ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "Z80.h" void Z80::exec_dd() { u8 instruction; R++; // Prefixed instruction increments R by one. instruction = env.rd8( PC++ ); (this->*(Opc_ddxx[instruction]))(); #ifdef OPCODES_STATS DD_Prefix[ instruction ]++; #endif } /* ADD IX, BC */ void Z80::Opc_ddxx_09() { IX = add16(IX, getBC()); cycleCount += 15; } /* ADD IX, DE */ void Z80::Opc_ddxx_19() { IX = add16(IX, getDE()); cycleCount += 15; } /* LD IX, (nn) */ void Z80::Opc_ddxx_21() { IX = env.rd16(PC); PC+=2; cycleCount += 14; } /* LD (NN),IX */ void Z80::Opc_ddxx_22() { setNNi16(IX); PC+=2; cycleCount += 20; } /* INC IX */ void Z80::Opc_ddxx_23() { IX++; cycleCount += 10; } /* INC IXH */ void Z80::Opc_ddxx_24() { IX = (IX & 0xFF) | (inc8(IX >> 8) << 8); cycleCount += 9; } /* DEC IXH */ void Z80::Opc_ddxx_25() { IX = (IX & 0xFF) | (dec8(IX >> 8) << 8); cycleCount += 9; } /* LD IXH, n */ void Z80::Opc_ddxx_26() { IX = ((IX & 0xFF) | env.rd8(PC++) << 8); cycleCount += 9; } /* ADD IX, IX */ void Z80::Opc_ddxx_29() { IX = add16(IX, IX); cycleCount += 15; } /* LD IX,(nn) */ void Z80::Opc_ddxx_2a() { IX = getNNi16(); PC += 2; cycleCount += 20; } /* DEC IX */ void Z80::Opc_ddxx_2b() { IX--; cycleCount += 10; } /* INC IXL */ void Z80::Opc_ddxx_2c() { IX = (IX & 0xFF00) | (inc8(IX & 0xFF)); cycleCount += 9; } /* DEC IXL */ void Z80::Opc_ddxx_2d() { IX = (IX & 0xFF00) | (dec8(IX & 0xFF)); cycleCount += 9; } /* LD IXL, n */ void Z80::Opc_ddxx_2e() { IX = (IX & 0xFF00) | env.rd8(PC++); cycleCount += 9; } /* INC (IX+d) */ void Z80::Opc_ddxx_34() { setIXdi(inc8(getIXdi())); PC++; cycleCount += 23; } /* DEC (IX+d) */ void Z80::Opc_ddxx_35() { setIXdi(dec8(getIXdi())); PC++; cycleCount += 23; } /* LD (IX+d), n */ void Z80::Opc_ddxx_36() { setIXdi(env.rd8(PC+1)); PC += 2; cycleCount += 19; } /* ADD IX, SP */ void Z80::Opc_ddxx_39() { IX = add16(IX, SP); cycleCount += 15; } /* LD B, IXH */ void Z80::Opc_ddxx_44() { B = (IX >> 8); cycleCount += 9; } /* LD B, IXL */ void Z80::Opc_ddxx_45() { B = (IX & 0xFF); cycleCount += 9; } /* LD B, (IX+d) */ void Z80::Opc_ddxx_46() { B = getIXdi(); PC++; cycleCount += 19; } /* LD C, IXH */ void Z80::Opc_ddxx_4c() { C = (IX >> 8); cycleCount += 9; } /* LD C, IXL */ void Z80::Opc_ddxx_4d() { C = (IX & 0xFF); cycleCount += 9; } /* LD C, (IX+d) */ void Z80::Opc_ddxx_4e() { C = getIXdi(); PC++; cycleCount += 19; } /* LD D, IXH */ void Z80::Opc_ddxx_54() { D = (IX >> 8); cycleCount += 9; } /* LD D, IXL */ void Z80::Opc_ddxx_55() { D = (IX & 0xFF); cycleCount += 9; } /* LD D, (IX+d) */ void Z80::Opc_ddxx_56() { D = getIXdi(); PC++; cycleCount += 19; } /* LD E, IXH */ void Z80::Opc_ddxx_5c() { E = (IX >> 8); cycleCount += 9; } /* LD E, IXL */ void Z80::Opc_ddxx_5d() { E = (IX & 0xFF); cycleCount += 9; } /* LD E, (IX+d) */ void Z80::Opc_ddxx_5e() { E = getIXdi(); PC++; cycleCount += 19; } /* LD IXH, B */ void Z80::Opc_ddxx_60() { IX = ( IX & 0xFF ) | (( u16 )B << 8 ); cycleCount += 9; } /* LD IXH, C */ void Z80::Opc_ddxx_61() { IX = ( IX & 0xFF ) | (( u16 )C << 8 ); cycleCount += 9; } /* LD IXH, D */ void Z80::Opc_ddxx_62() { IX = ( IX & 0xFF ) | (( u16 )D << 8 ); cycleCount += 9; } /* LD IXH, E */ void Z80::Opc_ddxx_63() { IX = ( IX & 0xFF ) | (( u16 )E << 8 ); cycleCount += 9; } /* LD IXH, IXH */ void Z80::Opc_ddxx_64() { IX = (IX); // Do nothing; cycleCount += 9; } /* LD IXH, IXL */ void Z80::Opc_ddxx_65() { IX = ( IX & 0xFF ) | (( IX & 0xFF ) << 8 ); cycleCount += 9; } /* LD H, (IX+d) */ void Z80::Opc_ddxx_66() { H = getIXdi(); PC++; cycleCount += 19; } /* LD IXH, A */ void Z80::Opc_ddxx_67() { IX = ( IX & 0xFF ) | (( u16 )A << 8 ); cycleCount += 9; } /* LD IXL, B */ void Z80::Opc_ddxx_68() { IX = ( IX & 0xFF00 ) | B; cycleCount += 9; } /* LD IXL, C */ void Z80::Opc_ddxx_69() { IX = ( IX & 0xFF00 ) | C; cycleCount += 9; } /* LD IXL, D */ void Z80::Opc_ddxx_6a() { IX = ( IX & 0xFF00 ) | D; cycleCount += 9; } /* LD IXL, E */ void Z80::Opc_ddxx_6b() { IX = ( IX & 0xFF00 ) | E; cycleCount += 9; } /* LD IXL, IXH */ void Z80::Opc_ddxx_6c() { IX = ( IX & 0xFF00 ) | ( IX >> 8 ); cycleCount += 9; } /* LD IXL, IXL */ void Z80::Opc_ddxx_6d() { IX = (IX); // Do nothing; cycleCount += 9; } /* LD L, (IX+d) */ void Z80::Opc_ddxx_6e() { L = getIXdi(); PC++; cycleCount += 19; } /* LD IXL, A */ void Z80::Opc_ddxx_6f() { IX = ( IX & 0xFF00 ) | A; cycleCount += 9; } /* LD (IX+d), B */ void Z80::Opc_ddxx_70() { setIXdi(B); PC++; cycleCount += 19; } /* LD (IX+d), C */ void Z80::Opc_ddxx_71() { setIXdi(C); PC++; cycleCount += 19; } /* LD (IX+d), D */ void Z80::Opc_ddxx_72() { setIXdi(D); PC++; cycleCount += 19; } /* LD (IX+d), E */ void Z80::Opc_ddxx_73() { setIXdi(E); PC++; cycleCount += 19; } /* LD (IX+d), H */ void Z80::Opc_ddxx_74() { setIXdi(H); PC++; cycleCount += 19; } /* LD (IX+d), L */ void Z80::Opc_ddxx_75() { setIXdi(L); PC++; cycleCount += 19; } /* LD (IX+d), A */ void Z80::Opc_ddxx_77() { setIXdi(A); PC++; cycleCount += 19; } /* LD A, IXH */ void Z80::Opc_ddxx_7c() { A = (IX >> 8); cycleCount += 9; } /* LD A, IXL */ void Z80::Opc_ddxx_7d() { A = (IX & 0xFF); cycleCount += 9; } /* LD A, (IX+d) */ void Z80::Opc_ddxx_7e() { A = getIXdi(); PC++; cycleCount += 19; } /* ADD A, IXH */ void Z80::Opc_ddxx_84() { A = add8(A, IX >> 8); cycleCount += 9; } /* ADD A, IXL */ void Z80::Opc_ddxx_85() { A = add8(A, IX & 0xFF); cycleCount += 9; } /* ADD A, (IX+d) */ void Z80::Opc_ddxx_86() { A = add8(A, getIXdi()); PC++; cycleCount += 19; } /* ADC A, IXH */ void Z80::Opc_ddxx_8c() { A = adc8(A, IX >> 8); cycleCount += 9; } /* ADC A, IXL */ void Z80::Opc_ddxx_8d() { A = adc8(A, IX & 0xFF); cycleCount += 9; } /* ADC A, (IX+d) */ void Z80::Opc_ddxx_8e() { A = adc8(A, getIXdi()); PC++; cycleCount += 19; } /* SUB A, IXH */ void Z80::Opc_ddxx_94() { A = sub8(A, IX >> 8); cycleCount += 9; } /* SUB A, IXL */ void Z80::Opc_ddxx_95() { A = sub8(A, IX & 0xFF); cycleCount += 9; } /* SUB A, (IX+d) */ void Z80::Opc_ddxx_96() { A = sub8(A, getIXdi()); PC++; cycleCount += 19; } /* SBC A, IXH */ void Z80::Opc_ddxx_9c() { A = sbc8(A, IX >> 8); cycleCount += 9; } /* SBC A, IXL */ void Z80::Opc_ddxx_9d() { A = sbc8(A, IX & 0xFF); cycleCount += 9; } /* SBC A, (IX+d) */ void Z80::Opc_ddxx_9e() { A = sbc8(A, getIXdi()); PC++; cycleCount += 19; } /* AND A, IXH */ void Z80::Opc_ddxx_a4() { A = and8(A, IX >> 8); cycleCount += 9; } /* AND A, IXL */ void Z80::Opc_ddxx_a5() { A = and8(A, IX & 0xFF); cycleCount += 9; } /* AND A, (IX+d) */ void Z80::Opc_ddxx_a6() { A = and8(A, getIXdi()); PC++; cycleCount += 19; } /* XOR A, IXH */ void Z80::Opc_ddxx_ac() { A = xor8(A, IX >> 8); cycleCount += 9; } /* XOR A, IXL */ void Z80::Opc_ddxx_ad() { A = xor8(A, IX & 0xFF); cycleCount += 9; } /* XOR A, (IX+d) */ void Z80::Opc_ddxx_ae() { A = xor8(A, getIXdi()); PC++; cycleCount += 19; } /* OR A, IXH */ void Z80::Opc_ddxx_b4() { A = or8(A, IX >> 8); cycleCount += 9; } /* OR A, IXL */ void Z80::Opc_ddxx_b5() { A = or8(A, IX & 0xFF); cycleCount += 9; } /* OR A, (IX+d) */ void Z80::Opc_ddxx_b6() { A = or8(A, getIXdi()); PC++; cycleCount += 19; } /* CP A, IXH */ void Z80::Opc_ddxx_bc() { cp8(A, IX >> 8); cycleCount += 9; } /* CP A, IXL */ void Z80::Opc_ddxx_bd() { cp8(A, IX & 0xFF); cycleCount += 9; } /* CP A, (IX+d) */ void Z80::Opc_ddxx_be() { cp8(A, getIXdi()); PC++; cycleCount += 19; } /* POP IX */ void Z80::Opc_ddxx_e1() { IX = pop(); cycleCount += 14; } /* EX (SP), IX */ void Z80::Opc_ddxx_e3() { u16 tmp1 = env.rd16( SP ); env.wr16( SP, IX ); IX = tmp1; cycleCount += 23; } /* PUSH IX */ void Z80::Opc_ddxx_e5() { push(IX); cycleCount += 15; } /* JP IX or LD PC, IX */ void Z80::Opc_ddxx_e9() { PC = IX; cycleCount += 8; } /* LD SP, IX */ void Z80::Opc_ddxx_f9() { SP = IX; cycleCount += 10; } Z80::Opc_handler Z80::Opc_ddxx[256] = { &Z80::invalid_opcode, /* 0xdd00 */ &Z80::invalid_opcode, /* 0xdd01 */ &Z80::invalid_opcode, /* 0xdd02 */ &Z80::invalid_opcode, /* 0xdd03 */ &Z80::invalid_opcode, /* 0xdd04 */ &Z80::invalid_opcode, /* 0xdd05 */ &Z80::invalid_opcode, /* 0xdd06 */ &Z80::invalid_opcode, /* 0xdd07 */ &Z80::invalid_opcode, /* 0xdd08 */ &Z80::Opc_ddxx_09, &Z80::invalid_opcode, /* 0xdd0a */ &Z80::invalid_opcode, /* 0xdd0b */ &Z80::invalid_opcode, /* 0xdd0c */ &Z80::invalid_opcode, /* 0xdd0d */ &Z80::invalid_opcode, /* 0xdd0e */ &Z80::invalid_opcode, /* 0xdd0f */ &Z80::invalid_opcode, /* 0xdd10 */ &Z80::invalid_opcode, /* 0xdd11 */ &Z80::invalid_opcode, /* 0xdd12 */ &Z80::invalid_opcode, /* 0xdd13 */ &Z80::invalid_opcode, /* 0xdd14 */ &Z80::invalid_opcode, /* 0xdd15 */ &Z80::invalid_opcode, /* 0xdd16 */ &Z80::invalid_opcode, /* 0xdd17 */ &Z80::invalid_opcode, /* 0xdd18 */ &Z80::Opc_ddxx_19, &Z80::invalid_opcode, /* 0xdd1a */ &Z80::invalid_opcode, /* 0xdd1b */ &Z80::invalid_opcode, /* 0xdd1c */ &Z80::invalid_opcode, /* 0xdd1d */ &Z80::invalid_opcode, /* 0xdd1e */ &Z80::invalid_opcode, /* 0xdd1f */ &Z80::invalid_opcode, /* 0xdd20 */ &Z80::Opc_ddxx_21, &Z80::Opc_ddxx_22, &Z80::Opc_ddxx_23, &Z80::Opc_ddxx_24, &Z80::Opc_ddxx_25, &Z80::Opc_ddxx_26, &Z80::invalid_opcode, /* 0xdd27 */ &Z80::invalid_opcode, /* 0xdd28 */ &Z80::Opc_ddxx_29, &Z80::Opc_ddxx_2a, &Z80::Opc_ddxx_2b, &Z80::Opc_ddxx_2c, &Z80::Opc_ddxx_2d, &Z80::Opc_ddxx_2e, &Z80::invalid_opcode, /* 0xdd2f */ &Z80::invalid_opcode, /* 0xdd30 */ &Z80::invalid_opcode, /* 0xdd31 */ &Z80::invalid_opcode, /* 0xdd32 */ &Z80::invalid_opcode, /* 0xdd33 */ &Z80::Opc_ddxx_34, &Z80::Opc_ddxx_35, &Z80::Opc_ddxx_36, &Z80::invalid_opcode, /* 0xdd37 */ &Z80::invalid_opcode, /* 0xdd38 */ &Z80::Opc_ddxx_39, &Z80::invalid_opcode, /* 0xdd3a */ &Z80::invalid_opcode, /* 0xdd3b */ &Z80::invalid_opcode, /* 0xdd3c */ &Z80::invalid_opcode, /* 0xdd3d */ &Z80::invalid_opcode, /* 0xdd3e */ &Z80::invalid_opcode, /* 0xdd3f */ &Z80::invalid_opcode, /* 0xdd40 */ &Z80::invalid_opcode, /* 0xdd41 */ &Z80::invalid_opcode, /* 0xdd42 */ &Z80::invalid_opcode, /* 0xdd43 */ &Z80::Opc_ddxx_44, &Z80::Opc_ddxx_45, &Z80::Opc_ddxx_46, &Z80::invalid_opcode, /* 0xdd47 */ &Z80::invalid_opcode, /* 0xdd48 */ &Z80::invalid_opcode, /* 0xdd49 */ &Z80::invalid_opcode, /* 0xdd4a */ &Z80::invalid_opcode, /* 0xdd4b */ &Z80::Opc_ddxx_4c, &Z80::Opc_ddxx_4d, &Z80::Opc_ddxx_4e, &Z80::invalid_opcode, /* 0xdd4f */ &Z80::invalid_opcode, /* 0xdd50 */ &Z80::invalid_opcode, /* 0xdd51 */ &Z80::invalid_opcode, /* 0xdd52 */ &Z80::invalid_opcode, /* 0xdd53 */ &Z80::Opc_ddxx_54, &Z80::Opc_ddxx_55, &Z80::Opc_ddxx_56, &Z80::invalid_opcode, /* 0xdd57 */ &Z80::invalid_opcode, /* 0xdd58 */ &Z80::invalid_opcode, /* 0xdd59 */ &Z80::invalid_opcode, /* 0xdd5a */ &Z80::invalid_opcode, /* 0xdd5b */ &Z80::Opc_ddxx_5c, &Z80::Opc_ddxx_5d, &Z80::Opc_ddxx_5e, &Z80::invalid_opcode, /* 0xdd5f */ &Z80::Opc_ddxx_60, &Z80::Opc_ddxx_61, &Z80::Opc_ddxx_62, &Z80::Opc_ddxx_63, &Z80::Opc_ddxx_64, &Z80::Opc_ddxx_65, &Z80::Opc_ddxx_66, &Z80::Opc_ddxx_67, &Z80::Opc_ddxx_68, &Z80::Opc_ddxx_69, &Z80::Opc_ddxx_6a, &Z80::Opc_ddxx_6b, &Z80::Opc_ddxx_6c, &Z80::Opc_ddxx_6d, &Z80::Opc_ddxx_6e, &Z80::Opc_ddxx_6f, &Z80::Opc_ddxx_70, &Z80::Opc_ddxx_71, &Z80::Opc_ddxx_72, &Z80::Opc_ddxx_73, &Z80::Opc_ddxx_74, &Z80::Opc_ddxx_75, &Z80::invalid_opcode, /* 0xdd76 */ &Z80::Opc_ddxx_77, &Z80::invalid_opcode, /* 0xdd78 */ &Z80::invalid_opcode, /* 0xdd79 */ &Z80::invalid_opcode, /* 0xdd7a */ &Z80::invalid_opcode, /* 0xdd7b */ &Z80::Opc_ddxx_7c, &Z80::Opc_ddxx_7d, &Z80::Opc_ddxx_7e, &Z80::invalid_opcode, /* 0xdd7f */ &Z80::invalid_opcode, /* 0xdd80 */ &Z80::invalid_opcode, /* 0xdd81 */ &Z80::invalid_opcode, /* 0xdd82 */ &Z80::invalid_opcode, /* 0xdd83 */ &Z80::Opc_ddxx_84, &Z80::Opc_ddxx_85, &Z80::Opc_ddxx_86, &Z80::invalid_opcode, /* 0xdd87 */ &Z80::invalid_opcode, /* 0xdd88 */ &Z80::invalid_opcode, /* 0xdd89 */ &Z80::invalid_opcode, /* 0xdd8a */ &Z80::invalid_opcode, /* 0xdd8b */ &Z80::Opc_ddxx_8c, &Z80::Opc_ddxx_8d, &Z80::Opc_ddxx_8e, &Z80::invalid_opcode, /* 0xdd8f */ &Z80::invalid_opcode, /* 0xdd90 */ &Z80::invalid_opcode, /* 0xdd91 */ &Z80::invalid_opcode, /* 0xdd92 */ &Z80::invalid_opcode, /* 0xdd93 */ &Z80::Opc_ddxx_94, &Z80::Opc_ddxx_95, &Z80::Opc_ddxx_96, &Z80::invalid_opcode, /* 0xdd97 */ &Z80::invalid_opcode, /* 0xdd98 */ &Z80::invalid_opcode, /* 0xdd99 */ &Z80::invalid_opcode, /* 0xdd9a */ &Z80::invalid_opcode, /* 0xdd9b */ &Z80::Opc_ddxx_9c, &Z80::Opc_ddxx_9d, &Z80::Opc_ddxx_9e, &Z80::invalid_opcode, /* 0xdd9f */ &Z80::invalid_opcode, /* 0xdda0 */ &Z80::invalid_opcode, /* 0xdda1 */ &Z80::invalid_opcode, /* 0xdda2 */ &Z80::invalid_opcode, /* 0xdda3 */ &Z80::Opc_ddxx_a4, &Z80::Opc_ddxx_a5, &Z80::Opc_ddxx_a6, &Z80::invalid_opcode, /* 0xdda7 */ &Z80::invalid_opcode, /* 0xdda8 */ &Z80::invalid_opcode, /* 0xdda9 */ &Z80::invalid_opcode, /* 0xddaa */ &Z80::invalid_opcode, /* 0xddab */ &Z80::Opc_ddxx_ac, &Z80::Opc_ddxx_ad, &Z80::Opc_ddxx_ae, &Z80::invalid_opcode, /* 0xddaf */ &Z80::invalid_opcode, /* 0xddb0 */ &Z80::invalid_opcode, /* 0xddb1 */ &Z80::invalid_opcode, /* 0xddb2 */ &Z80::invalid_opcode, /* 0xddb3 */ &Z80::Opc_ddxx_b4, &Z80::Opc_ddxx_b5, &Z80::Opc_ddxx_b6, &Z80::invalid_opcode, /* 0xddb7 */ &Z80::invalid_opcode, /* 0xddb8 */ &Z80::invalid_opcode, /* 0xddb9 */ &Z80::invalid_opcode, /* 0xddba */ &Z80::invalid_opcode, /* 0xddbb */ &Z80::Opc_ddxx_bc, &Z80::Opc_ddxx_bd, &Z80::Opc_ddxx_be, &Z80::invalid_opcode, /* 0xddbf */ &Z80::invalid_opcode, /* 0xddc0 */ &Z80::invalid_opcode, /* 0xddc1 */ &Z80::invalid_opcode, /* 0xddc2 */ &Z80::invalid_opcode, /* 0xddc3 */ &Z80::invalid_opcode, /* 0xddc4 */ &Z80::invalid_opcode, /* 0xddc5 */ &Z80::invalid_opcode, /* 0xddc6 */ &Z80::invalid_opcode, /* 0xddc7 */ &Z80::invalid_opcode, /* 0xddc8 */ &Z80::invalid_opcode, /* 0xddc9 */ &Z80::invalid_opcode, /* 0xddca */ &Z80::exec_ddcb, &Z80::invalid_opcode, /* 0xddcc */ &Z80::invalid_opcode, /* 0xddcd */ &Z80::invalid_opcode, /* 0xddce */ &Z80::invalid_opcode, /* 0xddcf */ &Z80::invalid_opcode, /* 0xddd0 */ &Z80::invalid_opcode, /* 0xddd1 */ &Z80::invalid_opcode, /* 0xddd2 */ &Z80::invalid_opcode, /* 0xddd3 */ &Z80::invalid_opcode, /* 0xddd4 */ &Z80::invalid_opcode, /* 0xddd5 */ &Z80::invalid_opcode, /* 0xddd6 */ &Z80::invalid_opcode, /* 0xddd7 */ &Z80::invalid_opcode, /* 0xddd8 */ &Z80::invalid_opcode, /* 0xddd9 */ &Z80::invalid_opcode, /* 0xddda */ &Z80::invalid_opcode, /* 0xdddb */ &Z80::invalid_opcode, /* 0xdddc */ &Z80::invalid_opcode, /* 0xdddd */ &Z80::invalid_opcode, /* 0xddde */ &Z80::invalid_opcode, /* 0xdddf */ &Z80::invalid_opcode, /* 0xdde0 */ &Z80::Opc_ddxx_e1, &Z80::invalid_opcode, /* 0xdde2 */ &Z80::Opc_ddxx_e3, &Z80::invalid_opcode, /* 0xdde4 */ &Z80::Opc_ddxx_e5, &Z80::invalid_opcode, /* 0xdde6 */ &Z80::invalid_opcode, /* 0xdde7 */ &Z80::invalid_opcode, /* 0xdde8 */ &Z80::Opc_ddxx_e9, &Z80::invalid_opcode, /* 0xddea */ &Z80::invalid_opcode, /* 0xddeb */ &Z80::invalid_opcode, /* 0xddec */ &Z80::invalid_opcode, /* 0xdded */ &Z80::invalid_opcode, /* 0xddee */ &Z80::invalid_opcode, /* 0xddef */ &Z80::invalid_opcode, /* 0xddf0 */ &Z80::invalid_opcode, /* 0xddf1 */ &Z80::invalid_opcode, /* 0xddf2 */ &Z80::invalid_opcode, /* 0xddf3 */ &Z80::invalid_opcode, /* 0xddf4 */ &Z80::invalid_opcode, /* 0xddf5 */ &Z80::invalid_opcode, /* 0xddf6 */ &Z80::invalid_opcode, /* 0xddf7 */ &Z80::invalid_opcode, /* 0xddf8 */ &Z80::Opc_ddxx_f9, &Z80::invalid_opcode, /* 0xddfa */ &Z80::invalid_opcode, /* 0xddfb */ &Z80::invalid_opcode, /* 0xddfc */ &Z80::invalid_opcode, /* 0xddfd */ &Z80::invalid_opcode, /* 0xddfe */ &Z80::invalid_opcode /* 0xddff */ }; osmose-emulator-1.4/src/Opc_ddcb.cpp000066400000000000000000001127631341430144300175100ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "Z80.h" void Z80::exec_ddcb() { u8 instruction; R++; // Prefixed instruction increments R by one. IXd = (u16)(IX + (s8)env.rd8(PC++)); instruction = env.rd8( PC++ ); (this->*(Opc_ddcb[instruction]))(); #ifdef OPCODES_STATS DDCB_Prefix[ instruction ]++; #endif } /* LD B, RLC (IX+d) */ void Z80::Opc_ddcb_00() { B = rlc8(env.rd8(IXd)); env.wr8(IXd, B); cycleCount += 23; } /* LD C, RLC (IX+d) */ void Z80::Opc_ddcb_01() { C = rlc8(env.rd8(IXd)); env.wr8(IXd, C); cycleCount += 23; } /* LD D, RLC (IX+d) */ void Z80::Opc_ddcb_02() { D = rlc8(env.rd8(IXd)); env.wr8(IXd, D); cycleCount += 23; } /* LD E, RLC (IX+d) */ void Z80::Opc_ddcb_03() { E = rlc8(env.rd8(IXd)); env.wr8(IXd, E); cycleCount += 23; } /* LD H, RLC (IX+d) */ void Z80::Opc_ddcb_04() { H = rlc8(env.rd8(IXd)); env.wr8(IXd, H); cycleCount += 23; } /* LD L, RLC (IX+d) */ void Z80::Opc_ddcb_05() { L = rlc8(env.rd8(IXd)); env.wr8(IXd, L); cycleCount += 23; } /* RLC (IX+d) */ void Z80::Opc_ddcb_06() { env.wr8(IXd, rlc8(env.rd8(IXd))); cycleCount += 23; } /* LD A, RLC (IX+d) */ void Z80::Opc_ddcb_07() { A = rlc8(env.rd8(IXd)); env.wr8(IXd, A); cycleCount += 23; } /* LD B, RRC (IX+d) */ void Z80::Opc_ddcb_08() { B = rrc8(env.rd8(IXd)); env.wr8(IXd, B); cycleCount += 23; } /* LD C, RRC (IX+d) */ void Z80::Opc_ddcb_09() { C = rrc8(env.rd8(IXd)); env.wr8(IXd, C); cycleCount += 23; } /* LD D, RRC (IX+d) */ void Z80::Opc_ddcb_0a() { D = rrc8(env.rd8(IXd)); env.wr8(IXd, D); cycleCount += 23; } /* LD E, RRC (IX+d) */ void Z80::Opc_ddcb_0b() { E = rrc8(env.rd8(IXd)); env.wr8(IXd, E); cycleCount += 23; } /* LD H, RRC (IX+d) */ void Z80::Opc_ddcb_0c() { H = rrc8(env.rd8(IXd)); env.wr8(IXd, H); cycleCount += 23; } /* LD L, RRC (IX+d) */ void Z80::Opc_ddcb_0d() { L = rrc8(env.rd8(IXd)); env.wr8(IXd, L); cycleCount += 23; } /* RRC (IX+d) */ void Z80::Opc_ddcb_0e() { env.wr8(IXd, rrc8(env.rd8(IXd))); cycleCount += 23; } /* LD A, RRC (IX+d) */ void Z80::Opc_ddcb_0f() { A = rrc8(env.rd8(IXd)); env.wr8(IXd, A); cycleCount += 23; } /* LD B, RL (IX+d) */ void Z80::Opc_ddcb_10() { B = rl8(env.rd8(IXd)); env.wr8(IXd, B); cycleCount += 23; } /* LD C, RL (IX+d) */ void Z80::Opc_ddcb_11() { C = rl8(env.rd8(IXd)); env.wr8(IXd, C); cycleCount += 23; } /* LD D, RL (IX+d) */ void Z80::Opc_ddcb_12() { D = rl8(env.rd8(IXd)); env.wr8(IXd, D); cycleCount += 23; } /* LD E, RL (IX+d) */ void Z80::Opc_ddcb_13() { E = rl8(env.rd8(IXd)); env.wr8(IXd, E); cycleCount += 23; } /* LD H, RL (IX+d) */ void Z80::Opc_ddcb_14() { H = rl8(env.rd8(IXd)); env.wr8(IXd, H); cycleCount += 23; } /* LD L, RL (IX+d) */ void Z80::Opc_ddcb_15() { L = rl8(env.rd8(IXd)); env.wr8(IXd, L); cycleCount += 23; } /* RL (IX+d) */ void Z80::Opc_ddcb_16() { env.wr8(IXd, rl8(env.rd8(IXd))); cycleCount += 23; } /* LD A, RL (IX+d) */ void Z80::Opc_ddcb_17() { A = rl8(env.rd8(IXd)); env.wr8(IXd, A); cycleCount += 23; } /* LD B, RR (IX+d) */ void Z80::Opc_ddcb_18() { B = rr8(env.rd8(IXd)); env.wr8(IXd, B); cycleCount += 23; } /* LD C, RR (IX+d) */ void Z80::Opc_ddcb_19() { C = rr8(env.rd8(IXd)); env.wr8(IXd, C); cycleCount += 23; } /* LD D, RR (IX+d) */ void Z80::Opc_ddcb_1a() { D = rr8(env.rd8(IXd)); env.wr8(IXd, D); cycleCount += 23; } /* LD E, RR (IX+d) */ void Z80::Opc_ddcb_1b() { E = rr8(env.rd8(IXd)); env.wr8(IXd, E); cycleCount += 23; } /* LD H, RR (IX+d) */ void Z80::Opc_ddcb_1c() { H = rr8(env.rd8(IXd)); env.wr8(IXd, H); cycleCount += 23; } /* LD L, RR (IX+d) */ void Z80::Opc_ddcb_1d() { L = rr8(env.rd8(IXd)); env.wr8(IXd, L); cycleCount += 23; } /* RR (IX+d) */ void Z80::Opc_ddcb_1e() { env.wr8(IXd, rr8(env.rd8(IXd))); cycleCount += 23; } /* LD A, RR (IX+d) */ void Z80::Opc_ddcb_1f() { A = rr8(env.rd8(IXd)); env.wr8(IXd, A); cycleCount += 23; } /* LD B, SLA (IX+d) */ void Z80::Opc_ddcb_20() { B = sla8(env.rd8(IXd)); env.wr8(IXd, B); cycleCount += 23; } /* LD C, SLA (IX+d) */ void Z80::Opc_ddcb_21() { C = sla8(env.rd8(IXd)); env.wr8(IXd, C); cycleCount += 23; } /* LD D, SLA (IX+d) */ void Z80::Opc_ddcb_22() { D = sla8(env.rd8(IXd)); env.wr8(IXd, D); cycleCount += 23; } /* LD E, SLA (IX+d) */ void Z80::Opc_ddcb_23() { E = sla8(env.rd8(IXd)); env.wr8(IXd, E); cycleCount += 23; } /* LD H, SLA (IX+d) */ void Z80::Opc_ddcb_24() { H = sla8(env.rd8(IXd)); env.wr8(IXd, H); cycleCount += 23; } /* LD L, SLA (IX+d) */ void Z80::Opc_ddcb_25() { L = sla8(env.rd8(IXd)); env.wr8(IXd, L); cycleCount += 23; } /* SLA (IX+d) */ void Z80::Opc_ddcb_26() { env.wr8(IXd, sla8(env.rd8(IXd))); cycleCount += 23; } /* LD A, SLA (IX+d) */ void Z80::Opc_ddcb_27() { A = sla8(env.rd8(IXd)); env.wr8(IXd, A); cycleCount += 23; } /* LD B, SRA (IX+d) */ void Z80::Opc_ddcb_28() { B = sra8(env.rd8(IXd)); env.wr8(IXd, B); cycleCount += 23; } /* LD C, SRA (IX+d) */ void Z80::Opc_ddcb_29() { C = sra8(env.rd8(IXd)); env.wr8(IXd, C); cycleCount += 23; } /* LD D, SRA (IX+d) */ void Z80::Opc_ddcb_2a() { D = sra8(env.rd8(IXd)); env.wr8(IXd, D); cycleCount += 23; } /* LD E, SRA (IX+d) */ void Z80::Opc_ddcb_2b() { E = sra8(env.rd8(IXd)); env.wr8(IXd, E); cycleCount += 23; } /* LD H, SRA (IX+d) */ void Z80::Opc_ddcb_2c() { H = sra8(env.rd8(IXd)); env.wr8(IXd, H); cycleCount += 23; } /* LD L, SRA (IX+d) */ void Z80::Opc_ddcb_2d() { L = sra8(env.rd8(IXd)); env.wr8(IXd, L); cycleCount += 23; } /* SRA (IX+d) */ void Z80::Opc_ddcb_2e() { env.wr8(IXd, sra8(env.rd8(IXd))); cycleCount += 23; } /* LD A, SRA (IX+d) */ void Z80::Opc_ddcb_2f() { A = sra8(env.rd8(IXd)); env.wr8(IXd, A); cycleCount += 23; } /* LD B, SLL (IX+d) */ void Z80::Opc_ddcb_30() { B = sll8(env.rd8(IXd)); env.wr8(IXd, B); cycleCount += 23; } /* LD C, SLL (IX+d) */ void Z80::Opc_ddcb_31() { C = sll8(env.rd8(IXd)); env.wr8(IXd, C); cycleCount += 23; } /* LD D, SLL (IX+d) */ void Z80::Opc_ddcb_32() { D = sll8(env.rd8(IXd)); env.wr8(IXd, D); cycleCount += 23; } /* LD E, SLL (IX+d) */ void Z80::Opc_ddcb_33() { E = sll8(env.rd8(IXd)); env.wr8(IXd, E); cycleCount += 23; } /* LD H, SLL (IX+d) */ void Z80::Opc_ddcb_34() { H = sll8(env.rd8(IXd)); env.wr8(IXd, H); cycleCount += 23; } /* LD L, SLL (IX+d) */ void Z80::Opc_ddcb_35() { L = sll8(env.rd8(IXd)); env.wr8(IXd, L); cycleCount += 23; } /* SLL (IX+d) */ void Z80::Opc_ddcb_36() { env.wr8(IXd, sll8(env.rd8(IXd))); cycleCount += 23; } /* LD A, SLL (IX+d) */ void Z80::Opc_ddcb_37() { A = sll8(env.rd8(IXd)); env.wr8(IXd, A); cycleCount += 23; } /* LD B, SRL (IX+d) */ void Z80::Opc_ddcb_38() { B = srl8(env.rd8(IXd)); env.wr8(IXd, B); cycleCount += 23; } /* LD C, SRL (IX+d) */ void Z80::Opc_ddcb_39() { C = srl8(env.rd8(IXd)); env.wr8(IXd, C); cycleCount += 23; } /* LD D, SRL (IX+d) */ void Z80::Opc_ddcb_3a() { D = srl8(env.rd8(IXd)); env.wr8(IXd, D); cycleCount += 23; } /* LD E, SRL (IX+d) */ void Z80::Opc_ddcb_3b() { E = srl8(env.rd8(IXd)); env.wr8(IXd, E); cycleCount += 23; } /* LD H, SRL (IX+d) */ void Z80::Opc_ddcb_3c() { H = srl8(env.rd8(IXd)); env.wr8(IXd, H); cycleCount += 23; } /* LD L, SRL (IX+d) */ void Z80::Opc_ddcb_3d() { L = srl8(env.rd8(IXd)); env.wr8(IXd, L); cycleCount += 23; } /* SRL (IX+d) */ void Z80::Opc_ddcb_3e() { env.wr8(IXd, srl8(env.rd8(IXd))); cycleCount += 23; } /* LD A, SRL (IX+d) */ void Z80::Opc_ddcb_3f() { A = srl8(env.rd8(IXd)); env.wr8(IXd, A); cycleCount += 23; } /* BIT 0, (IX+d) */ void Z80::Opc_ddcb_40() { bit(0, env.rd8(IXd)); cycleCount += 20; } /* BIT 0, (IX+d) */ void Z80::Opc_ddcb_41() { bit(0, env.rd8(IXd)); cycleCount += 20; } /* BIT 0, (IX+d) */ void Z80::Opc_ddcb_42() { bit(0, env.rd8(IXd)); cycleCount += 20; } /* BIT 0, (IX+d) */ void Z80::Opc_ddcb_43() { bit(0, env.rd8(IXd)); cycleCount += 20; } /* BIT 0, (IX+d) */ void Z80::Opc_ddcb_44() { bit(0, env.rd8(IXd)); cycleCount += 20; } /* BIT 0, (IX+d) */ void Z80::Opc_ddcb_45() { bit(0, env.rd8(IXd)); cycleCount += 20; } /* BIT 0, (IX+d) */ void Z80::Opc_ddcb_46() { bit(0, env.rd8(IXd)); cycleCount += 20; } /* BIT 0, (IX+d) */ void Z80::Opc_ddcb_47() { bit(0, env.rd8(IXd)); cycleCount += 20; } /* BIT 1, (IX+d) */ void Z80::Opc_ddcb_48() { bit(1, env.rd8(IXd)); cycleCount += 20; } /* BIT 1, (IX+d) */ void Z80::Opc_ddcb_49() { bit(1, env.rd8(IXd)); cycleCount += 20; } /* BIT 1, (IX+d) */ void Z80::Opc_ddcb_4a() { bit(1, env.rd8(IXd)); cycleCount += 20; } /* BIT 1, (IX+d) */ void Z80::Opc_ddcb_4b() { bit(1, env.rd8(IXd)); cycleCount += 20; } /* BIT 1, (IX+d) */ void Z80::Opc_ddcb_4c() { bit(1, env.rd8(IXd)); cycleCount += 20; } /* BIT 1, (IX+d) */ void Z80::Opc_ddcb_4d() { bit(1, env.rd8(IXd)); cycleCount += 20; } /* BIT 1, (IX+d) */ void Z80::Opc_ddcb_4e() { bit(1, env.rd8(IXd)); cycleCount += 20; } /* BIT 1, (IX+d) */ void Z80::Opc_ddcb_4f() { bit(1, env.rd8(IXd)); cycleCount += 20; } /* BIT 2, (IX+d) */ void Z80::Opc_ddcb_50() { bit(2, env.rd8(IXd)); cycleCount += 20; } /* BIT 2, (IX+d) */ void Z80::Opc_ddcb_51() { bit(2, env.rd8(IXd)); cycleCount += 20; } /* BIT 2, (IX+d) */ void Z80::Opc_ddcb_52() { bit(2, env.rd8(IXd)); cycleCount += 20; } /* BIT 2, (IX+d) */ void Z80::Opc_ddcb_53() { bit(2, env.rd8(IXd)); cycleCount += 20; } /* BIT 2, (IX+d) */ void Z80::Opc_ddcb_54() { bit(2, env.rd8(IXd)); cycleCount += 20; } /* BIT 2, (IX+d) */ void Z80::Opc_ddcb_55() { bit(2, env.rd8(IXd)); cycleCount += 20; } /* BIT 2, (IX+d) */ void Z80::Opc_ddcb_56() { bit(2, env.rd8(IXd)); cycleCount += 20; } /* BIT 2, (IX+d) */ void Z80::Opc_ddcb_57() { bit(2, env.rd8(IXd)); cycleCount += 20; } /* BIT 3, (IX+d) */ void Z80::Opc_ddcb_58() { bit(3, env.rd8(IXd)); cycleCount += 20; } /* BIT 3, (IX+d) */ void Z80::Opc_ddcb_59() { bit(3, env.rd8(IXd)); cycleCount += 20; } /* BIT 3, (IX+d) */ void Z80::Opc_ddcb_5a() { bit(3, env.rd8(IXd)); cycleCount += 20; } /* BIT 3, (IX+d) */ void Z80::Opc_ddcb_5b() { bit(3, env.rd8(IXd)); cycleCount += 20; } /* BIT 3, (IX+d) */ void Z80::Opc_ddcb_5c() { bit(3, env.rd8(IXd)); cycleCount += 20; } /* BIT 3, (IX+d) */ void Z80::Opc_ddcb_5d() { bit(3, env.rd8(IXd)); cycleCount += 20; } /* BIT 3, (IX+d) */ void Z80::Opc_ddcb_5e() { bit(3, env.rd8(IXd)); cycleCount += 20; } /* BIT 3, (IX+d) */ void Z80::Opc_ddcb_5f() { bit(3, env.rd8(IXd)); cycleCount += 20; } /* BIT 4, (IX+d) */ void Z80::Opc_ddcb_60() { bit(4, env.rd8(IXd)); cycleCount += 20; } /* BIT 4, (IX+d) */ void Z80::Opc_ddcb_61() { bit(4, env.rd8(IXd)); cycleCount += 20; } /* BIT 4, (IX+d) */ void Z80::Opc_ddcb_62() { bit(4, env.rd8(IXd)); cycleCount += 20; } /* BIT 4, (IX+d) */ void Z80::Opc_ddcb_63() { bit(4, env.rd8(IXd)); cycleCount += 20; } /* BIT 4, (IX+d) */ void Z80::Opc_ddcb_64() { bit(4, env.rd8(IXd)); cycleCount += 20; } /* BIT 4, (IX+d) */ void Z80::Opc_ddcb_65() { bit(4, env.rd8(IXd)); cycleCount += 20; } /* BIT 4, (IX+d) */ void Z80::Opc_ddcb_66() { bit(4, env.rd8(IXd)); cycleCount += 20; } /* BIT 4, (IX+d) */ void Z80::Opc_ddcb_67() { bit(4, env.rd8(IXd)); cycleCount += 20; } /* BIT 5, (IX+d) */ void Z80::Opc_ddcb_68() { bit(5, env.rd8(IXd)); cycleCount += 20; } /* BIT 5, (IX+d) */ void Z80::Opc_ddcb_69() { bit(5, env.rd8(IXd)); cycleCount += 20; } /* BIT 5, (IX+d) */ void Z80::Opc_ddcb_6a() { bit(5, env.rd8(IXd)); cycleCount += 20; } /* BIT 5, (IX+d) */ void Z80::Opc_ddcb_6b() { bit(5, env.rd8(IXd)); cycleCount += 20; } /* BIT 5, (IX+d) */ void Z80::Opc_ddcb_6c() { bit(5, env.rd8(IXd)); cycleCount += 20; } /* BIT 5, (IX+d) */ void Z80::Opc_ddcb_6d() { bit(5, env.rd8(IXd)); cycleCount += 20; } /* BIT 5, (IX+d) */ void Z80::Opc_ddcb_6e() { bit(5, env.rd8(IXd)); cycleCount += 20; } /* BIT 5, (IX+d) */ void Z80::Opc_ddcb_6f() { bit(5, env.rd8(IXd)); cycleCount += 20; } /* BIT 6, (IX+d) */ void Z80::Opc_ddcb_70() { bit(6, env.rd8(IXd)); cycleCount += 20; } /* BIT 6, (IX+d) */ void Z80::Opc_ddcb_71() { bit(6, env.rd8(IXd)); cycleCount += 20; } /* BIT 6, (IX+d) */ void Z80::Opc_ddcb_72() { bit(6, env.rd8(IXd)); cycleCount += 20; } /* BIT 6, (IX+d) */ void Z80::Opc_ddcb_73() { bit(6, env.rd8(IXd)); cycleCount += 20; } /* BIT 6, (IX+d) */ void Z80::Opc_ddcb_74() { bit(6, env.rd8(IXd)); cycleCount += 20; } /* BIT 6, (IX+d) */ void Z80::Opc_ddcb_75() { bit(6, env.rd8(IXd)); cycleCount += 20; } /* BIT 6, (IX+d) */ void Z80::Opc_ddcb_76() { bit(6, env.rd8(IXd)); cycleCount += 20; } /* BIT 6, (IX+d) */ void Z80::Opc_ddcb_77() { bit(6, env.rd8(IXd)); cycleCount += 20; } /* BIT 7, (IX+d) */ void Z80::Opc_ddcb_78() { bit(7, env.rd8(IXd)); cycleCount += 20; } /* BIT 7, (IX+d) */ void Z80::Opc_ddcb_79() { bit(7, env.rd8(IXd)); cycleCount += 20; } /* BIT 7, (IX+d) */ void Z80::Opc_ddcb_7a() { bit(7, env.rd8(IXd)); cycleCount += 20; } /* BIT 7, (IX+d) */ void Z80::Opc_ddcb_7b() { bit(7, env.rd8(IXd)); cycleCount += 20; } /* BIT 7, (IX+d) */ void Z80::Opc_ddcb_7c() { bit(7, env.rd8(IXd)); cycleCount += 20; } /* BIT 7, (IX+d) */ void Z80::Opc_ddcb_7d() { bit(7, env.rd8(IXd)); cycleCount += 20; } /* BIT 7, (IX+d) */ void Z80::Opc_ddcb_7e() { bit(7, env.rd8(IXd)); cycleCount += 20; } /* BIT 7, (IX+d) */ void Z80::Opc_ddcb_7f() { bit(7, env.rd8(IXd)); cycleCount += 20; } /* LD B, RES 0, (IX+d) */ void Z80::Opc_ddcb_80() { env.wr8(IXd, res(0, env.rd8(IXd))); B = env.rd8(IXd); cycleCount += 23; } /* LD C, RES 0, (IX+d) */ void Z80::Opc_ddcb_81() { env.wr8(IXd, res(0, env.rd8(IXd))); C = env.rd8(IXd); cycleCount += 23; } /* LD D, RES 0, (IX+d) */ void Z80::Opc_ddcb_82() { env.wr8(IXd, res(0, env.rd8(IXd))); D = env.rd8(IXd); cycleCount += 23; } /* LD E, RES 0, (IX+d) */ void Z80::Opc_ddcb_83() { env.wr8(IXd, res(0, env.rd8(IXd))); E = env.rd8(IXd); cycleCount += 23; } /* LD H, RES 0, (IX+d) */ void Z80::Opc_ddcb_84() { env.wr8(IXd, res(0, env.rd8(IXd))); H = env.rd8(IXd); cycleCount += 23; } /* LD L, RES 0, (IX+d) */ void Z80::Opc_ddcb_85() { env.wr8(IXd, res(0, env.rd8(IXd))); L = env.rd8(IXd); cycleCount += 23; } /* RES 0, (IX+d) */ void Z80::Opc_ddcb_86() { env.wr8(IXd, res(0, env.rd8(IXd))); cycleCount += 23; } /* LD A, RES 0, (IX+d) */ void Z80::Opc_ddcb_87() { env.wr8(IXd, res(0, env.rd8(IXd))); A = env.rd8(IXd); cycleCount += 23; } /* LD B, RES 1, (IX+d) */ void Z80::Opc_ddcb_88() { env.wr8(IXd, res(1, env.rd8(IXd))); B = env.rd8(IXd); cycleCount += 23; } /* LD C, RES 1, (IX+d) */ void Z80::Opc_ddcb_89() { env.wr8(IXd, res(1, env.rd8(IXd))); C = env.rd8(IXd); cycleCount += 23; } /* LD D, RES 1, (IX+d) */ void Z80::Opc_ddcb_8a() { env.wr8(IXd, res(1, env.rd8(IXd))); D = env.rd8(IXd); cycleCount += 23; } /* LD E, RES 1, (IX+d) */ void Z80::Opc_ddcb_8b() { env.wr8(IXd, res(1, env.rd8(IXd))); E = env.rd8(IXd); cycleCount += 23; } /* LD H, RES 1, (IX+d) */ void Z80::Opc_ddcb_8c() { env.wr8(IXd, res(1, env.rd8(IXd))); H = env.rd8(IXd); cycleCount += 23; } /* LD L, RES 1, (IX+d) */ void Z80::Opc_ddcb_8d() { env.wr8(IXd, res(1, env.rd8(IXd))); L = env.rd8(IXd); cycleCount += 23; } /* RES 1, (IX+d) */ void Z80::Opc_ddcb_8e() { env.wr8(IXd, res(1, env.rd8(IXd))); cycleCount += 23; } /* LD A, RES 1, (IX+d) */ void Z80::Opc_ddcb_8f() { env.wr8(IXd, res(1, env.rd8(IXd))); A = env.rd8(IXd); cycleCount += 23; } /* LD B, RES 2, (IX+d) */ void Z80::Opc_ddcb_90() { env.wr8(IXd, res(2, env.rd8(IXd))); B = env.rd8(IXd); cycleCount += 23; } /* LD C, RES 2, (IX+d) */ void Z80::Opc_ddcb_91() { env.wr8(IXd, res(2, env.rd8(IXd))); C = env.rd8(IXd); cycleCount += 23; } /* LD D, RES 2, (IX+d) */ void Z80::Opc_ddcb_92() { env.wr8(IXd, res(2, env.rd8(IXd))); D = env.rd8(IXd); cycleCount += 23; } /* LD E, RES 2, (IX+d) */ void Z80::Opc_ddcb_93() { env.wr8(IXd, res(2, env.rd8(IXd))); E = env.rd8(IXd); cycleCount += 23; } /* LD H, RES 2, (IX+d) */ void Z80::Opc_ddcb_94() { env.wr8(IXd, res(2, env.rd8(IXd))); H = env.rd8(IXd); cycleCount += 23; } /* LD L, RES 2, (IX+d) */ void Z80::Opc_ddcb_95() { env.wr8(IXd, res(2, env.rd8(IXd))); L = env.rd8(IXd); cycleCount += 23; } /* RES 2, (IX+d) */ void Z80::Opc_ddcb_96() { env.wr8(IXd, res(2, env.rd8(IXd))); cycleCount += 23; } /* LD A, RES 2, (IX+d) */ void Z80::Opc_ddcb_97() { env.wr8(IXd, res(2, env.rd8(IXd))); A = env.rd8(IXd); cycleCount += 23; } /* LD B, RES 3, (IX+d) */ void Z80::Opc_ddcb_98() { env.wr8(IXd, res(3, env.rd8(IXd))); B = env.rd8(IXd); cycleCount += 23; } /* LD C, RES 3, (IX+d) */ void Z80::Opc_ddcb_99() { env.wr8(IXd, res(3, env.rd8(IXd))); C = env.rd8(IXd); cycleCount += 23; } /* LD D, RES 3, (IX+d) */ void Z80::Opc_ddcb_9a() { env.wr8(IXd, res(3, env.rd8(IXd))); D = env.rd8(IXd); cycleCount += 23; } /* LD E, RES 3, (IX+d) */ void Z80::Opc_ddcb_9b() { env.wr8(IXd, res(3, env.rd8(IXd))); E = env.rd8(IXd); cycleCount += 23; } /* LD H, RES 3, (IX+d) */ void Z80::Opc_ddcb_9c() { env.wr8(IXd, res(3, env.rd8(IXd))); H = env.rd8(IXd); cycleCount += 23; } /* LD L, RES 3, (IX+d) */ void Z80::Opc_ddcb_9d() { env.wr8(IXd, res(3, env.rd8(IXd))); L = env.rd8(IXd); cycleCount += 23; } /* RES 3, (IX+d) */ void Z80::Opc_ddcb_9e() { env.wr8(IXd, res(3, env.rd8(IXd))); cycleCount += 23; } /* LD A, RES 3, (IX+d) */ void Z80::Opc_ddcb_9f() { env.wr8(IXd, res(3, env.rd8(IXd))); A = env.rd8(IXd); cycleCount += 23; } /* LD B, RES 4, (IX+d) */ void Z80::Opc_ddcb_a0() { env.wr8(IXd, res(4, env.rd8(IXd))); B = env.rd8(IXd); cycleCount += 23; } /* LD C, RES 4, (IX+d) */ void Z80::Opc_ddcb_a1() { env.wr8(IXd, res(4, env.rd8(IXd))); C = env.rd8(IXd); cycleCount += 23; } /* LD D, RES 4, (IX+d) */ void Z80::Opc_ddcb_a2() { env.wr8(IXd, res(4, env.rd8(IXd))); D = env.rd8(IXd); cycleCount += 23; } /* LD E, RES 4, (IX+d) */ void Z80::Opc_ddcb_a3() { env.wr8(IXd, res(4, env.rd8(IXd))); E = env.rd8(IXd); cycleCount += 23; } /* LD H, RES 4, (IX+d) */ void Z80::Opc_ddcb_a4() { env.wr8(IXd, res(4, env.rd8(IXd))); H = env.rd8(IXd); cycleCount += 23; } /* LD L, RES 4, (IX+d) */ void Z80::Opc_ddcb_a5() { env.wr8(IXd, res(4, env.rd8(IXd))); L = env.rd8(IXd); cycleCount += 23; } /* RES 4, (IX+d) */ void Z80::Opc_ddcb_a6() { env.wr8(IXd, res(4, env.rd8(IXd))); cycleCount += 23; } /* LD A, RES 4, (IX+d) */ void Z80::Opc_ddcb_a7() { env.wr8(IXd, res(4, env.rd8(IXd))); A = env.rd8(IXd); cycleCount += 23; } /* LD B, RES 5, (IX+d) */ void Z80::Opc_ddcb_a8() { env.wr8(IXd, res(5, env.rd8(IXd))); B = env.rd8(IXd); cycleCount += 23; } /* LD C, RES 5, (IX+d) */ void Z80::Opc_ddcb_a9() { env.wr8(IXd, res(5, env.rd8(IXd))); C = env.rd8(IXd); cycleCount += 23; } /* LD D, RES 5, (IX+d) */ void Z80::Opc_ddcb_aa() { env.wr8(IXd, res(5, env.rd8(IXd))); D = env.rd8(IXd); cycleCount += 23; } /* LD E, RES 5, (IX+d) */ void Z80::Opc_ddcb_ab() { env.wr8(IXd, res(5, env.rd8(IXd))); E = env.rd8(IXd); cycleCount += 23; } /* LD H, RES 5, (IX+d) */ void Z80::Opc_ddcb_ac() { env.wr8(IXd, res(5, env.rd8(IXd))); H = env.rd8(IXd); cycleCount += 23; } /* LD L, RES 5, (IX+d) */ void Z80::Opc_ddcb_ad() { env.wr8(IXd, res(5, env.rd8(IXd))); L = env.rd8(IXd); cycleCount += 23; } /* RES 5, (IX+d) */ void Z80::Opc_ddcb_ae() { env.wr8(IXd, res(5, env.rd8(IXd))); cycleCount += 23; } /* LD A, RES 5, (IX+d) */ void Z80::Opc_ddcb_af() { env.wr8(IXd, res(5, env.rd8(IXd))); A = env.rd8(IXd); cycleCount += 23; } /* LD B, RES 6, (IX+d) */ void Z80::Opc_ddcb_b0() { env.wr8(IXd, res(6, env.rd8(IXd))); B = env.rd8(IXd); cycleCount += 23; } /* LD C, RES 6, (IX+d) */ void Z80::Opc_ddcb_b1() { env.wr8(IXd, res(6, env.rd8(IXd))); C = env.rd8(IXd); cycleCount += 23; } /* LD D, RES 6, (IX+d) */ void Z80::Opc_ddcb_b2() { env.wr8(IXd, res(6, env.rd8(IXd))); D = env.rd8(IXd); cycleCount += 23; } /* LD E, RES 6, (IX+d) */ void Z80::Opc_ddcb_b3() { env.wr8(IXd, res(6, env.rd8(IXd))); E = env.rd8(IXd); cycleCount += 23; } /* LD H, RES 6, (IX+d) */ void Z80::Opc_ddcb_b4() { env.wr8(IXd, res(6, env.rd8(IXd))); H = env.rd8(IXd); cycleCount += 23; } /* LD L, RES 6, (IX+d) */ void Z80::Opc_ddcb_b5() { env.wr8(IXd, res(6, env.rd8(IXd))); L = env.rd8(IXd); cycleCount += 23; } /* RES 6, (IX+d) */ void Z80::Opc_ddcb_b6() { env.wr8(IXd, res(6, env.rd8(IXd))); cycleCount += 23; } /* LD A, RES 6, (IX+d) */ void Z80::Opc_ddcb_b7() { env.wr8(IXd, res(6, env.rd8(IXd))); A = env.rd8(IXd); cycleCount += 23; } /* LD B, RES 7, (IX+d) */ void Z80::Opc_ddcb_b8() { env.wr8(IXd, res(7, env.rd8(IXd))); B = env.rd8(IXd); cycleCount += 23; } /* LD C, RES 7, (IX+d) */ void Z80::Opc_ddcb_b9() { env.wr8(IXd, res(7, env.rd8(IXd))); C = env.rd8(IXd); cycleCount += 23; } /* LD D, RES 7, (IX+d) */ void Z80::Opc_ddcb_ba() { env.wr8(IXd, res(7, env.rd8(IXd))); D = env.rd8(IXd); cycleCount += 23; } /* LD E, RES 7, (IX+d) */ void Z80::Opc_ddcb_bb() { env.wr8(IXd, res(7, env.rd8(IXd))); E = env.rd8(IXd); cycleCount += 23; } /* LD H, RES 7, (IX+d) */ void Z80::Opc_ddcb_bc() { env.wr8(IXd, res(7, env.rd8(IXd))); H = env.rd8(IXd); cycleCount += 23; } /* LD L, RES 7, (IX+d) */ void Z80::Opc_ddcb_bd() { env.wr8(IXd, res(7, env.rd8(IXd))); L = env.rd8(IXd); cycleCount += 23; } /* RES 7, (IX+d) */ void Z80::Opc_ddcb_be() { env.wr8(IXd, res(7, env.rd8(IXd))); cycleCount += 23; } /* LD A, RES 7, (IX+d) */ void Z80::Opc_ddcb_bf() { env.wr8(IXd, res(7, env.rd8(IXd))); A = env.rd8(IXd); cycleCount += 23; } /* LD B, SET 0, (IX+d) */ void Z80::Opc_ddcb_c0() { env.wr8(IXd, set(0, env.rd8(IXd))); B = env.rd8(IXd); cycleCount += 23; } /* LD C, SET 0, (IX+d) */ void Z80::Opc_ddcb_c1() { env.wr8(IXd, set(0, env.rd8(IXd))); C = env.rd8(IXd); cycleCount += 23; } /* LD D, SET 0, (IX+d) */ void Z80::Opc_ddcb_c2() { env.wr8(IXd, set(0, env.rd8(IXd))); D = env.rd8(IXd); cycleCount += 23; } /* LD E, SET 0, (IX+d) */ void Z80::Opc_ddcb_c3() { env.wr8(IXd, set(0, env.rd8(IXd))); E = env.rd8(IXd); cycleCount += 23; } /* LD H, SET 0, (IX+d) */ void Z80::Opc_ddcb_c4() { env.wr8(IXd, set(0, env.rd8(IXd))); H = env.rd8(IXd); cycleCount += 23; } /* LD L, SET 0, (IX+d) */ void Z80::Opc_ddcb_c5() { env.wr8(IXd, set(0, env.rd8(IXd))); L = env.rd8(IXd); cycleCount += 23; } /* SET 0, (IX+d) */ void Z80::Opc_ddcb_c6() { env.wr8(IXd, set(0, env.rd8(IXd))); cycleCount += 23; } /* LD A, SET 0, (IX+d) */ void Z80::Opc_ddcb_c7() { env.wr8(IXd, set(0, env.rd8(IXd))); A = env.rd8(IXd); cycleCount += 23; } /* LD B, SET 1, (IX+d) */ void Z80::Opc_ddcb_c8() { env.wr8(IXd, set(1, env.rd8(IXd))); B = env.rd8(IXd); cycleCount += 23; } /* LD C, SET 1, (IX+d) */ void Z80::Opc_ddcb_c9() { env.wr8(IXd, set(1, env.rd8(IXd))); C = env.rd8(IXd); cycleCount += 23; } /* LD D, SET 1, (IX+d) */ void Z80::Opc_ddcb_ca() { env.wr8(IXd, set(1, env.rd8(IXd))); D = env.rd8(IXd); cycleCount += 23; } /* LD E, SET 1, (IX+d) */ void Z80::Opc_ddcb_cb() { env.wr8(IXd, set(1, env.rd8(IXd))); E = env.rd8(IXd); cycleCount += 23; } /* LD H, SET 1, (IX+d) */ void Z80::Opc_ddcb_cc() { env.wr8(IXd, set(1, env.rd8(IXd))); H = env.rd8(IXd); cycleCount += 23; } /* LD L, SET 1, (IX+d) */ void Z80::Opc_ddcb_cd() { env.wr8(IXd, set(1, env.rd8(IXd))); L = env.rd8(IXd); cycleCount += 23; } /* SET 1, (IX+d) */ void Z80::Opc_ddcb_ce() { env.wr8(IXd, set(1, env.rd8(IXd))); cycleCount += 23; } /* LD A, SET 1, (IX+d) */ void Z80::Opc_ddcb_cf() { env.wr8(IXd, set(1, env.rd8(IXd))); A = env.rd8(IXd); cycleCount += 23; } /* LD B, SET 2, (IX+d) */ void Z80::Opc_ddcb_d0() { env.wr8(IXd, set(2, env.rd8(IXd))); B = env.rd8(IXd); cycleCount += 23; } /* LD C, SET 2, (IX+d) */ void Z80::Opc_ddcb_d1() { env.wr8(IXd, set(2, env.rd8(IXd))); C = env.rd8(IXd); cycleCount += 23; } /* LD D, SET 2, (IX+d) */ void Z80::Opc_ddcb_d2() { env.wr8(IXd, set(2, env.rd8(IXd))); D = env.rd8(IXd); cycleCount += 23; } /* LD E, SET 2, (IX+d) */ void Z80::Opc_ddcb_d3() { env.wr8(IXd, set(2, env.rd8(IXd))); E = env.rd8(IXd); cycleCount += 23; } /* LD H, SET 2, (IX+d) */ void Z80::Opc_ddcb_d4() { env.wr8(IXd, set(2, env.rd8(IXd))); H = env.rd8(IXd); cycleCount += 23; } /* LD L, SET 2, (IX+d) */ void Z80::Opc_ddcb_d5() { env.wr8(IXd, set(2, env.rd8(IXd))); L = env.rd8(IXd); cycleCount += 23; } /* SET 2, (IX+d) */ void Z80::Opc_ddcb_d6() { env.wr8(IXd, set(2, env.rd8(IXd))); cycleCount += 23; } /* LD A, SET 2, (IX+d) */ void Z80::Opc_ddcb_d7() { env.wr8(IXd, set(2, env.rd8(IXd))); A = env.rd8(IXd); cycleCount += 23; } /* LD B, SET 3, (IX+d) */ void Z80::Opc_ddcb_d8() { env.wr8(IXd, set(3, env.rd8(IXd))); B = env.rd8(IXd); cycleCount += 23; } /* LD C, SET 3, (IX+d) */ void Z80::Opc_ddcb_d9() { env.wr8(IXd, set(3, env.rd8(IXd))); C = env.rd8(IXd); cycleCount += 23; } /* LD D, SET 3, (IX+d) */ void Z80::Opc_ddcb_da() { env.wr8(IXd, set(3, env.rd8(IXd))); D = env.rd8(IXd); cycleCount += 23; } /* LD E, SET 3, (IX+d) */ void Z80::Opc_ddcb_db() { env.wr8(IXd, set(3, env.rd8(IXd))); E = env.rd8(IXd); cycleCount += 23; } /* LD H, SET 3, (IX+d) */ void Z80::Opc_ddcb_dc() { env.wr8(IXd, set(3, env.rd8(IXd))); H = env.rd8(IXd); cycleCount += 23; } /* LD L, SET 3, (IX+d) */ void Z80::Opc_ddcb_dd() { env.wr8(IXd, set(3, env.rd8(IXd))); L = env.rd8(IXd); cycleCount += 23; } /* SET 3, (IX+d) */ void Z80::Opc_ddcb_de() { env.wr8(IXd, set(3, env.rd8(IXd))); cycleCount += 23; } /* LD A, SET 3, (IX+d) */ void Z80::Opc_ddcb_df() { env.wr8(IXd, set(3, env.rd8(IXd))); A = env.rd8(IXd); cycleCount += 23; } /* LD B, SET 4, (IX+d) */ void Z80::Opc_ddcb_e0() { env.wr8(IXd, set(4, env.rd8(IXd))); B = env.rd8(IXd); cycleCount += 23; } /* LD C, SET 4, (IX+d) */ void Z80::Opc_ddcb_e1() { env.wr8(IXd, set(4, env.rd8(IXd))); C = env.rd8(IXd); cycleCount += 23; } /* LD D, SET 4, (IX+d) */ void Z80::Opc_ddcb_e2() { env.wr8(IXd, set(4, env.rd8(IXd))); D = env.rd8(IXd); cycleCount += 23; } /* LD E, SET 4, (IX+d) */ void Z80::Opc_ddcb_e3() { env.wr8(IXd, set(4, env.rd8(IXd))); E = env.rd8(IXd); cycleCount += 23; } /* LD H, SET 4, (IX+d) */ void Z80::Opc_ddcb_e4() { env.wr8(IXd, set(4, env.rd8(IXd))); H = env.rd8(IXd); cycleCount += 23; } /* LD L, SET 4, (IX+d) */ void Z80::Opc_ddcb_e5() { env.wr8(IXd, set(4, env.rd8(IXd))); L = env.rd8(IXd); cycleCount += 23; } /* SET 4, (IX+d) */ void Z80::Opc_ddcb_e6() { env.wr8(IXd, set(4, env.rd8(IXd))); cycleCount += 23; } /* LD A, SET 4, (IX+d) */ void Z80::Opc_ddcb_e7() { env.wr8(IXd, set(4, env.rd8(IXd))); A = env.rd8(IXd); cycleCount += 23; } /* LD B, SET 5, (IX+d) */ void Z80::Opc_ddcb_e8() { env.wr8(IXd, set(5, env.rd8(IXd))); B = env.rd8(IXd); cycleCount += 23; } /* LD C, SET 5, (IX+d) */ void Z80::Opc_ddcb_e9() { env.wr8(IXd, set(5, env.rd8(IXd))); C = env.rd8(IXd); cycleCount += 23; } /* LD D, SET 5, (IX+d) */ void Z80::Opc_ddcb_ea() { env.wr8(IXd, set(5, env.rd8(IXd))); D = env.rd8(IXd); cycleCount += 23; } /* LD E, SET 5, (IX+d) */ void Z80::Opc_ddcb_eb() { env.wr8(IXd, set(5, env.rd8(IXd))); E = env.rd8(IXd); cycleCount += 23; } /* LD H, SET 5, (IX+d) */ void Z80::Opc_ddcb_ec() { env.wr8(IXd, set(5, env.rd8(IXd))); H = env.rd8(IXd); cycleCount += 23; } /* LD L, SET 5, (IX+d) */ void Z80::Opc_ddcb_ed() { env.wr8(IXd, set(5, env.rd8(IXd))); L = env.rd8(IXd); cycleCount += 23; } /* SET 5, (IX+d) */ void Z80::Opc_ddcb_ee() { env.wr8(IXd, set(5, env.rd8(IXd))); cycleCount += 23; } /* LD A, SET 5, (IX+d) */ void Z80::Opc_ddcb_ef() { env.wr8(IXd, set(5, env.rd8(IXd))); A = env.rd8(IXd); cycleCount += 23; } /* LD B, SET 6, (IX+d) */ void Z80::Opc_ddcb_f0() { env.wr8(IXd, set(6, env.rd8(IXd))); B = env.rd8(IXd); cycleCount += 23; } /* LD C, SET 6, (IX+d) */ void Z80::Opc_ddcb_f1() { env.wr8(IXd, set(6, env.rd8(IXd))); C = env.rd8(IXd); cycleCount += 23; } /* LD D, SET 6, (IX+d) */ void Z80::Opc_ddcb_f2() { env.wr8(IXd, set(6, env.rd8(IXd))); D = env.rd8(IXd); cycleCount += 23; } /* LD E, SET 6, (IX+d) */ void Z80::Opc_ddcb_f3() { env.wr8(IXd, set(6, env.rd8(IXd))); E = env.rd8(IXd); cycleCount += 23; } /* LD H, SET 6, (IX+d) */ void Z80::Opc_ddcb_f4() { env.wr8(IXd, set(6, env.rd8(IXd))); H = env.rd8(IXd); cycleCount += 23; } /* LD L, SET 6, (IX+d) */ void Z80::Opc_ddcb_f5() { env.wr8(IXd, set(6, env.rd8(IXd))); L = env.rd8(IXd); cycleCount += 23; } /* SET 6, (IX+d) */ void Z80::Opc_ddcb_f6() { env.wr8(IXd, set(6, env.rd8(IXd))); cycleCount += 23; } /* LD A, SET 6, (IX+d) */ void Z80::Opc_ddcb_f7() { env.wr8(IXd, set(6, env.rd8(IXd))); A = env.rd8(IXd); cycleCount += 23; } /* LD B, SET 7, (IX+d) */ void Z80::Opc_ddcb_f8() { env.wr8(IXd, set(7, env.rd8(IXd))); B = env.rd8(IXd); cycleCount += 23; } /* LD C, SET 7, (IX+d) */ void Z80::Opc_ddcb_f9() { env.wr8(IXd, set(7, env.rd8(IXd))); C = env.rd8(IXd); cycleCount += 23; } /* LD D, SET 7, (IX+d) */ void Z80::Opc_ddcb_fa() { env.wr8(IXd, set(7, env.rd8(IXd))); D = env.rd8(IXd); cycleCount += 23; } /* LD E, SET 7, (IX+d) */ void Z80::Opc_ddcb_fb() { env.wr8(IXd, set(7, env.rd8(IXd))); E = env.rd8(IXd); cycleCount += 23; } /* LD H, SET 7, (IX+d) */ void Z80::Opc_ddcb_fc() { env.wr8(IXd, set(7, env.rd8(IXd))); H = env.rd8(IXd); cycleCount += 23; } /* LD L, SET 7, (IX+d) */ void Z80::Opc_ddcb_fd() { env.wr8(IXd, set(7, env.rd8(IXd))); L = env.rd8(IXd); cycleCount += 23; } /* SET 7, (IX+d) */ void Z80::Opc_ddcb_fe() { env.wr8(IXd, set(7, env.rd8(IXd))); cycleCount += 23; } /* LD A, SET 7, (IX+d) */ void Z80::Opc_ddcb_ff() { env.wr8(IXd, set(7, env.rd8(IXd))); A = env.rd8(IXd); cycleCount += 23; } Z80::Opc_handler Z80::Opc_ddcb[256] = { &Z80::Opc_ddcb_00, &Z80::Opc_ddcb_01, &Z80::Opc_ddcb_02, &Z80::Opc_ddcb_03, &Z80::Opc_ddcb_04, &Z80::Opc_ddcb_05, &Z80::Opc_ddcb_06, &Z80::Opc_ddcb_07, &Z80::Opc_ddcb_08, &Z80::Opc_ddcb_09, &Z80::Opc_ddcb_0a, &Z80::Opc_ddcb_0b, &Z80::Opc_ddcb_0c, &Z80::Opc_ddcb_0d, &Z80::Opc_ddcb_0e, &Z80::Opc_ddcb_0f, &Z80::Opc_ddcb_10, &Z80::Opc_ddcb_11, &Z80::Opc_ddcb_12, &Z80::Opc_ddcb_13, &Z80::Opc_ddcb_14, &Z80::Opc_ddcb_15, &Z80::Opc_ddcb_16, &Z80::Opc_ddcb_17, &Z80::Opc_ddcb_18, &Z80::Opc_ddcb_19, &Z80::Opc_ddcb_1a, &Z80::Opc_ddcb_1b, &Z80::Opc_ddcb_1c, &Z80::Opc_ddcb_1d, &Z80::Opc_ddcb_1e, &Z80::Opc_ddcb_1f, &Z80::Opc_ddcb_20, &Z80::Opc_ddcb_21, &Z80::Opc_ddcb_22, &Z80::Opc_ddcb_23, &Z80::Opc_ddcb_24, &Z80::Opc_ddcb_25, &Z80::Opc_ddcb_26, &Z80::Opc_ddcb_27, &Z80::Opc_ddcb_28, &Z80::Opc_ddcb_29, &Z80::Opc_ddcb_2a, &Z80::Opc_ddcb_2b, &Z80::Opc_ddcb_2c, &Z80::Opc_ddcb_2d, &Z80::Opc_ddcb_2e, &Z80::Opc_ddcb_2f, &Z80::Opc_ddcb_30, &Z80::Opc_ddcb_31, &Z80::Opc_ddcb_32, &Z80::Opc_ddcb_33, &Z80::Opc_ddcb_34, &Z80::Opc_ddcb_35, &Z80::Opc_ddcb_36, &Z80::Opc_ddcb_37, &Z80::Opc_ddcb_38, &Z80::Opc_ddcb_39, &Z80::Opc_ddcb_3a, &Z80::Opc_ddcb_3b, &Z80::Opc_ddcb_3c, &Z80::Opc_ddcb_3d, &Z80::Opc_ddcb_3e, &Z80::Opc_ddcb_3f, &Z80::Opc_ddcb_40, &Z80::Opc_ddcb_41, &Z80::Opc_ddcb_42, &Z80::Opc_ddcb_43, &Z80::Opc_ddcb_44, &Z80::Opc_ddcb_45, &Z80::Opc_ddcb_46, &Z80::Opc_ddcb_47, &Z80::Opc_ddcb_48, &Z80::Opc_ddcb_49, &Z80::Opc_ddcb_4a, &Z80::Opc_ddcb_4b, &Z80::Opc_ddcb_4c, &Z80::Opc_ddcb_4d, &Z80::Opc_ddcb_4e, &Z80::Opc_ddcb_4f, &Z80::Opc_ddcb_50, &Z80::Opc_ddcb_51, &Z80::Opc_ddcb_52, &Z80::Opc_ddcb_53, &Z80::Opc_ddcb_54, &Z80::Opc_ddcb_55, &Z80::Opc_ddcb_56, &Z80::Opc_ddcb_57, &Z80::Opc_ddcb_58, &Z80::Opc_ddcb_59, &Z80::Opc_ddcb_5a, &Z80::Opc_ddcb_5b, &Z80::Opc_ddcb_5c, &Z80::Opc_ddcb_5d, &Z80::Opc_ddcb_5e, &Z80::Opc_ddcb_5f, &Z80::Opc_ddcb_60, &Z80::Opc_ddcb_61, &Z80::Opc_ddcb_62, &Z80::Opc_ddcb_63, &Z80::Opc_ddcb_64, &Z80::Opc_ddcb_65, &Z80::Opc_ddcb_66, &Z80::Opc_ddcb_67, &Z80::Opc_ddcb_68, &Z80::Opc_ddcb_69, &Z80::Opc_ddcb_6a, &Z80::Opc_ddcb_6b, &Z80::Opc_ddcb_6c, &Z80::Opc_ddcb_6d, &Z80::Opc_ddcb_6e, &Z80::Opc_ddcb_6f, &Z80::Opc_ddcb_70, &Z80::Opc_ddcb_71, &Z80::Opc_ddcb_72, &Z80::Opc_ddcb_73, &Z80::Opc_ddcb_74, &Z80::Opc_ddcb_75, &Z80::Opc_ddcb_76, &Z80::Opc_ddcb_77, &Z80::Opc_ddcb_78, &Z80::Opc_ddcb_79, &Z80::Opc_ddcb_7a, &Z80::Opc_ddcb_7b, &Z80::Opc_ddcb_7c, &Z80::Opc_ddcb_7d, &Z80::Opc_ddcb_7e, &Z80::Opc_ddcb_7f, &Z80::Opc_ddcb_80, &Z80::Opc_ddcb_81, &Z80::Opc_ddcb_82, &Z80::Opc_ddcb_83, &Z80::Opc_ddcb_84, &Z80::Opc_ddcb_85, &Z80::Opc_ddcb_86, &Z80::Opc_ddcb_87, &Z80::Opc_ddcb_88, &Z80::Opc_ddcb_89, &Z80::Opc_ddcb_8a, &Z80::Opc_ddcb_8b, &Z80::Opc_ddcb_8c, &Z80::Opc_ddcb_8d, &Z80::Opc_ddcb_8e, &Z80::Opc_ddcb_8f, &Z80::Opc_ddcb_90, &Z80::Opc_ddcb_91, &Z80::Opc_ddcb_92, &Z80::Opc_ddcb_93, &Z80::Opc_ddcb_94, &Z80::Opc_ddcb_95, &Z80::Opc_ddcb_96, &Z80::Opc_ddcb_97, &Z80::Opc_ddcb_98, &Z80::Opc_ddcb_99, &Z80::Opc_ddcb_9a, &Z80::Opc_ddcb_9b, &Z80::Opc_ddcb_9c, &Z80::Opc_ddcb_9d, &Z80::Opc_ddcb_9e, &Z80::Opc_ddcb_9f, &Z80::Opc_ddcb_a0, &Z80::Opc_ddcb_a1, &Z80::Opc_ddcb_a2, &Z80::Opc_ddcb_a3, &Z80::Opc_ddcb_a4, &Z80::Opc_ddcb_a5, &Z80::Opc_ddcb_a6, &Z80::Opc_ddcb_a7, &Z80::Opc_ddcb_a8, &Z80::Opc_ddcb_a9, &Z80::Opc_ddcb_aa, &Z80::Opc_ddcb_ab, &Z80::Opc_ddcb_ac, &Z80::Opc_ddcb_ad, &Z80::Opc_ddcb_ae, &Z80::Opc_ddcb_af, &Z80::Opc_ddcb_b0, &Z80::Opc_ddcb_b1, &Z80::Opc_ddcb_b2, &Z80::Opc_ddcb_b3, &Z80::Opc_ddcb_b4, &Z80::Opc_ddcb_b5, &Z80::Opc_ddcb_b6, &Z80::Opc_ddcb_b7, &Z80::Opc_ddcb_b8, &Z80::Opc_ddcb_b9, &Z80::Opc_ddcb_ba, &Z80::Opc_ddcb_bb, &Z80::Opc_ddcb_bc, &Z80::Opc_ddcb_bd, &Z80::Opc_ddcb_be, &Z80::Opc_ddcb_bf, &Z80::Opc_ddcb_c0, &Z80::Opc_ddcb_c1, &Z80::Opc_ddcb_c2, &Z80::Opc_ddcb_c3, &Z80::Opc_ddcb_c4, &Z80::Opc_ddcb_c5, &Z80::Opc_ddcb_c6, &Z80::Opc_ddcb_c7, &Z80::Opc_ddcb_c8, &Z80::Opc_ddcb_c9, &Z80::Opc_ddcb_ca, &Z80::Opc_ddcb_cb, &Z80::Opc_ddcb_cc, &Z80::Opc_ddcb_cd, &Z80::Opc_ddcb_ce, &Z80::Opc_ddcb_cf, &Z80::Opc_ddcb_d0, &Z80::Opc_ddcb_d1, &Z80::Opc_ddcb_d2, &Z80::Opc_ddcb_d3, &Z80::Opc_ddcb_d4, &Z80::Opc_ddcb_d5, &Z80::Opc_ddcb_d6, &Z80::Opc_ddcb_d7, &Z80::Opc_ddcb_d8, &Z80::Opc_ddcb_d9, &Z80::Opc_ddcb_da, &Z80::Opc_ddcb_db, &Z80::Opc_ddcb_dc, &Z80::Opc_ddcb_dd, &Z80::Opc_ddcb_de, &Z80::Opc_ddcb_df, &Z80::Opc_ddcb_e0, &Z80::Opc_ddcb_e1, &Z80::Opc_ddcb_e2, &Z80::Opc_ddcb_e3, &Z80::Opc_ddcb_e4, &Z80::Opc_ddcb_e5, &Z80::Opc_ddcb_e6, &Z80::Opc_ddcb_e7, &Z80::Opc_ddcb_e8, &Z80::Opc_ddcb_e9, &Z80::Opc_ddcb_ea, &Z80::Opc_ddcb_eb, &Z80::Opc_ddcb_ec, &Z80::Opc_ddcb_ed, &Z80::Opc_ddcb_ee, &Z80::Opc_ddcb_ef, &Z80::Opc_ddcb_f0, &Z80::Opc_ddcb_f1, &Z80::Opc_ddcb_f2, &Z80::Opc_ddcb_f3, &Z80::Opc_ddcb_f4, &Z80::Opc_ddcb_f5, &Z80::Opc_ddcb_f6, &Z80::Opc_ddcb_f7, &Z80::Opc_ddcb_f8, &Z80::Opc_ddcb_f9, &Z80::Opc_ddcb_fa, &Z80::Opc_ddcb_fb, &Z80::Opc_ddcb_fc, &Z80::Opc_ddcb_fd, &Z80::Opc_ddcb_fe, &Z80::Opc_ddcb_ff }; osmose-emulator-1.4/src/Opc_ed.cpp000066400000000000000000000500561341430144300172000ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "Z80.h" #include /* Opcodes prefixed with 0xED */ void Z80::exec_ed() { u8 instruction; R++; // Prefixed instruction increments R by one. instruction = env.rd8( PC++ ); (this->*(Opc_edxx[instruction]))(); #ifdef OPCODES_STATS ED_Prefix[ instruction ]++; #endif } /* IN B, (C) */ void Z80::Opc_edxx_40() { cycleCount += 12; B = env.in( C ); setFlagAfterInput( B ); } /* OUT (C), B */ void Z80::Opc_edxx_41() { cycleCount += 12; env.out( C, B ); } /* SBC HL, BC */ void Z80::Opc_edxx_42() { sbcHL(getBC()); } /* LD (nn), BC */ void Z80::Opc_edxx_43() { cycleCount += 20; setNNi16( getBC()); PC += 2; } /* NEG */ void Z80::Opc_edxx_44() { cycleCount += 8; u8 tmp1 = A; A = 0; A = sub8( A, tmp1 ); } /* RETN */ void Z80::Opc_edxx_45() { cycleCount += 14; PC = pop(); IFF1 = IFF2; if (IFF2) env.onInterruptsEnabled(); } /* IM 0 */ void Z80::Opc_edxx_46() { IM=0; cycleCount+=8; } /* LD I, A */ void Z80::Opc_edxx_47() { I = A; cycleCount+=9; } /* IN (C), C */ void Z80::Opc_edxx_48() { cycleCount += 12; C = env.in( C ); setFlagAfterInput( C ); } /* OUT (C), C */ void Z80::Opc_edxx_49() { cycleCount += 12; env.out( C, C ); } /* ADC HL, BC */ void Z80::Opc_edxx_4a() { adcHL(getBC()); } /* LD BC, (nn) */ void Z80::Opc_edxx_4b() { cycleCount += 20; setBC( getNNi16()); PC += 2; } /* NEG */ void Z80::Opc_edxx_4c() { Opc_edxx_44(); } /* RETI */ void Z80::Opc_edxx_4d() { cycleCount += 14; PC = pop(); env.onReturnFromInterrupt(); } /* IM 0 */ void Z80::Opc_edxx_4e() { IM=0; cycleCount+=8; } /* LD R, A */ void Z80::Opc_edxx_4f() { R = A; Rbit7 = (A & 0x80); // save R bit 7. cycleCount+=9; } /* IN D, (C) */ void Z80::Opc_edxx_50() { cycleCount += 12; D = env.in( C ); setFlagAfterInput( D ); } /* OUT (C), D */ void Z80::Opc_edxx_51() { cycleCount += 12; env.out( C, D ); } /* SBC HL, DE */ void Z80::Opc_edxx_52() { sbcHL(getDE()); } /* LD (nn), DE */ void Z80::Opc_edxx_53() { cycleCount += 20; setNNi16( getDE()); PC += 2; } /* NEG */ void Z80::Opc_edxx_54() { Opc_edxx_44(); } /* RETN */ void Z80::Opc_edxx_55() { Opc_edxx_45(); } /* IM 1 */ void Z80::Opc_edxx_56() { IM = 1; cycleCount+=8; } /* LD A, I */ void Z80::Opc_edxx_57() { cycleCount += 9; A = I; F = (F & (CF | HF | NF)) | PF_SF_ZF_[A]; F &= ~(HF | PF | NF); if (IFF2) F |= PF; // Copy IFF2 into Parity bit of F. } /* IN E, (C) */ void Z80::Opc_edxx_58() { cycleCount += 12; E = env.in( C ); setFlagAfterInput( E ); } /* OUT (C), E */ void Z80::Opc_edxx_59() { cycleCount += 12; env.out( C, E ); } /* ADC HL, DE */ void Z80::Opc_edxx_5a() { adcHL(getDE()); } /* LD DE, (nn) */ void Z80::Opc_edxx_5b() { cycleCount += 20; setDE( getNNi16()); PC += 2; } /* NEG */ void Z80::Opc_edxx_5c() { Opc_edxx_44(); } /* RETN */ void Z80::Opc_edxx_5d() { Opc_edxx_45(); } /* IM 2 */ void Z80::Opc_edxx_5e() { IM=2; cycleCount+=8; } /* LD A, R */ /* CPU increase R by one on each instruction. But bit7 of R is never */ /* changed by this. It can only by modified with LD R, A instruction.*/ /* That's why this bit is stored separatly in Rbit7 variable. */ void Z80::Opc_edxx_5f() { cycleCount += 9; A = ((R & 0x7F) | Rbit7); F = (F & (CF | HF | NF)) | PF_SF_ZF_[A]; F &= ~(HF | PF | NF); if ( IFF2 ) F |= PF; // Copy IFF2 into Parity bit of F. } /* IN H, (C) */ void Z80::Opc_edxx_60() { cycleCount += 12; H = env.in( C ); setFlagAfterInput( H ); } /* OUT (C), H */ void Z80::Opc_edxx_61() { cycleCount += 12; env.out( C, H ); } /* SBC HL, HL */ void Z80::Opc_edxx_62() { sbcHL(getHL()); } /* LD (nn), HL */ void Z80::Opc_edxx_63() { Opc_std_22(); cycleCount += 4; // prefixed instruction penality. } /* NEG */ void Z80::Opc_edxx_64() { Opc_edxx_44(); } /* RETN */ void Z80::Opc_edxx_65() { Opc_edxx_45(); } /* IM 0 */ void Z80::Opc_edxx_66() { IM=0; cycleCount+=8; } /* RRD */ void Z80::Opc_edxx_67() { rrd(); } /* IN L, (C) */ void Z80::Opc_edxx_68() { cycleCount += 12; L = env.in( C ); setFlagAfterInput( L ); } /* OUT (C), L */ void Z80::Opc_edxx_69() { cycleCount += 12; env.out( C, L ); } /* ADC HL, HL */ void Z80::Opc_edxx_6a() { adcHL(getHL()); } /* LD HL,(NN) */ void Z80::Opc_edxx_6b() { Opc_std_2a(); cycleCount += 4; // prefixed instruction penality. } /* NEG */ void Z80::Opc_edxx_6c() { Opc_edxx_44(); } /* RETN */ void Z80::Opc_edxx_6d() { Opc_edxx_45(); } /* IM 0 */ void Z80::Opc_edxx_6e() { IM=0; cycleCount+=8; } /* RLD */ void Z80::Opc_edxx_6f() { rld(); } /* 0xed70 IN(C) / IN F,(C) This undocumented instruction read port via C but does not store the result. Flag register is nevertheless updated */ void Z80::Opc_edxx_70() { cycleCount += 12; u8 dummy = env.in( C ); setFlagAfterInput( dummy ); } /* OUT C, 0 */ void Z80::Opc_edxx_71() { cycleCount += 12; env.out( C, 0 ); } /* SBC HL, SP */ void Z80::Opc_edxx_72() { sbcHL(SP); } /* LD (nn), SP */ void Z80::Opc_edxx_73() { cycleCount += 20; setNNi16( SP ); PC += 2; } /* NEG */ void Z80::Opc_edxx_74() { Opc_edxx_44(); } /* RETN */ void Z80::Opc_edxx_75() { Opc_edxx_45(); } /* IM 1 */ void Z80::Opc_edxx_76() { IM=1; cycleCount+=8; } /* IN A, (C) */ void Z80::Opc_edxx_78() { cycleCount += 12; A = env.in( C ); setFlagAfterInput( A ); } /* OUT (C), A */ void Z80::Opc_edxx_79() { cycleCount += 12; env.out( C, A ); } /* ADC HL, SP */ void Z80::Opc_edxx_7a() { adcHL(SP); } /* LD SP, (nn) */ void Z80::Opc_edxx_7b() { cycleCount += 20; SP = getNNi16(); PC += 2; } /* NEG */ void Z80::Opc_edxx_7c() { Opc_edxx_44(); } /* RETN */ void Z80::Opc_edxx_7d() { Opc_edxx_45(); } /* IM 2 */ void Z80::Opc_edxx_7e() { IM=2; cycleCount+=8; } /* LDI */ void Z80::Opc_edxx_a0() { cycleCount += 16; env.wr8( getDE(), env.rd8( getHL())); if ( ++L == 0 ) ++H; // HL++ if ( ++E == 0 ) ++D; // DE++ if ( C-- == 0 ) --B; // BC-- F &= ZF | SF | CF; if ( getBC() ) F |= PF; } /* CPI */ void Z80::Opc_edxx_a1() { u8 tmp_f = F; cycleCount += 16; cp8( A, env.rd8( getHL())); if ( ++L == 0 ) ++H; // inc HL if ( C-- == 0 ) --B; F = ( F &~( CF | PF )) | ( tmp_f &CF ); if ( getBC()) F |= PF; //Clear parity if BC = 0. } /* INI */ void Z80::Opc_edxx_a2() { cycleCount += 16; env.wr8( getHL(), env.in(C)); if ( ++L == 0 ) ++H; // HL++ B = dec8( B ); } /* OUTI */ void Z80::Opc_edxx_a3() { B = dec8( B ); env.out( C, env.rd8( getHL())); if ( ++L == 0 ) ++H; // HL++ cycleCount += 16; } /* LDD */ void Z80::Opc_edxx_a8() { cycleCount += 16; env.wr8( getDE(), env.rd8( getHL())); // (DE) = (HL), HL-- DE-- BC-- if ( L-- == 0 ) --H; if ( E-- == 0 ) --D; if ( C-- == 0 ) --B; F &= ~( HF | NF | PF ); if ( getBC()) F |= PF; } /* CPD */ void Z80::Opc_edxx_a9() { u8 tmp_f = F; cycleCount += 16; cp8( A, env.rd8( getHL())); if ( L-- == 0 ) --H; if ( C-- == 0 ) --B; F = ( F &~( CF | PF )) | ( tmp_f &CF ); if ( getBC()) F |= PF; //Clear parity if BC = 0. } /* IND */ void Z80::Opc_edxx_aa() { cycleCount += 16; env.wr8( getHL(), env.in(C)); if ( L-- == 0 ) --H; B = dec8( B ); } /* OUTD */ void Z80::Opc_edxx_ab() { B = dec8( B ); env.out( C, env.rd8( getHL())); if ( L-- == 0 ) --H; cycleCount += 16; } /* 0xedb0 LDIR This instruction works as a lot of single instructions. It's auto repeated by decrementing PC by two. Interrupt can occurs during execution. */ void Z80::Opc_edxx_b0() { Opc_edxx_a0(); // LDI if ( F & PF ) { cycleCount += 5; PC -= 2; } } /* 0xedb1 CPIR This instruction works as a lot of single instructions. It's auto repeated by decrementing PC by two. Interrupt can occurs during execution. */ void Z80::Opc_edxx_b1() { Opc_edxx_a1(); // CPI if (( F &PF ) && !( F &ZF )) // Parity is cleared when BC=0, Zero set when A=(HL) { cycleCount += 5; PC -= 2; // repeat instruction. } } /* INIR */ void Z80::Opc_edxx_b2() { Opc_edxx_a2(); // INI if ( B != 0 ) { cycleCount += 5; PC -= 2; } } /* OTIR */ void Z80::Opc_edxx_b3() { Opc_edxx_a3(); // OTI if ( B != 0 ) { cycleCount += 5; PC -= 2; } } /* LDDR */ void Z80::Opc_edxx_b8() { Opc_edxx_a8(); // LDD if ( F &PF ) // Parity is cleared when BC == 0 { cycleCount += 5; PC -= 2; } } /* CPDR*/ void Z80::Opc_edxx_b9() { Opc_edxx_a9(); // CPD if (( F &PF ) && !( F &ZF )) { PC -= 2; cycleCount += 5; } } /* INDR */ void Z80::Opc_edxx_ba() { Opc_edxx_aa(); // IND if ( B != 0 ) { cycleCount += 5; PC -= 2; } } /* OTDR */ void Z80::Opc_edxx_bb() { Opc_edxx_ab(); // OUTD if ( B != 0 ) { cycleCount += 5; PC -= 2; } } Z80::Opc_handler Z80::Opc_edxx[256] = { &Z80::invalid_prefixed_opcode, /* 0xed00 */ &Z80::invalid_prefixed_opcode, /* 0xed01 */ &Z80::invalid_prefixed_opcode, /* 0xed02 */ &Z80::invalid_prefixed_opcode, /* 0xed03 */ &Z80::invalid_prefixed_opcode, /* 0xed04 */ &Z80::invalid_prefixed_opcode, /* 0xed05 */ &Z80::invalid_prefixed_opcode, /* 0xed06 */ &Z80::invalid_prefixed_opcode, /* 0xed07 */ &Z80::invalid_prefixed_opcode, /* 0xed08 */ &Z80::invalid_prefixed_opcode, /* 0xed09 */ &Z80::invalid_prefixed_opcode, /* 0xed0a */ &Z80::invalid_prefixed_opcode, /* 0xed0b */ &Z80::invalid_prefixed_opcode, /* 0xed0c */ &Z80::invalid_prefixed_opcode, /* 0xed0d */ &Z80::invalid_prefixed_opcode, /* 0xed0e */ &Z80::invalid_prefixed_opcode, /* 0xed0f */ &Z80::invalid_prefixed_opcode, /* 0xed10 */ &Z80::invalid_prefixed_opcode, /* 0xed11 */ &Z80::invalid_prefixed_opcode, /* 0xed12 */ &Z80::invalid_prefixed_opcode, /* 0xed13 */ &Z80::invalid_prefixed_opcode, /* 0xed14 */ &Z80::invalid_prefixed_opcode, /* 0xed15 */ &Z80::invalid_prefixed_opcode, /* 0xed16 */ &Z80::invalid_prefixed_opcode, /* 0xed17 */ &Z80::invalid_prefixed_opcode, /* 0xed18 */ &Z80::invalid_prefixed_opcode, /* 0xed19 */ &Z80::invalid_prefixed_opcode, /* 0xed1a */ &Z80::invalid_prefixed_opcode, /* 0xed1b */ &Z80::invalid_prefixed_opcode, /* 0xed1c */ &Z80::invalid_prefixed_opcode, /* 0xed1d */ &Z80::invalid_prefixed_opcode, /* 0xed1e */ &Z80::invalid_prefixed_opcode, /* 0xed1f */ &Z80::invalid_prefixed_opcode, /* 0xed20 */ &Z80::invalid_prefixed_opcode, /* 0xed21 */ &Z80::invalid_prefixed_opcode, /* 0xed22 */ &Z80::invalid_prefixed_opcode, /* 0xed23 */ &Z80::invalid_prefixed_opcode, /* 0xed24 */ &Z80::invalid_prefixed_opcode, /* 0xed25 */ &Z80::invalid_prefixed_opcode, /* 0xed26 */ &Z80::invalid_prefixed_opcode, /* 0xed27 */ &Z80::invalid_prefixed_opcode, /* 0xed28 */ &Z80::invalid_prefixed_opcode, /* 0xed29 */ &Z80::invalid_prefixed_opcode, /* 0xed2a */ &Z80::invalid_prefixed_opcode, /* 0xed2b */ &Z80::invalid_prefixed_opcode, /* 0xed2c */ &Z80::invalid_prefixed_opcode, /* 0xed2d */ &Z80::invalid_prefixed_opcode, /* 0xed2e */ &Z80::invalid_prefixed_opcode, /* 0xed2f */ &Z80::invalid_prefixed_opcode, /* 0xed30 */ &Z80::invalid_prefixed_opcode, /* 0xed31 */ &Z80::invalid_prefixed_opcode, /* 0xed32 */ &Z80::invalid_prefixed_opcode, /* 0xed33 */ &Z80::invalid_prefixed_opcode, /* 0xed34 */ &Z80::invalid_prefixed_opcode, /* 0xed35 */ &Z80::invalid_prefixed_opcode, /* 0xed36 */ &Z80::invalid_prefixed_opcode, /* 0xed37 */ &Z80::invalid_prefixed_opcode, /* 0xed38 */ &Z80::invalid_prefixed_opcode, /* 0xed39 */ &Z80::invalid_prefixed_opcode, /* 0xed3a */ &Z80::invalid_prefixed_opcode, /* 0xed3b */ &Z80::invalid_prefixed_opcode, /* 0xed3c */ &Z80::invalid_prefixed_opcode, /* 0xed3d */ &Z80::invalid_prefixed_opcode, /* 0xed3e */ &Z80::invalid_prefixed_opcode, /* 0xed3f */ &Z80::Opc_edxx_40, &Z80::Opc_edxx_41, &Z80::Opc_edxx_42, &Z80::Opc_edxx_43, &Z80::Opc_edxx_44, &Z80::Opc_edxx_45, &Z80::Opc_edxx_46, &Z80::Opc_edxx_47, &Z80::Opc_edxx_48, &Z80::Opc_edxx_49, &Z80::Opc_edxx_4a, &Z80::Opc_edxx_4b, &Z80::Opc_edxx_4c, &Z80::Opc_edxx_4d, &Z80::Opc_edxx_4e, &Z80::Opc_edxx_4f, &Z80::Opc_edxx_50, &Z80::Opc_edxx_51, &Z80::Opc_edxx_52, &Z80::Opc_edxx_53, &Z80::Opc_edxx_54, &Z80::Opc_edxx_55, &Z80::Opc_edxx_56, &Z80::Opc_edxx_57, &Z80::Opc_edxx_58, &Z80::Opc_edxx_59, &Z80::Opc_edxx_5a, &Z80::Opc_edxx_5b, &Z80::Opc_edxx_5c, &Z80::Opc_edxx_5d, &Z80::Opc_edxx_5e, &Z80::Opc_edxx_5f, &Z80::Opc_edxx_60, &Z80::Opc_edxx_61, &Z80::Opc_edxx_62, &Z80::Opc_edxx_63, &Z80::Opc_edxx_64, &Z80::Opc_edxx_65, &Z80::Opc_edxx_66, &Z80::Opc_edxx_67, &Z80::Opc_edxx_68, &Z80::Opc_edxx_69, &Z80::Opc_edxx_6a, &Z80::Opc_edxx_6b, &Z80::Opc_edxx_6c, &Z80::Opc_edxx_6d, &Z80::Opc_edxx_6e, &Z80::Opc_edxx_6f, &Z80::Opc_edxx_70, &Z80::Opc_edxx_71, &Z80::Opc_edxx_72, &Z80::Opc_edxx_73, &Z80::Opc_edxx_74, &Z80::Opc_edxx_75, &Z80::Opc_edxx_76, &Z80::invalid_prefixed_opcode, /* 0xed77 */ &Z80::Opc_edxx_78, &Z80::Opc_edxx_79, &Z80::Opc_edxx_7a, &Z80::Opc_edxx_7b, &Z80::Opc_edxx_7c, &Z80::Opc_edxx_7d, &Z80::Opc_edxx_7e, &Z80::invalid_prefixed_opcode, /* 0xed7f */ &Z80::invalid_prefixed_opcode, /* 0xed80 */ &Z80::invalid_prefixed_opcode, /* 0xed81 */ &Z80::invalid_prefixed_opcode, /* 0xed82 */ &Z80::invalid_prefixed_opcode, /* 0xed83 */ &Z80::invalid_prefixed_opcode, /* 0xed84 */ &Z80::invalid_prefixed_opcode, /* 0xed85 */ &Z80::invalid_prefixed_opcode, /* 0xed86 */ &Z80::invalid_prefixed_opcode, /* 0xed87 */ &Z80::invalid_prefixed_opcode, /* 0xed88 */ &Z80::invalid_prefixed_opcode, /* 0xed89 */ &Z80::invalid_prefixed_opcode, /* 0xed8a */ &Z80::invalid_prefixed_opcode, /* 0xed8b */ &Z80::invalid_prefixed_opcode, /* 0xed8c */ &Z80::invalid_prefixed_opcode, /* 0xed8d */ &Z80::invalid_prefixed_opcode, /* 0xed8e */ &Z80::invalid_prefixed_opcode, /* 0xed8f */ &Z80::invalid_prefixed_opcode, /* 0xed90 */ &Z80::invalid_prefixed_opcode, /* 0xed91 */ &Z80::invalid_prefixed_opcode, /* 0xed92 */ &Z80::invalid_prefixed_opcode, /* 0xed93 */ &Z80::invalid_prefixed_opcode, /* 0xed94 */ &Z80::invalid_prefixed_opcode, /* 0xed95 */ &Z80::invalid_prefixed_opcode, /* 0xed96 */ &Z80::invalid_prefixed_opcode, /* 0xed97 */ &Z80::invalid_prefixed_opcode, /* 0xed98 */ &Z80::invalid_prefixed_opcode, /* 0xed99 */ &Z80::invalid_prefixed_opcode, /* 0xed9a */ &Z80::invalid_prefixed_opcode, /* 0xed9b */ &Z80::invalid_prefixed_opcode, /* 0xed9c */ &Z80::invalid_prefixed_opcode, /* 0xed9d */ &Z80::invalid_prefixed_opcode, /* 0xed9e */ &Z80::invalid_prefixed_opcode, /* 0xed9f */ &Z80::Opc_edxx_a0, &Z80::Opc_edxx_a1, &Z80::Opc_edxx_a2, &Z80::Opc_edxx_a3, &Z80::invalid_prefixed_opcode, /* 0xeda4 */ &Z80::invalid_prefixed_opcode, /* 0xeda5 */ &Z80::invalid_prefixed_opcode, /* 0xeda6 */ &Z80::invalid_prefixed_opcode, /* 0xeda7 */ &Z80::Opc_edxx_a8, &Z80::Opc_edxx_a9, &Z80::Opc_edxx_aa, &Z80::Opc_edxx_ab, &Z80::invalid_prefixed_opcode, /* 0xedac */ &Z80::invalid_prefixed_opcode, /* 0xedad */ &Z80::invalid_prefixed_opcode, /* 0xedae */ &Z80::invalid_prefixed_opcode, /* 0xedaf */ &Z80::Opc_edxx_b0, &Z80::Opc_edxx_b1, &Z80::Opc_edxx_b2, &Z80::Opc_edxx_b3, &Z80::invalid_prefixed_opcode, /* 0xedb4 */ &Z80::invalid_prefixed_opcode, /* 0xedb5 */ &Z80::invalid_prefixed_opcode, /* 0xedb6 */ &Z80::invalid_prefixed_opcode, /* 0xedb7 */ &Z80::Opc_edxx_b8, &Z80::Opc_edxx_b9, &Z80::Opc_edxx_ba, &Z80::Opc_edxx_bb, &Z80::invalid_prefixed_opcode, /* 0xedbc */ &Z80::invalid_prefixed_opcode, /* 0xedbd */ &Z80::invalid_prefixed_opcode, /* 0xedbe */ &Z80::invalid_prefixed_opcode, /* 0xedbf */ &Z80::invalid_prefixed_opcode, /* 0xedc0 */ &Z80::invalid_prefixed_opcode, /* 0xedc1 */ &Z80::invalid_prefixed_opcode, /* 0xedc2 */ &Z80::invalid_prefixed_opcode, /* 0xedc3 */ &Z80::invalid_prefixed_opcode, /* 0xedc4 */ &Z80::invalid_prefixed_opcode, /* 0xedc5 */ &Z80::invalid_prefixed_opcode, /* 0xedc6 */ &Z80::invalid_prefixed_opcode, /* 0xedc7 */ &Z80::invalid_prefixed_opcode, /* 0xedc8 */ &Z80::invalid_prefixed_opcode, /* 0xedc9 */ &Z80::invalid_prefixed_opcode, /* 0xedca */ &Z80::invalid_prefixed_opcode, /* 0xedcb */ &Z80::invalid_prefixed_opcode, /* 0xedcc */ &Z80::invalid_prefixed_opcode, /* 0xedcd */ &Z80::invalid_prefixed_opcode, /* 0xedce */ &Z80::invalid_prefixed_opcode, /* 0xedcf */ &Z80::invalid_prefixed_opcode, /* 0xedd0 */ &Z80::invalid_prefixed_opcode, /* 0xedd1 */ &Z80::invalid_prefixed_opcode, /* 0xedd2 */ &Z80::invalid_prefixed_opcode, /* 0xedd3 */ &Z80::invalid_prefixed_opcode, /* 0xedd4 */ &Z80::invalid_prefixed_opcode, /* 0xedd5 */ &Z80::invalid_prefixed_opcode, /* 0xedd6 */ &Z80::invalid_prefixed_opcode, /* 0xedd7 */ &Z80::invalid_prefixed_opcode, /* 0xedd8 */ &Z80::invalid_prefixed_opcode, /* 0xedd9 */ &Z80::invalid_prefixed_opcode, /* 0xedda */ &Z80::invalid_prefixed_opcode, /* 0xeddb */ &Z80::invalid_prefixed_opcode, /* 0xeddc */ &Z80::invalid_prefixed_opcode, /* 0xeddd */ &Z80::invalid_prefixed_opcode, /* 0xedde */ &Z80::invalid_prefixed_opcode, /* 0xeddf */ &Z80::invalid_prefixed_opcode, /* 0xede0 */ &Z80::invalid_prefixed_opcode, /* 0xede1 */ &Z80::invalid_prefixed_opcode, /* 0xede2 */ &Z80::invalid_prefixed_opcode, /* 0xede3 */ &Z80::invalid_prefixed_opcode, /* 0xede4 */ &Z80::invalid_prefixed_opcode, /* 0xede5 */ &Z80::invalid_prefixed_opcode, /* 0xede6 */ &Z80::invalid_prefixed_opcode, /* 0xede7 */ &Z80::invalid_prefixed_opcode, /* 0xede8 */ &Z80::invalid_prefixed_opcode, /* 0xede9 */ &Z80::invalid_prefixed_opcode, /* 0xedea */ &Z80::invalid_prefixed_opcode, /* 0xedeb */ &Z80::invalid_prefixed_opcode, /* 0xedec */ &Z80::invalid_prefixed_opcode, /* 0xeded */ &Z80::invalid_prefixed_opcode, /* 0xedee */ &Z80::invalid_prefixed_opcode, /* 0xedef */ &Z80::invalid_prefixed_opcode, /* 0xedf0 */ &Z80::invalid_prefixed_opcode, /* 0xedf1 */ &Z80::invalid_prefixed_opcode, /* 0xedf2 */ &Z80::invalid_prefixed_opcode, /* 0xedf3 */ &Z80::invalid_prefixed_opcode, /* 0xedf4 */ &Z80::invalid_prefixed_opcode, /* 0xedf5 */ &Z80::invalid_prefixed_opcode, /* 0xedf6 */ &Z80::invalid_prefixed_opcode, /* 0xedf7 */ &Z80::invalid_prefixed_opcode, /* 0xedf8 */ &Z80::invalid_prefixed_opcode, /* 0xedf9 */ &Z80::invalid_prefixed_opcode, /* 0xedfa */ &Z80::invalid_prefixed_opcode, /* 0xedfb */ &Z80::invalid_prefixed_opcode, /* 0xedfc */ &Z80::invalid_prefixed_opcode, /* 0xedfd */ &Z80::invalid_prefixed_opcode, /* 0xedfe */ &Z80::invalid_prefixed_opcode /* 0xedff */ }; osmose-emulator-1.4/src/Opc_fd.cpp000066400000000000000000000433161341430144300172020ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "Z80.h" /* Opcodes prefixed with 0xFD */ void Z80::exec_fd() { u8 instruction; R++; // Prefixed instruction increments R by one. instruction = env.rd8( PC++ ); (this->*(Opc_fdxx[instruction]))(); #ifdef OPCODES_STATS FD_Prefix[ instruction ]++; #endif } /* ADD IY, BC */ void Z80::Opc_fdxx_09() { IY = add16(IY, getBC()); cycleCount += 15; } /* ADD IY, DE */ void Z80::Opc_fdxx_19() { IY = add16(IY, getDE()); cycleCount += 15; } /* LD IY, (nn) */ void Z80::Opc_fdxx_21() { IY = env.rd16(PC); PC+=2; cycleCount += 14; } /* LD (NN),IY */ void Z80::Opc_fdxx_22() { setNNi16(IY); PC+=2; cycleCount += 20; } /* INC IY */ void Z80::Opc_fdxx_23() { IY++; cycleCount += 10; } /* INC IYH */ void Z80::Opc_fdxx_24() { IY = (IY & 0xFF) | (inc8(IY >> 8) << 8); cycleCount += 9; } /* DEC IYH */ void Z80::Opc_fdxx_25() { IY = (IY & 0xFF) | (dec8(IY >> 8) << 8); cycleCount += 9; } /* LD IYH, n */ void Z80::Opc_fdxx_26() { IY = ((IY & 0xFF) | env.rd8(PC++) << 8); cycleCount += 9; } /* ADD IY, IY */ void Z80::Opc_fdxx_29() { IY = add16(IY, IY); cycleCount += 15; } /* LD IY,(nn) */ void Z80::Opc_fdxx_2a() { IY = getNNi16(); PC += 2; cycleCount += 20; } /* DEC IY */ void Z80::Opc_fdxx_2b() { IY--; cycleCount += 10; } /* INC IYL */ void Z80::Opc_fdxx_2c() { IY = (IY & 0xFF00) | (inc8(IY & 0xFF)); cycleCount += 9; } /* DEC IYL */ void Z80::Opc_fdxx_2d() { IY = (IY & 0xFF00) | (dec8(IY & 0xFF)); cycleCount += 9; } /* LD IYL, n */ void Z80::Opc_fdxx_2e() { IY = (IY & 0xFF00) | env.rd8(PC++); cycleCount += 9; } /* INC (IY+d) */ void Z80::Opc_fdxx_34() { setIYdi(inc8(getIYdi())); PC++; cycleCount += 23; } /* DEC (IY+d) */ void Z80::Opc_fdxx_35() { setIYdi(dec8(getIYdi())); PC++; cycleCount += 23; } /* LD (IY+d), n */ void Z80::Opc_fdxx_36() { setIYdi(env.rd8(PC+1)); PC += 2; cycleCount += 19; } /* ADD IY, SP */ void Z80::Opc_fdxx_39() { IY = add16(IY, SP); cycleCount += 15; } /* LD B, IYH */ void Z80::Opc_fdxx_44() { B = (IY >> 8); cycleCount += 9; } /* LD B, IYL */ void Z80::Opc_fdxx_45() { B = (IY & 0xFF); cycleCount += 9; } /* LD B, (IY+d) */ void Z80::Opc_fdxx_46() { B = getIYdi(); PC++; cycleCount += 19; } /* LD C, IYH */ void Z80::Opc_fdxx_4c() { C = (IY >> 8); cycleCount += 9; } /* LD C, IYL */ void Z80::Opc_fdxx_4d() { C = (IY & 0xFF); cycleCount += 9; } /* LD C, (IY+d) */ void Z80::Opc_fdxx_4e() { C = getIYdi(); PC++; cycleCount += 19; } /* LD D, IYH */ void Z80::Opc_fdxx_54() { D = (IY >> 8); cycleCount += 9; } /* LD D, IYL */ void Z80::Opc_fdxx_55() { D = (IY & 0xFF); cycleCount += 9; } /* LD D, (IY+d) */ void Z80::Opc_fdxx_56() { D = getIYdi(); PC++; cycleCount += 19; } /* LD E, IYH */ void Z80::Opc_fdxx_5c() { E = (IY >> 8); cycleCount += 9; } /* LD E, IYL */ void Z80::Opc_fdxx_5d() { E = (IY & 0xFF); cycleCount += 9; } /* LD E, (IY+d) */ void Z80::Opc_fdxx_5e() { E = getIYdi(); PC++; cycleCount += 19; } /* LD IYH, B */ void Z80::Opc_fdxx_60() { IY = ( IY & 0xFF ) | (( u16 )B << 8 ); cycleCount += 9; } /* LD IYH, C */ void Z80::Opc_fdxx_61() { IY = ( IY & 0xFF ) | (( u16 )C << 8 ); cycleCount += 9; } /* LD IYH, D */ void Z80::Opc_fdxx_62() { IY = ( IY & 0xFF ) | (( u16 )D << 8 ); cycleCount += 9; } /* LD IYH, E */ void Z80::Opc_fdxx_63() { IY = ( IY & 0xFF ) | (( u16 )E << 8 ); cycleCount += 9; } /* LD IYH, IYH */ void Z80::Opc_fdxx_64() { IY = IY; // Do nothing; cycleCount += 9; } /* LD IYH, IYL */ void Z80::Opc_fdxx_65() { IY = ( IY & 0xFF ) | (( IY & 0xFF ) << 8 ); cycleCount += 9; } /* LD H, (IY+d) */ void Z80::Opc_fdxx_66() { H = getIYdi(); PC++; cycleCount += 19; } /* LD IYH, A */ void Z80::Opc_fdxx_67() { IY = ( IY & 0xFF ) | (( u16 )A << 8 ); cycleCount += 9; } /* LD IYL, B */ void Z80::Opc_fdxx_68() { IY = ( IY & 0xFF00 ) | B; cycleCount += 9; } /* LD IYL, C */ void Z80::Opc_fdxx_69() { IY = ( IY & 0xFF00 ) | C; cycleCount += 9; } /* LD IYL, D */ void Z80::Opc_fdxx_6a() { IY = ( IY & 0xFF00 ) | D; cycleCount += 9; } /* LD IYL, E */ void Z80::Opc_fdxx_6b() { IY = ( IY & 0xFF00 ) | E; cycleCount += 9; } /* LD IYL, IYH */ void Z80::Opc_fdxx_6c() { IY = ( IY & 0xFF00 ) | ( IY >> 8 ); cycleCount += 9; } /* LD IYL, IYL */ void Z80::Opc_fdxx_6d() { IY = IY; // Do nothing; cycleCount += 9; } /* LD L, (IY+d) */ void Z80::Opc_fdxx_6e() { L = getIYdi(); PC++; cycleCount += 19; } /* LD IYL, A */ void Z80::Opc_fdxx_6f() { IY = ( IY & 0xFF00 ) | A; cycleCount += 9; } /* LD (IY+d), B */ void Z80::Opc_fdxx_70() { setIYdi(B); PC++; cycleCount += 19; } /* LD (IY+d), C */ void Z80::Opc_fdxx_71() { setIYdi(C); PC++; cycleCount += 19; } /* LD (IY+d), D */ void Z80::Opc_fdxx_72() { setIYdi(D); PC++; cycleCount += 19; } /* LD (IY+d), E */ void Z80::Opc_fdxx_73() { setIYdi(E); PC++; cycleCount += 19; } /* LD (IY+d), H */ void Z80::Opc_fdxx_74() { setIYdi(H); PC++; cycleCount += 19; } /* LD (IY+d), L */ void Z80::Opc_fdxx_75() { setIYdi(L); PC++; cycleCount += 19; } /* LD (IY+d), A */ void Z80::Opc_fdxx_77() { setIYdi(A); PC++; cycleCount += 19; } /* LD A, IYH */ void Z80::Opc_fdxx_7c() { A = (IY >> 8); cycleCount += 9; } /* LD A, IYL */ void Z80::Opc_fdxx_7d() { A = (IY & 0xFF); cycleCount += 9; } /* LD A, (IY+d) */ void Z80::Opc_fdxx_7e() { A = getIYdi(); PC++; cycleCount += 19; } /* ADD A, IYH */ void Z80::Opc_fdxx_84() { A = add8(A, IY >> 8); cycleCount += 9; } /* ADD A, IYL */ void Z80::Opc_fdxx_85() { A = add8(A, IY & 0xFF); cycleCount += 9; } /* ADD A, (IY+d) */ void Z80::Opc_fdxx_86() { A = add8(A, getIYdi()); PC++; cycleCount += 19; } /* ADC A, IYH */ void Z80::Opc_fdxx_8c() { A = adc8(A, IY >> 8); cycleCount += 9; } /* ADC A, IYL */ void Z80::Opc_fdxx_8d() { A = adc8(A, IY & 0xFF); cycleCount += 9; } /* ADC A, (IY+d) */ void Z80::Opc_fdxx_8e() { A = adc8(A, getIYdi()); PC++; cycleCount += 19; } /* SUB A, IYH */ void Z80::Opc_fdxx_94() { A = sub8(A, IY >> 8); cycleCount += 9; } /* SUB A, IYL */ void Z80::Opc_fdxx_95() { A = sub8(A, IY & 0xFF); cycleCount += 9; } /* SUB A, (IY+d) */ void Z80::Opc_fdxx_96() { A = sub8(A, getIYdi()); PC++; cycleCount += 19; } /* SBC A, IYH */ void Z80::Opc_fdxx_9c() { A = sbc8(A, IY >> 8); cycleCount += 9; } /* SBC A, IYL */ void Z80::Opc_fdxx_9d() { A = sbc8(A, IY & 0xFF); cycleCount += 9; } /* SBC A, (IY+d) */ void Z80::Opc_fdxx_9e() { A = sbc8(A, getIYdi()); PC++; cycleCount += 19; } /* AND A, IYH */ void Z80::Opc_fdxx_a4() { A = and8(A, IY >> 8); cycleCount += 9; } /* AND A, IYL */ void Z80::Opc_fdxx_a5() { A = and8(A, IY & 0xFF); cycleCount += 9; } /* AND A, (IY+d) */ void Z80::Opc_fdxx_a6() { A = and8(A, getIYdi()); PC++; cycleCount += 19; } /* XOR A, IYH */ void Z80::Opc_fdxx_ac() { A = xor8(A, IY >> 8); cycleCount += 9; } /* XOR A, IYL */ void Z80::Opc_fdxx_ad() { A = xor8(A, IY & 0xFF); cycleCount += 9; } /* XOR A, (IY+d) */ void Z80::Opc_fdxx_ae() { A = xor8(A, getIYdi()); PC++; cycleCount += 19; } /* OR A, IYH */ void Z80::Opc_fdxx_b4() { A = or8(A, IY >> 8); cycleCount += 9; } /* OR A, IYL */ void Z80::Opc_fdxx_b5() { A = or8(A, IY & 0xFF); cycleCount += 9; } /* OR A, (IY+d) */ void Z80::Opc_fdxx_b6() { A = or8(A, getIYdi()); PC++; cycleCount += 19; } /* CP A, IYH */ void Z80::Opc_fdxx_bc() { cp8(A, IY >> 8); cycleCount += 9; } /* CP A, IYL */ void Z80::Opc_fdxx_bd() { cp8(A, IY & 0xFF); cycleCount += 9; } /* CP A, (IY+d) */ void Z80::Opc_fdxx_be() { cp8(A, getIYdi()); PC++; cycleCount += 19; } /* POP IY */ void Z80::Opc_fdxx_e1() { IY = pop(); cycleCount += 14; } /* EX (SP), IY */ void Z80::Opc_fdxx_e3() { u16 tmp1 = env.rd16( SP ); env.wr16( SP, IY ); IY = tmp1; cycleCount += 23; } /* PUSH IY */ void Z80::Opc_fdxx_e5() { push(IY); cycleCount += 15; } /* JP IY or LD PC, IY */ void Z80::Opc_fdxx_e9() { PC = IY; cycleCount += 8; } /* LD SP, IY */ void Z80::Opc_fdxx_f9() { SP = IY; cycleCount += 10; } Z80::Opc_handler Z80::Opc_fdxx[256] = { &Z80::invalid_opcode, /* 0xfd00 */ &Z80::invalid_opcode, /* 0xfd01 */ &Z80::invalid_opcode, /* 0xfd02 */ &Z80::invalid_opcode, /* 0xfd03 */ &Z80::invalid_opcode, /* 0xfd04 */ &Z80::invalid_opcode, /* 0xfd05 */ &Z80::invalid_opcode, /* 0xfd06 */ &Z80::invalid_opcode, /* 0xfd07 */ &Z80::invalid_opcode, /* 0xfd08 */ &Z80::Opc_fdxx_09, &Z80::invalid_opcode, /* 0xfd0a */ &Z80::invalid_opcode, /* 0xfd0b */ &Z80::invalid_opcode, /* 0xfd0c */ &Z80::invalid_opcode, /* 0xfd0d */ &Z80::invalid_opcode, /* 0xfd0e */ &Z80::invalid_opcode, /* 0xfd0f */ &Z80::invalid_opcode, /* 0xfd10 */ &Z80::invalid_opcode, /* 0xfd11 */ &Z80::invalid_opcode, /* 0xfd12 */ &Z80::invalid_opcode, /* 0xfd13 */ &Z80::invalid_opcode, /* 0xfd14 */ &Z80::invalid_opcode, /* 0xfd15 */ &Z80::invalid_opcode, /* 0xfd16 */ &Z80::invalid_opcode, /* 0xfd17 */ &Z80::invalid_opcode, /* 0xfd18 */ &Z80::Opc_fdxx_19, &Z80::invalid_opcode, /* 0xfd1a */ &Z80::invalid_opcode, /* 0xfd1b */ &Z80::invalid_opcode, /* 0xfd1c */ &Z80::invalid_opcode, /* 0xfd1d */ &Z80::invalid_opcode, /* 0xfd1e */ &Z80::invalid_opcode, /* 0xfd1f */ &Z80::invalid_opcode, /* 0xfd20 */ &Z80::Opc_fdxx_21, &Z80::Opc_fdxx_22, &Z80::Opc_fdxx_23, &Z80::Opc_fdxx_24, &Z80::Opc_fdxx_25, &Z80::Opc_fdxx_26, &Z80::invalid_opcode, /* 0xfd27 */ &Z80::invalid_opcode, /* 0xfd28 */ &Z80::Opc_fdxx_29, &Z80::Opc_fdxx_2a, &Z80::Opc_fdxx_2b, &Z80::Opc_fdxx_2c, &Z80::Opc_fdxx_2d, &Z80::Opc_fdxx_2e, &Z80::invalid_opcode, /* 0xfd2f */ &Z80::invalid_opcode, /* 0xfd30 */ &Z80::invalid_opcode, /* 0xfd31 */ &Z80::invalid_opcode, /* 0xfd32 */ &Z80::invalid_opcode, /* 0xfd33 */ &Z80::Opc_fdxx_34, &Z80::Opc_fdxx_35, &Z80::Opc_fdxx_36, &Z80::invalid_opcode, /* 0xfd37 */ &Z80::invalid_opcode, /* 0xfd38 */ &Z80::Opc_fdxx_39, &Z80::invalid_opcode, /* 0xfd3a */ &Z80::invalid_opcode, /* 0xfd3b */ &Z80::invalid_opcode, /* 0xfd3c */ &Z80::invalid_opcode, /* 0xfd3d */ &Z80::invalid_opcode, /* 0xfd3e */ &Z80::invalid_opcode, /* 0xfd3f */ &Z80::invalid_opcode, /* 0xfd40 */ &Z80::invalid_opcode, /* 0xfd41 */ &Z80::invalid_opcode, /* 0xfd42 */ &Z80::invalid_opcode, /* 0xfd43 */ &Z80::Opc_fdxx_44, &Z80::Opc_fdxx_45, &Z80::Opc_fdxx_46, &Z80::invalid_opcode, /* 0xfd47 */ &Z80::invalid_opcode, /* 0xfd48 */ &Z80::invalid_opcode, /* 0xfd49 */ &Z80::invalid_opcode, /* 0xfd4a */ &Z80::invalid_opcode, /* 0xfd4b */ &Z80::Opc_fdxx_4c, &Z80::Opc_fdxx_4d, &Z80::Opc_fdxx_4e, &Z80::invalid_opcode, /* 0xfd4f */ &Z80::invalid_opcode, /* 0xfd50 */ &Z80::invalid_opcode, /* 0xfd51 */ &Z80::invalid_opcode, /* 0xfd52 */ &Z80::invalid_opcode, /* 0xfd53 */ &Z80::Opc_fdxx_54, &Z80::Opc_fdxx_55, &Z80::Opc_fdxx_56, &Z80::invalid_opcode, /* 0xfd57 */ &Z80::invalid_opcode, /* 0xfd58 */ &Z80::invalid_opcode, /* 0xfd59 */ &Z80::invalid_opcode, /* 0xfd5a */ &Z80::invalid_opcode, /* 0xfd5b */ &Z80::Opc_fdxx_5c, &Z80::Opc_fdxx_5d, &Z80::Opc_fdxx_5e, &Z80::invalid_opcode, /* 0xfd5f */ &Z80::Opc_fdxx_60, &Z80::Opc_fdxx_61, &Z80::Opc_fdxx_62, &Z80::Opc_fdxx_63, &Z80::Opc_fdxx_64, &Z80::Opc_fdxx_65, &Z80::Opc_fdxx_66, &Z80::Opc_fdxx_67, &Z80::Opc_fdxx_68, &Z80::Opc_fdxx_69, &Z80::Opc_fdxx_6a, &Z80::Opc_fdxx_6b, &Z80::Opc_fdxx_6c, &Z80::Opc_fdxx_6d, &Z80::Opc_fdxx_6e, &Z80::Opc_fdxx_6f, &Z80::Opc_fdxx_70, &Z80::Opc_fdxx_71, &Z80::Opc_fdxx_72, &Z80::Opc_fdxx_73, &Z80::Opc_fdxx_74, &Z80::Opc_fdxx_75, &Z80::invalid_opcode, /* 0xfd76 */ &Z80::Opc_fdxx_77, &Z80::invalid_opcode, /* 0xfd78 */ &Z80::invalid_opcode, /* 0xfd79 */ &Z80::invalid_opcode, /* 0xfd7a */ &Z80::invalid_opcode, /* 0xfd7b */ &Z80::Opc_fdxx_7c, &Z80::Opc_fdxx_7d, &Z80::Opc_fdxx_7e, &Z80::invalid_opcode, /* 0xfd7f */ &Z80::invalid_opcode, /* 0xfd80 */ &Z80::invalid_opcode, /* 0xfd81 */ &Z80::invalid_opcode, /* 0xfd82 */ &Z80::invalid_opcode, /* 0xfd83 */ &Z80::Opc_fdxx_84, &Z80::Opc_fdxx_85, &Z80::Opc_fdxx_86, &Z80::invalid_opcode, /* 0xfd87 */ &Z80::invalid_opcode, /* 0xfd88 */ &Z80::invalid_opcode, /* 0xfd89 */ &Z80::invalid_opcode, /* 0xfd8a */ &Z80::invalid_opcode, /* 0xfd8b */ &Z80::Opc_fdxx_8c, &Z80::Opc_fdxx_8d, &Z80::Opc_fdxx_8e, &Z80::invalid_opcode, /* 0xfd8f */ &Z80::invalid_opcode, /* 0xfd90 */ &Z80::invalid_opcode, /* 0xfd91 */ &Z80::invalid_opcode, /* 0xfd92 */ &Z80::invalid_opcode, /* 0xfd93 */ &Z80::Opc_fdxx_94, &Z80::Opc_fdxx_95, &Z80::Opc_fdxx_96, &Z80::invalid_opcode, /* 0xfd97 */ &Z80::invalid_opcode, /* 0xfd98 */ &Z80::invalid_opcode, /* 0xfd99 */ &Z80::invalid_opcode, /* 0xfd9a */ &Z80::invalid_opcode, /* 0xfd9b */ &Z80::Opc_fdxx_9c, &Z80::Opc_fdxx_9d, &Z80::Opc_fdxx_9e, &Z80::invalid_opcode, /* 0xfd9f */ &Z80::invalid_opcode, /* 0xfda0 */ &Z80::invalid_opcode, /* 0xfda1 */ &Z80::invalid_opcode, /* 0xfda2 */ &Z80::invalid_opcode, /* 0xfda3 */ &Z80::Opc_fdxx_a4, &Z80::Opc_fdxx_a5, &Z80::Opc_fdxx_a6, &Z80::invalid_opcode, /* 0xfda7 */ &Z80::invalid_opcode, /* 0xfda8 */ &Z80::invalid_opcode, /* 0xfda9 */ &Z80::invalid_opcode, /* 0xfdaa */ &Z80::invalid_opcode, /* 0xfdab */ &Z80::Opc_fdxx_ac, &Z80::Opc_fdxx_ad, &Z80::Opc_fdxx_ae, &Z80::invalid_opcode, /* 0xfdaf */ &Z80::invalid_opcode, /* 0xfdb0 */ &Z80::invalid_opcode, /* 0xfdb1 */ &Z80::invalid_opcode, /* 0xfdb2 */ &Z80::invalid_opcode, /* 0xfdb3 */ &Z80::Opc_fdxx_b4, &Z80::Opc_fdxx_b5, &Z80::Opc_fdxx_b6, &Z80::invalid_opcode, /* 0xfdb7 */ &Z80::invalid_opcode, /* 0xfdb8 */ &Z80::invalid_opcode, /* 0xfdb9 */ &Z80::invalid_opcode, /* 0xfdba */ &Z80::invalid_opcode, /* 0xfdbb */ &Z80::Opc_fdxx_bc, &Z80::Opc_fdxx_bd, &Z80::Opc_fdxx_be, &Z80::invalid_opcode, /* 0xfdbf */ &Z80::invalid_opcode, /* 0xfdc0 */ &Z80::invalid_opcode, /* 0xfdc1 */ &Z80::invalid_opcode, /* 0xfdc2 */ &Z80::invalid_opcode, /* 0xfdc3 */ &Z80::invalid_opcode, /* 0xfdc4 */ &Z80::invalid_opcode, /* 0xfdc5 */ &Z80::invalid_opcode, /* 0xfdc6 */ &Z80::invalid_opcode, /* 0xfdc7 */ &Z80::invalid_opcode, /* 0xfdc8 */ &Z80::invalid_opcode, /* 0xfdc9 */ &Z80::invalid_opcode, /* 0xfdca */ &Z80::exec_fdcb, &Z80::invalid_opcode, /* 0xfdcc */ &Z80::invalid_opcode, /* 0xfdcd */ &Z80::invalid_opcode, /* 0xfdce */ &Z80::invalid_opcode, /* 0xfdcf */ &Z80::invalid_opcode, /* 0xfdd0 */ &Z80::invalid_opcode, /* 0xfdd1 */ &Z80::invalid_opcode, /* 0xfdd2 */ &Z80::invalid_opcode, /* 0xfdd3 */ &Z80::invalid_opcode, /* 0xfdd4 */ &Z80::invalid_opcode, /* 0xfdd5 */ &Z80::invalid_opcode, /* 0xfdd6 */ &Z80::invalid_opcode, /* 0xfdd7 */ &Z80::invalid_opcode, /* 0xfdd8 */ &Z80::invalid_opcode, /* 0xfdd9 */ &Z80::invalid_opcode, /* 0xfdda */ &Z80::invalid_opcode, /* 0xfddb */ &Z80::invalid_opcode, /* 0xfddc */ &Z80::invalid_opcode, /* 0xfddd */ &Z80::invalid_opcode, /* 0xfdde */ &Z80::invalid_opcode, /* 0xfddf */ &Z80::invalid_opcode, /* 0xfde0 */ &Z80::Opc_fdxx_e1, &Z80::invalid_opcode, /* 0xfde2 */ &Z80::Opc_fdxx_e3, &Z80::invalid_opcode, /* 0xfde4 */ &Z80::Opc_fdxx_e5, &Z80::invalid_opcode, /* 0xfde6 */ &Z80::invalid_opcode, /* 0xfde7 */ &Z80::invalid_opcode, /* 0xfde8 */ &Z80::Opc_fdxx_e9, &Z80::invalid_opcode, /* 0xfdea */ &Z80::invalid_opcode, /* 0xfdeb */ &Z80::invalid_opcode, /* 0xfdec */ &Z80::invalid_opcode, /* 0xfded */ &Z80::invalid_opcode, /* 0xfdee */ &Z80::invalid_opcode, /* 0xfdef */ &Z80::invalid_opcode, /* 0xfdf0 */ &Z80::invalid_opcode, /* 0xfdf1 */ &Z80::invalid_opcode, /* 0xfdf2 */ &Z80::invalid_opcode, /* 0xfdf3 */ &Z80::invalid_opcode, /* 0xfdf4 */ &Z80::invalid_opcode, /* 0xfdf5 */ &Z80::invalid_opcode, /* 0xfdf6 */ &Z80::invalid_opcode, /* 0xfdf7 */ &Z80::invalid_opcode, /* 0xfdf8 */ &Z80::Opc_fdxx_f9, &Z80::invalid_opcode, /* 0xfdfa */ &Z80::invalid_opcode, /* 0xfdfb */ &Z80::invalid_opcode, /* 0xfdfc */ &Z80::invalid_opcode, /* 0xfdfd */ &Z80::invalid_opcode, /* 0xfdfe */ &Z80::invalid_opcode /* 0xfdff */ }; osmose-emulator-1.4/src/Opc_fdcb.cpp000066400000000000000000001127621341430144300175110ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "Z80.h" void Z80::exec_fdcb() { u8 instruction; R++; // Prefixed instruction increments R by one. IYd = (u16)(IY + (s8)env.rd8(PC++)); instruction = env.rd8( PC++ ); (this->*(Opc_fdcb[instruction]))(); #ifdef OPCODES_STATS FDCB_Prefix[ instruction ]++; #endif } /* LD B, RLC (IY+d) */ void Z80::Opc_fdcb_00() { B = rlc8(env.rd8(IYd)); env.wr8(IYd, B); cycleCount += 23; } /* LD C, RLC (IY+d) */ void Z80::Opc_fdcb_01() { C = rlc8(env.rd8(IYd)); env.wr8(IYd, C); cycleCount += 23; } /* LD D, RLC (IY+d) */ void Z80::Opc_fdcb_02() { D = rlc8(env.rd8(IYd)); env.wr8(IYd, D); cycleCount += 23; } /* LD E, RLC (IY+d) */ void Z80::Opc_fdcb_03() { E = rlc8(env.rd8(IYd)); env.wr8(IYd, E); cycleCount += 23; } /* LD H, RLC (IY+d) */ void Z80::Opc_fdcb_04() { H = rlc8(env.rd8(IYd)); env.wr8(IYd, H); cycleCount += 23; } /* LD L, RLC (IY+d) */ void Z80::Opc_fdcb_05() { L = rlc8(env.rd8(IYd)); env.wr8(IYd, L); cycleCount += 23; } /* RLC (IY+d) */ void Z80::Opc_fdcb_06() { env.wr8(IYd, rlc8(env.rd8(IYd))); cycleCount += 23; } /* LD A, RLC (IY+d) */ void Z80::Opc_fdcb_07() { A = rlc8(env.rd8(IYd)); env.wr8(IYd, A); cycleCount += 23; } /* LD B, RRC (IY+d) */ void Z80::Opc_fdcb_08() { B = rrc8(env.rd8(IYd)); env.wr8(IYd, B); cycleCount += 23; } /* LD C, RRC (IY+d) */ void Z80::Opc_fdcb_09() { C = rrc8(env.rd8(IYd)); env.wr8(IYd, C); cycleCount += 23; } /* LD D, RRC (IY+d) */ void Z80::Opc_fdcb_0a() { D = rrc8(env.rd8(IYd)); env.wr8(IYd, D); cycleCount += 23; } /* LD E, RRC (IY+d) */ void Z80::Opc_fdcb_0b() { E = rrc8(env.rd8(IYd)); env.wr8(IYd, E); cycleCount += 23; } /* LD H, RRC (IY+d) */ void Z80::Opc_fdcb_0c() { H = rrc8(env.rd8(IYd)); env.wr8(IYd, H); cycleCount += 23; } /* LD L, RRC (IY+d) */ void Z80::Opc_fdcb_0d() { L = rrc8(env.rd8(IYd)); env.wr8(IYd, L); cycleCount += 23; } /* RRC (IY+d) */ void Z80::Opc_fdcb_0e() { env.wr8(IYd, rrc8(env.rd8(IYd))); cycleCount += 23; } /* LD A, RRC (IY+d) */ void Z80::Opc_fdcb_0f() { A = rrc8(env.rd8(IYd)); env.wr8(IYd, A); cycleCount += 23; } /* LD B, RL (IY+d) */ void Z80::Opc_fdcb_10() { B = rl8(env.rd8(IYd)); env.wr8(IYd, B); cycleCount += 23; } /* LD C, RL (IY+d) */ void Z80::Opc_fdcb_11() { C = rl8(env.rd8(IYd)); env.wr8(IYd, C); cycleCount += 23; } /* LD D, RL (IY+d) */ void Z80::Opc_fdcb_12() { D = rl8(env.rd8(IYd)); env.wr8(IYd, D); cycleCount += 23; } /* LD E, RL (IY+d) */ void Z80::Opc_fdcb_13() { E = rl8(env.rd8(IYd)); env.wr8(IYd, E); cycleCount += 23; } /* LD H, RL (IY+d) */ void Z80::Opc_fdcb_14() { H = rl8(env.rd8(IYd)); env.wr8(IYd, H); cycleCount += 23; } /* LD L, RL (IY+d) */ void Z80::Opc_fdcb_15() { L = rl8(env.rd8(IYd)); env.wr8(IYd, L); cycleCount += 23; } /* RL (IY+d) */ void Z80::Opc_fdcb_16() { env.wr8(IYd, rl8(env.rd8(IYd))); cycleCount += 23; } /* LD A, RL (IY+d) */ void Z80::Opc_fdcb_17() { A = rl8(env.rd8(IYd)); env.wr8(IYd, A); cycleCount += 23; } /* LD B, RR (IY+d) */ void Z80::Opc_fdcb_18() { B = rr8(env.rd8(IYd)); env.wr8(IYd, B); cycleCount += 23; } /* LD C, RR (IY+d) */ void Z80::Opc_fdcb_19() { C = rr8(env.rd8(IYd)); env.wr8(IYd, C); cycleCount += 23; } /* LD D, RR (IY+d) */ void Z80::Opc_fdcb_1a() { D = rr8(env.rd8(IYd)); env.wr8(IYd, D); cycleCount += 23; } /* LD E, RR (IY+d) */ void Z80::Opc_fdcb_1b() { E = rr8(env.rd8(IYd)); env.wr8(IYd, E); cycleCount += 23; } /* LD H, RR (IY+d) */ void Z80::Opc_fdcb_1c() { H = rr8(env.rd8(IYd)); env.wr8(IYd, H); cycleCount += 23; } /* LD L, RR (IY+d) */ void Z80::Opc_fdcb_1d() { L = rr8(env.rd8(IYd)); env.wr8(IYd, L); cycleCount += 23; } /* RR (IY+d) */ void Z80::Opc_fdcb_1e() { env.wr8(IYd, rr8(env.rd8(IYd))); cycleCount += 23; } /* LD A, RR (IY+d) */ void Z80::Opc_fdcb_1f() { A = rr8(env.rd8(IYd)); env.wr8(IYd, A); cycleCount += 23; } /* LD B, SLA (IY+d) */ void Z80::Opc_fdcb_20() { B = sla8(env.rd8(IYd)); env.wr8(IYd, B); cycleCount += 23; } /* LD C, SLA (IY+d) */ void Z80::Opc_fdcb_21() { C = sla8(env.rd8(IYd)); env.wr8(IYd, C); cycleCount += 23; } /* LD D, SLA (IY+d) */ void Z80::Opc_fdcb_22() { D = sla8(env.rd8(IYd)); env.wr8(IYd, D); cycleCount += 23; } /* LD E, SLA (IY+d) */ void Z80::Opc_fdcb_23() { E = sla8(env.rd8(IYd)); env.wr8(IYd, E); cycleCount += 23; } /* LD H, SLA (IY+d) */ void Z80::Opc_fdcb_24() { H = sla8(env.rd8(IYd)); env.wr8(IYd, H); cycleCount += 23; } /* LD L, SLA (IY+d) */ void Z80::Opc_fdcb_25() { L = sla8(env.rd8(IYd)); env.wr8(IYd, L); cycleCount += 23; } /* SLA (IY+d) */ void Z80::Opc_fdcb_26() { env.wr8(IYd, sla8(env.rd8(IYd))); cycleCount += 23; } /* LD A, SLA (IY+d) */ void Z80::Opc_fdcb_27() { A = sla8(env.rd8(IYd)); env.wr8(IYd, A); cycleCount += 23; } /* LD B, SRA (IY+d) */ void Z80::Opc_fdcb_28() { B = sra8(env.rd8(IYd)); env.wr8(IYd, B); cycleCount += 23; } /* LD C, SRA (IY+d) */ void Z80::Opc_fdcb_29() { C = sra8(env.rd8(IYd)); env.wr8(IYd, C); cycleCount += 23; } /* LD D, SRA (IY+d) */ void Z80::Opc_fdcb_2a() { D = sra8(env.rd8(IYd)); env.wr8(IYd, D); cycleCount += 23; } /* LD E, SRA (IY+d) */ void Z80::Opc_fdcb_2b() { E = sra8(env.rd8(IYd)); env.wr8(IYd, E); cycleCount += 23; } /* LD H, SRA (IY+d) */ void Z80::Opc_fdcb_2c() { H = sra8(env.rd8(IYd)); env.wr8(IYd, H); cycleCount += 23; } /* LD L, SRA (IY+d) */ void Z80::Opc_fdcb_2d() { L = sra8(env.rd8(IYd)); env.wr8(IYd, L); cycleCount += 23; } /* SRA (IY+d) */ void Z80::Opc_fdcb_2e() { env.wr8(IYd, sra8(env.rd8(IYd))); cycleCount += 23; } /* LD A, SRA (IY+d) */ void Z80::Opc_fdcb_2f() { A = sra8(env.rd8(IYd)); env.wr8(IYd, A); cycleCount += 23; } /* LD B, SLL (IY+d) */ void Z80::Opc_fdcb_30() { B = sll8(env.rd8(IYd)); env.wr8(IYd, B); cycleCount += 23; } /* LD C, SLL (IY+d) */ void Z80::Opc_fdcb_31() { C = sll8(env.rd8(IYd)); env.wr8(IYd, C); cycleCount += 23; } /* LD D, SLL (IY+d) */ void Z80::Opc_fdcb_32() { D = sll8(env.rd8(IYd)); env.wr8(IYd, D); cycleCount += 23; } /* LD E, SLL (IY+d) */ void Z80::Opc_fdcb_33() { E = sll8(env.rd8(IYd)); env.wr8(IYd, E); cycleCount += 23; } /* LD H, SLL (IY+d) */ void Z80::Opc_fdcb_34() { H = sll8(env.rd8(IYd)); env.wr8(IYd, H); cycleCount += 23; } /* LD L, SLL (IY+d) */ void Z80::Opc_fdcb_35() { L = sll8(env.rd8(IYd)); env.wr8(IYd, L); cycleCount += 23; } /* SLL (IY+d) */ void Z80::Opc_fdcb_36() { env.wr8(IYd, sll8(env.rd8(IYd))); cycleCount += 23; } /* LD A, SLL (IY+d) */ void Z80::Opc_fdcb_37() { A = sll8(env.rd8(IYd)); env.wr8(IYd, A); cycleCount += 23; } /* LD B, SRL (IY+d) */ void Z80::Opc_fdcb_38() { B = srl8(env.rd8(IYd)); env.wr8(IYd, B); cycleCount += 23; } /* LD C, SRL (IY+d) */ void Z80::Opc_fdcb_39() { C = srl8(env.rd8(IYd)); env.wr8(IYd, C); cycleCount += 23; } /* LD D, SRL (IY+d) */ void Z80::Opc_fdcb_3a() { D = srl8(env.rd8(IYd)); env.wr8(IYd, D); cycleCount += 23; } /* LD E, SRL (IY+d) */ void Z80::Opc_fdcb_3b() { E = srl8(env.rd8(IYd)); env.wr8(IYd, E); cycleCount += 23; } /* LD H, SRL (IY+d) */ void Z80::Opc_fdcb_3c() { H = srl8(env.rd8(IYd)); env.wr8(IYd, H); cycleCount += 23; } /* LD L, SRL (IY+d) */ void Z80::Opc_fdcb_3d() { L = srl8(env.rd8(IYd)); env.wr8(IYd, L); cycleCount += 23; } /* SRL (IY+d) */ void Z80::Opc_fdcb_3e() { env.wr8(IYd, srl8(env.rd8(IYd))); cycleCount += 23; } /* LD A, SRL (IY+d) */ void Z80::Opc_fdcb_3f() { A = srl8(env.rd8(IYd)); env.wr8(IYd, A); cycleCount += 23; } /* BIT 0, (IY+d) */ void Z80::Opc_fdcb_40() { bit(0, env.rd8(IYd)); cycleCount += 20; } /* BIT 0, (IY+d) */ void Z80::Opc_fdcb_41() { bit(0, env.rd8(IYd)); cycleCount += 20; } /* BIT 0, (IY+d) */ void Z80::Opc_fdcb_42() { bit(0, env.rd8(IYd)); cycleCount += 20; } /* BIT 0, (IY+d) */ void Z80::Opc_fdcb_43() { bit(0, env.rd8(IYd)); cycleCount += 20; } /* BIT 0, (IY+d) */ void Z80::Opc_fdcb_44() { bit(0, env.rd8(IYd)); cycleCount += 20; } /* BIT 0, (IY+d) */ void Z80::Opc_fdcb_45() { bit(0, env.rd8(IYd)); cycleCount += 20; } /* BIT 0, (IY+d) */ void Z80::Opc_fdcb_46() { bit(0, env.rd8(IYd)); cycleCount += 20; } /* BIT 0, (IY+d) */ void Z80::Opc_fdcb_47() { bit(0, env.rd8(IYd)); cycleCount += 20; } /* BIT 1, (IY+d) */ void Z80::Opc_fdcb_48() { bit(1, env.rd8(IYd)); cycleCount += 20; } /* BIT 1, (IY+d) */ void Z80::Opc_fdcb_49() { bit(1, env.rd8(IYd)); cycleCount += 20; } /* BIT 1, (IY+d) */ void Z80::Opc_fdcb_4a() { bit(1, env.rd8(IYd)); cycleCount += 20; } /* BIT 1, (IY+d) */ void Z80::Opc_fdcb_4b() { bit(1, env.rd8(IYd)); cycleCount += 20; } /* BIT 1, (IY+d) */ void Z80::Opc_fdcb_4c() { bit(1, env.rd8(IYd)); cycleCount += 20; } /* BIT 1, (IY+d) */ void Z80::Opc_fdcb_4d() { bit(1, env.rd8(IYd)); cycleCount += 20; } /* BIT 1, (IY+d) */ void Z80::Opc_fdcb_4e() { bit(1, env.rd8(IYd)); cycleCount += 20; } /* BIT 1, (IY+d) */ void Z80::Opc_fdcb_4f() { bit(1, env.rd8(IYd)); cycleCount += 20; } /* BIT 2, (IY+d) */ void Z80::Opc_fdcb_50() { bit(2, env.rd8(IYd)); cycleCount += 20; } /* BIT 2, (IY+d) */ void Z80::Opc_fdcb_51() { bit(2, env.rd8(IYd)); cycleCount += 20; } /* BIT 2, (IY+d) */ void Z80::Opc_fdcb_52() { bit(2, env.rd8(IYd)); cycleCount += 20; } /* BIT 2, (IY+d) */ void Z80::Opc_fdcb_53() { bit(2, env.rd8(IYd)); cycleCount += 20; } /* BIT 2, (IY+d) */ void Z80::Opc_fdcb_54() { bit(2, env.rd8(IYd)); cycleCount += 20; } /* BIT 2, (IY+d) */ void Z80::Opc_fdcb_55() { bit(2, env.rd8(IYd)); cycleCount += 20; } /* BIT 2, (IY+d) */ void Z80::Opc_fdcb_56() { bit(2, env.rd8(IYd)); cycleCount += 20; } /* BIT 2, (IY+d) */ void Z80::Opc_fdcb_57() { bit(2, env.rd8(IYd)); cycleCount += 20; } /* BIT 3, (IY+d) */ void Z80::Opc_fdcb_58() { bit(3, env.rd8(IYd)); cycleCount += 20; } /* BIT 3, (IY+d) */ void Z80::Opc_fdcb_59() { bit(3, env.rd8(IYd)); cycleCount += 20; } /* BIT 3, (IY+d) */ void Z80::Opc_fdcb_5a() { bit(3, env.rd8(IYd)); cycleCount += 20; } /* BIT 3, (IY+d) */ void Z80::Opc_fdcb_5b() { bit(3, env.rd8(IYd)); cycleCount += 20; } /* BIT 3, (IY+d) */ void Z80::Opc_fdcb_5c() { bit(3, env.rd8(IYd)); cycleCount += 20; } /* BIT 3, (IY+d) */ void Z80::Opc_fdcb_5d() { bit(3, env.rd8(IYd)); cycleCount += 20; } /* BIT 3, (IY+d) */ void Z80::Opc_fdcb_5e() { bit(3, env.rd8(IYd)); cycleCount += 20; } /* BIT 3, (IY+d) */ void Z80::Opc_fdcb_5f() { bit(3, env.rd8(IYd)); cycleCount += 20; } /* BIT 4, (IY+d) */ void Z80::Opc_fdcb_60() { bit(4, env.rd8(IYd)); cycleCount += 20; } /* BIT 4, (IY+d) */ void Z80::Opc_fdcb_61() { bit(4, env.rd8(IYd)); cycleCount += 20; } /* BIT 4, (IY+d) */ void Z80::Opc_fdcb_62() { bit(4, env.rd8(IYd)); cycleCount += 20; } /* BIT 4, (IY+d) */ void Z80::Opc_fdcb_63() { bit(4, env.rd8(IYd)); cycleCount += 20; } /* BIT 4, (IY+d) */ void Z80::Opc_fdcb_64() { bit(4, env.rd8(IYd)); cycleCount += 20; } /* BIT 4, (IY+d) */ void Z80::Opc_fdcb_65() { bit(4, env.rd8(IYd)); cycleCount += 20; } /* BIT 4, (IY+d) */ void Z80::Opc_fdcb_66() { bit(4, env.rd8(IYd)); cycleCount += 20; } /* BIT 4, (IY+d) */ void Z80::Opc_fdcb_67() { bit(4, env.rd8(IYd)); cycleCount += 20; } /* BIT 5, (IY+d) */ void Z80::Opc_fdcb_68() { bit(5, env.rd8(IYd)); cycleCount += 20; } /* BIT 5, (IY+d) */ void Z80::Opc_fdcb_69() { bit(5, env.rd8(IYd)); cycleCount += 20; } /* BIT 5, (IY+d) */ void Z80::Opc_fdcb_6a() { bit(5, env.rd8(IYd)); cycleCount += 20; } /* BIT 5, (IY+d) */ void Z80::Opc_fdcb_6b() { bit(5, env.rd8(IYd)); cycleCount += 20; } /* BIT 5, (IY+d) */ void Z80::Opc_fdcb_6c() { bit(5, env.rd8(IYd)); cycleCount += 20; } /* BIT 5, (IY+d) */ void Z80::Opc_fdcb_6d() { bit(5, env.rd8(IYd)); cycleCount += 20; } /* BIT 5, (IY+d) */ void Z80::Opc_fdcb_6e() { bit(5, env.rd8(IYd)); cycleCount += 20; } /* BIT 5, (IY+d) */ void Z80::Opc_fdcb_6f() { bit(5, env.rd8(IYd)); cycleCount += 20; } /* BIT 6, (IY+d) */ void Z80::Opc_fdcb_70() { bit(6, env.rd8(IYd)); cycleCount += 20; } /* BIT 6, (IY+d) */ void Z80::Opc_fdcb_71() { bit(6, env.rd8(IYd)); cycleCount += 20; } /* BIT 6, (IY+d) */ void Z80::Opc_fdcb_72() { bit(6, env.rd8(IYd)); cycleCount += 20; } /* BIT 6, (IY+d) */ void Z80::Opc_fdcb_73() { bit(6, env.rd8(IYd)); cycleCount += 20; } /* BIT 6, (IY+d) */ void Z80::Opc_fdcb_74() { bit(6, env.rd8(IYd)); cycleCount += 20; } /* BIT 6, (IY+d) */ void Z80::Opc_fdcb_75() { bit(6, env.rd8(IYd)); cycleCount += 20; } /* BIT 6, (IY+d) */ void Z80::Opc_fdcb_76() { bit(6, env.rd8(IYd)); cycleCount += 20; } /* BIT 6, (IY+d) */ void Z80::Opc_fdcb_77() { bit(6, env.rd8(IYd)); cycleCount += 20; } /* BIT 7, (IY+d) */ void Z80::Opc_fdcb_78() { bit(7, env.rd8(IYd)); cycleCount += 20; } /* BIT 7, (IY+d) */ void Z80::Opc_fdcb_79() { bit(7, env.rd8(IYd)); cycleCount += 20; } /* BIT 7, (IY+d) */ void Z80::Opc_fdcb_7a() { bit(7, env.rd8(IYd)); cycleCount += 20; } /* BIT 7, (IY+d) */ void Z80::Opc_fdcb_7b() { bit(7, env.rd8(IYd)); cycleCount += 20; } /* BIT 7, (IY+d) */ void Z80::Opc_fdcb_7c() { bit(7, env.rd8(IYd)); cycleCount += 20; } /* BIT 7, (IY+d) */ void Z80::Opc_fdcb_7d() { bit(7, env.rd8(IYd)); cycleCount += 20; } /* BIT 7, (IY+d) */ void Z80::Opc_fdcb_7e() { bit(7, env.rd8(IYd)); cycleCount += 20; } /* BIT 7, (IY+d) */ void Z80::Opc_fdcb_7f() { bit(7, env.rd8(IYd)); cycleCount += 20; } /* LD B, RES 0, (IY+d) */ void Z80::Opc_fdcb_80() { env.wr8(IYd, res(0, env.rd8(IYd))); B = env.rd8(IYd); cycleCount += 23; } /* LD C, RES 0, (IY+d) */ void Z80::Opc_fdcb_81() { env.wr8(IYd, res(0, env.rd8(IYd))); C = env.rd8(IYd); cycleCount += 23; } /* LD D, RES 0, (IY+d) */ void Z80::Opc_fdcb_82() { env.wr8(IYd, res(0, env.rd8(IYd))); D = env.rd8(IYd); cycleCount += 23; } /* LD E, RES 0, (IY+d) */ void Z80::Opc_fdcb_83() { env.wr8(IYd, res(0, env.rd8(IYd))); E = env.rd8(IYd); cycleCount += 23; } /* LD H, RES 0, (IY+d) */ void Z80::Opc_fdcb_84() { env.wr8(IYd, res(0, env.rd8(IYd))); H = env.rd8(IYd); cycleCount += 23; } /* LD L, RES 0, (IY+d) */ void Z80::Opc_fdcb_85() { env.wr8(IYd, res(0, env.rd8(IYd))); L = env.rd8(IYd); cycleCount += 23; } /* RES 0, (IY+d) */ void Z80::Opc_fdcb_86() { env.wr8(IYd, res(0, env.rd8(IYd))); cycleCount += 23; } /* LD A, RES 0, (IY+d) */ void Z80::Opc_fdcb_87() { env.wr8(IYd, res(0, env.rd8(IYd))); A = env.rd8(IYd); cycleCount += 23; } /* LD B, RES 1, (IY+d) */ void Z80::Opc_fdcb_88() { env.wr8(IYd, res(1, env.rd8(IYd))); B = env.rd8(IYd); cycleCount += 23; } /* LD C, RES 1, (IY+d) */ void Z80::Opc_fdcb_89() { env.wr8(IYd, res(1, env.rd8(IYd))); C = env.rd8(IYd); cycleCount += 23; } /* LD D, RES 1, (IY+d) */ void Z80::Opc_fdcb_8a() { env.wr8(IYd, res(1, env.rd8(IYd))); D = env.rd8(IYd); cycleCount += 23; } /* LD E, RES 1, (IY+d) */ void Z80::Opc_fdcb_8b() { env.wr8(IYd, res(1, env.rd8(IYd))); E = env.rd8(IYd); cycleCount += 23; } /* LD H, RES 1, (IY+d) */ void Z80::Opc_fdcb_8c() { env.wr8(IYd, res(1, env.rd8(IYd))); H = env.rd8(IYd); cycleCount += 23; } /* LD L, RES 1, (IY+d) */ void Z80::Opc_fdcb_8d() { env.wr8(IYd, res(1, env.rd8(IYd))); L = env.rd8(IYd); cycleCount += 23; } /* RES 1, (IY+d) */ void Z80::Opc_fdcb_8e() { env.wr8(IYd, res(1, env.rd8(IYd))); cycleCount += 23; } /* LD A, RES 1, (IY+d) */ void Z80::Opc_fdcb_8f() { env.wr8(IYd, res(1, env.rd8(IYd))); A = env.rd8(IYd); cycleCount += 23; } /* LD B, RES 2, (IY+d) */ void Z80::Opc_fdcb_90() { env.wr8(IYd, res(2, env.rd8(IYd))); B = env.rd8(IYd); cycleCount += 23; } /* LD C, RES 2, (IY+d) */ void Z80::Opc_fdcb_91() { env.wr8(IYd, res(2, env.rd8(IYd))); C = env.rd8(IYd); cycleCount += 23; } /* LD D, RES 2, (IY+d) */ void Z80::Opc_fdcb_92() { env.wr8(IYd, res(2, env.rd8(IYd))); D = env.rd8(IYd); cycleCount += 23; } /* LD E, RES 2, (IY+d) */ void Z80::Opc_fdcb_93() { env.wr8(IYd, res(2, env.rd8(IYd))); E = env.rd8(IYd); cycleCount += 23; } /* LD H, RES 2, (IY+d) */ void Z80::Opc_fdcb_94() { env.wr8(IYd, res(2, env.rd8(IYd))); H = env.rd8(IYd); cycleCount += 23; } /* LD L, RES 2, (IY+d) */ void Z80::Opc_fdcb_95() { env.wr8(IYd, res(2, env.rd8(IYd))); L = env.rd8(IYd); cycleCount += 23; } /* RES 2, (IY+d) */ void Z80::Opc_fdcb_96() { env.wr8(IYd, res(2, env.rd8(IYd))); cycleCount += 23; } /* LD A, RES 2, (IY+d) */ void Z80::Opc_fdcb_97() { env.wr8(IYd, res(2, env.rd8(IYd))); A = env.rd8(IYd); cycleCount += 23; } /* LD B, RES 3, (IY+d) */ void Z80::Opc_fdcb_98() { env.wr8(IYd, res(3, env.rd8(IYd))); B = env.rd8(IYd); cycleCount += 23; } /* LD C, RES 3, (IY+d) */ void Z80::Opc_fdcb_99() { env.wr8(IYd, res(3, env.rd8(IYd))); C = env.rd8(IYd); cycleCount += 23; } /* LD D, RES 3, (IY+d) */ void Z80::Opc_fdcb_9a() { env.wr8(IYd, res(3, env.rd8(IYd))); D = env.rd8(IYd); cycleCount += 23; } /* LD E, RES 3, (IY+d) */ void Z80::Opc_fdcb_9b() { env.wr8(IYd, res(3, env.rd8(IYd))); E = env.rd8(IYd); cycleCount += 23; } /* LD H, RES 3, (IY+d) */ void Z80::Opc_fdcb_9c() { env.wr8(IYd, res(3, env.rd8(IYd))); H = env.rd8(IYd); cycleCount += 23; } /* LD L, RES 3, (IY+d) */ void Z80::Opc_fdcb_9d() { env.wr8(IYd, res(3, env.rd8(IYd))); L = env.rd8(IYd); cycleCount += 23; } /* RES 3, (IY+d) */ void Z80::Opc_fdcb_9e() { env.wr8(IYd, res(3, env.rd8(IYd))); cycleCount += 23; } /* LD A, RES 3, (IY+d) */ void Z80::Opc_fdcb_9f() { env.wr8(IYd, res(3, env.rd8(IYd))); A = env.rd8(IYd); cycleCount += 23; } /* LD B, RES 4, (IY+d) */ void Z80::Opc_fdcb_a0() { env.wr8(IYd, res(4, env.rd8(IYd))); B = env.rd8(IYd); cycleCount += 23; } /* LD C, RES 4, (IY+d) */ void Z80::Opc_fdcb_a1() { env.wr8(IYd, res(4, env.rd8(IYd))); C = env.rd8(IYd); cycleCount += 23; } /* LD D, RES 4, (IY+d) */ void Z80::Opc_fdcb_a2() { env.wr8(IYd, res(4, env.rd8(IYd))); D = env.rd8(IYd); cycleCount += 23; } /* LD E, RES 4, (IY+d) */ void Z80::Opc_fdcb_a3() { env.wr8(IYd, res(4, env.rd8(IYd))); E = env.rd8(IYd); cycleCount += 23; } /* LD H, RES 4, (IY+d) */ void Z80::Opc_fdcb_a4() { env.wr8(IYd, res(4, env.rd8(IYd))); H = env.rd8(IYd); cycleCount += 23; } /* LD L, RES 4, (IY+d) */ void Z80::Opc_fdcb_a5() { env.wr8(IYd, res(4, env.rd8(IYd))); L = env.rd8(IYd); cycleCount += 23; } /* RES 4, (IY+d) */ void Z80::Opc_fdcb_a6() { env.wr8(IYd, res(4, env.rd8(IYd))); cycleCount += 23; } /* LD A, RES 4, (IY+d) */ void Z80::Opc_fdcb_a7() { env.wr8(IYd, res(4, env.rd8(IYd))); A = env.rd8(IYd); cycleCount += 23; } /* LD B, RES 5, (IY+d) */ void Z80::Opc_fdcb_a8() { env.wr8(IYd, res(5, env.rd8(IYd))); B = env.rd8(IYd); cycleCount += 23; } /* LD C, RES 5, (IY+d) */ void Z80::Opc_fdcb_a9() { env.wr8(IYd, res(5, env.rd8(IYd))); C = env.rd8(IYd); cycleCount += 23; } /* LD D, RES 5, (IY+d) */ void Z80::Opc_fdcb_aa() { env.wr8(IYd, res(5, env.rd8(IYd))); D = env.rd8(IYd); cycleCount += 23; } /* LD E, RES 5, (IY+d) */ void Z80::Opc_fdcb_ab() { env.wr8(IYd, res(5, env.rd8(IYd))); E = env.rd8(IYd); cycleCount += 23; } /* LD H, RES 5, (IY+d) */ void Z80::Opc_fdcb_ac() { env.wr8(IYd, res(5, env.rd8(IYd))); H = env.rd8(IYd); cycleCount += 23; } /* LD L, RES 5, (IY+d) */ void Z80::Opc_fdcb_ad() { env.wr8(IYd, res(5, env.rd8(IYd))); L = env.rd8(IYd); cycleCount += 23; } /* RES 5, (IY+d) */ void Z80::Opc_fdcb_ae() { env.wr8(IYd, res(5, env.rd8(IYd))); cycleCount += 23; } /* LD A, RES 5, (IY+d) */ void Z80::Opc_fdcb_af() { env.wr8(IYd, res(5, env.rd8(IYd))); A = env.rd8(IYd); cycleCount += 23; } /* LD B, RES 6, (IY+d) */ void Z80::Opc_fdcb_b0() { env.wr8(IYd, res(6, env.rd8(IYd))); B = env.rd8(IYd); cycleCount += 23; } /* LD C, RES 6, (IY+d) */ void Z80::Opc_fdcb_b1() { env.wr8(IYd, res(6, env.rd8(IYd))); C = env.rd8(IYd); cycleCount += 23; } /* LD D, RES 6, (IY+d) */ void Z80::Opc_fdcb_b2() { env.wr8(IYd, res(6, env.rd8(IYd))); D = env.rd8(IYd); cycleCount += 23; } /* LD E, RES 6, (IY+d) */ void Z80::Opc_fdcb_b3() { env.wr8(IYd, res(6, env.rd8(IYd))); E = env.rd8(IYd); cycleCount += 23; } /* LD H, RES 6, (IY+d) */ void Z80::Opc_fdcb_b4() { env.wr8(IYd, res(6, env.rd8(IYd))); H = env.rd8(IYd); cycleCount += 23; } /* LD L, RES 6, (IY+d) */ void Z80::Opc_fdcb_b5() { env.wr8(IYd, res(6, env.rd8(IYd))); L = env.rd8(IYd); cycleCount += 23; } /* RES 6, (IY+d) */ void Z80::Opc_fdcb_b6() { env.wr8(IYd, res(6, env.rd8(IYd))); cycleCount += 23; } /* LD A, RES 6, (IY+d) */ void Z80::Opc_fdcb_b7() { env.wr8(IYd, res(6, env.rd8(IYd))); A = env.rd8(IYd); cycleCount += 23; } /* LD B, RES 7, (IY+d) */ void Z80::Opc_fdcb_b8() { env.wr8(IYd, res(7, env.rd8(IYd))); B = env.rd8(IYd); cycleCount += 23; } /* LD C, RES 7, (IY+d) */ void Z80::Opc_fdcb_b9() { env.wr8(IYd, res(7, env.rd8(IYd))); C = env.rd8(IYd); cycleCount += 23; } /* LD D, RES 7, (IY+d) */ void Z80::Opc_fdcb_ba() { env.wr8(IYd, res(7, env.rd8(IYd))); D = env.rd8(IYd); cycleCount += 23; } /* LD E, RES 7, (IY+d) */ void Z80::Opc_fdcb_bb() { env.wr8(IYd, res(7, env.rd8(IYd))); E = env.rd8(IYd); cycleCount += 23; } /* LD H, RES 7, (IY+d) */ void Z80::Opc_fdcb_bc() { env.wr8(IYd, res(7, env.rd8(IYd))); H = env.rd8(IYd); cycleCount += 23; } /* LD L, RES 7, (IY+d) */ void Z80::Opc_fdcb_bd() { env.wr8(IYd, res(7, env.rd8(IYd))); L = env.rd8(IYd); cycleCount += 23; } /* RES 7, (IY+d) */ void Z80::Opc_fdcb_be() { env.wr8(IYd, res(7, env.rd8(IYd))); cycleCount += 23; } /* LD A, RES 7, (IY+d) */ void Z80::Opc_fdcb_bf() { env.wr8(IYd, res(7, env.rd8(IYd))); A = env.rd8(IYd); cycleCount += 23; } /* LD B, SET 0, (IY+d) */ void Z80::Opc_fdcb_c0() { env.wr8(IYd, set(0, env.rd8(IYd))); B = env.rd8(IYd); cycleCount += 23; } /* LD C, SET 0, (IY+d) */ void Z80::Opc_fdcb_c1() { env.wr8(IYd, set(0, env.rd8(IYd))); C = env.rd8(IYd); cycleCount += 23; } /* LD D, SET 0, (IY+d) */ void Z80::Opc_fdcb_c2() { env.wr8(IYd, set(0, env.rd8(IYd))); D = env.rd8(IYd); cycleCount += 23; } /* LD E, SET 0, (IY+d) */ void Z80::Opc_fdcb_c3() { env.wr8(IYd, set(0, env.rd8(IYd))); E = env.rd8(IYd); cycleCount += 23; } /* LD H, SET 0, (IY+d) */ void Z80::Opc_fdcb_c4() { env.wr8(IYd, set(0, env.rd8(IYd))); H = env.rd8(IYd); cycleCount += 23; } /* LD L, SET 0, (IY+d) */ void Z80::Opc_fdcb_c5() { env.wr8(IYd, set(0, env.rd8(IYd))); L = env.rd8(IYd); cycleCount += 23; } /* SET 0, (IY+d) */ void Z80::Opc_fdcb_c6() { env.wr8(IYd, set(0, env.rd8(IYd))); cycleCount += 23; } /* LD A, SET 0, (IY+d) */ void Z80::Opc_fdcb_c7() { env.wr8(IYd, set(0, env.rd8(IYd))); A = env.rd8(IYd); cycleCount += 23; } /* LD B, SET 1, (IY+d) */ void Z80::Opc_fdcb_c8() { env.wr8(IYd, set(1, env.rd8(IYd))); B = env.rd8(IYd); cycleCount += 23; } /* LD C, SET 1, (IY+d) */ void Z80::Opc_fdcb_c9() { env.wr8(IYd, set(1, env.rd8(IYd))); C = env.rd8(IYd); cycleCount += 23; } /* LD D, SET 1, (IY+d) */ void Z80::Opc_fdcb_ca() { env.wr8(IYd, set(1, env.rd8(IYd))); D = env.rd8(IYd); cycleCount += 23; } /* LD E, SET 1, (IY+d) */ void Z80::Opc_fdcb_cb() { env.wr8(IYd, set(1, env.rd8(IYd))); E = env.rd8(IYd); cycleCount += 23; } /* LD H, SET 1, (IY+d) */ void Z80::Opc_fdcb_cc() { env.wr8(IYd, set(1, env.rd8(IYd))); H = env.rd8(IYd); cycleCount += 23; } /* LD L, SET 1, (IY+d) */ void Z80::Opc_fdcb_cd() { env.wr8(IYd, set(1, env.rd8(IYd))); L = env.rd8(IYd); cycleCount += 23; } /* SET 1, (IY+d) */ void Z80::Opc_fdcb_ce() { env.wr8(IYd, set(1, env.rd8(IYd))); cycleCount += 23; } /* LD A, SET 1, (IY+d) */ void Z80::Opc_fdcb_cf() { env.wr8(IYd, set(1, env.rd8(IYd))); A = env.rd8(IYd); cycleCount += 23; } /* LD B, SET 2, (IY+d) */ void Z80::Opc_fdcb_d0() { env.wr8(IYd, set(2, env.rd8(IYd))); B = env.rd8(IYd); cycleCount += 23; } /* LD C, SET 2, (IY+d) */ void Z80::Opc_fdcb_d1() { env.wr8(IYd, set(2, env.rd8(IYd))); C = env.rd8(IYd); cycleCount += 23; } /* LD D, SET 2, (IY+d) */ void Z80::Opc_fdcb_d2() { env.wr8(IYd, set(2, env.rd8(IYd))); D = env.rd8(IYd); cycleCount += 23; } /* LD E, SET 2, (IY+d) */ void Z80::Opc_fdcb_d3() { env.wr8(IYd, set(2, env.rd8(IYd))); E = env.rd8(IYd); cycleCount += 23; } /* LD H, SET 2, (IY+d) */ void Z80::Opc_fdcb_d4() { env.wr8(IYd, set(2, env.rd8(IYd))); H = env.rd8(IYd); cycleCount += 23; } /* LD L, SET 2, (IY+d) */ void Z80::Opc_fdcb_d5() { env.wr8(IYd, set(2, env.rd8(IYd))); L = env.rd8(IYd); cycleCount += 23; } /* SET 2, (IY+d) */ void Z80::Opc_fdcb_d6() { env.wr8(IYd, set(2, env.rd8(IYd))); cycleCount += 23; } /* LD A, SET 2, (IY+d) */ void Z80::Opc_fdcb_d7() { env.wr8(IYd, set(2, env.rd8(IYd))); A = env.rd8(IYd); cycleCount += 23; } /* LD B, SET 3, (IY+d) */ void Z80::Opc_fdcb_d8() { env.wr8(IYd, set(3, env.rd8(IYd))); B = env.rd8(IYd); cycleCount += 23; } /* LD C, SET 3, (IY+d) */ void Z80::Opc_fdcb_d9() { env.wr8(IYd, set(3, env.rd8(IYd))); C = env.rd8(IYd); cycleCount += 23; } /* LD D, SET 3, (IY+d) */ void Z80::Opc_fdcb_da() { env.wr8(IYd, set(3, env.rd8(IYd))); D = env.rd8(IYd); cycleCount += 23; } /* LD E, SET 3, (IY+d) */ void Z80::Opc_fdcb_db() { env.wr8(IYd, set(3, env.rd8(IYd))); E = env.rd8(IYd); cycleCount += 23; } /* LD H, SET 3, (IY+d) */ void Z80::Opc_fdcb_dc() { env.wr8(IYd, set(3, env.rd8(IYd))); H = env.rd8(IYd); cycleCount += 23; } /* LD L, SET 3, (IY+d) */ void Z80::Opc_fdcb_dd() { env.wr8(IYd, set(3, env.rd8(IYd))); L = env.rd8(IYd); cycleCount += 23; } /* SET 3, (IY+d) */ void Z80::Opc_fdcb_de() { env.wr8(IYd, set(3, env.rd8(IYd))); cycleCount += 23; } /* LD A, SET 3, (IY+d) */ void Z80::Opc_fdcb_df() { env.wr8(IYd, set(3, env.rd8(IYd))); A = env.rd8(IYd); cycleCount += 23; } /* LD B, SET 4, (IY+d) */ void Z80::Opc_fdcb_e0() { env.wr8(IYd, set(4, env.rd8(IYd))); B = env.rd8(IYd); cycleCount += 23; } /* LD C, SET 4, (IY+d) */ void Z80::Opc_fdcb_e1() { env.wr8(IYd, set(4, env.rd8(IYd))); C = env.rd8(IYd); cycleCount += 23; } /* LD D, SET 4, (IY+d) */ void Z80::Opc_fdcb_e2() { env.wr8(IYd, set(4, env.rd8(IYd))); D = env.rd8(IYd); cycleCount += 23; } /* LD E, SET 4, (IY+d) */ void Z80::Opc_fdcb_e3() { env.wr8(IYd, set(4, env.rd8(IYd))); E = env.rd8(IYd); cycleCount += 23; } /* LD H, SET 4, (IY+d) */ void Z80::Opc_fdcb_e4() { env.wr8(IYd, set(4, env.rd8(IYd))); H = env.rd8(IYd); cycleCount += 23; } /* LD L, SET 4, (IY+d) */ void Z80::Opc_fdcb_e5() { env.wr8(IYd, set(4, env.rd8(IYd))); L = env.rd8(IYd); cycleCount += 23; } /* SET 4, (IY+d) */ void Z80::Opc_fdcb_e6() { env.wr8(IYd, set(4, env.rd8(IYd))); cycleCount += 23; } /* LD A, SET 4, (IY+d) */ void Z80::Opc_fdcb_e7() { env.wr8(IYd, set(4, env.rd8(IYd))); A = env.rd8(IYd); cycleCount += 23; } /* LD B, SET 5, (IY+d) */ void Z80::Opc_fdcb_e8() { env.wr8(IYd, set(5, env.rd8(IYd))); B = env.rd8(IYd); cycleCount += 23; } /* LD C, SET 5, (IY+d) */ void Z80::Opc_fdcb_e9() { env.wr8(IYd, set(5, env.rd8(IYd))); C = env.rd8(IYd); cycleCount += 23; } /* LD D, SET 5, (IY+d) */ void Z80::Opc_fdcb_ea() { env.wr8(IYd, set(5, env.rd8(IYd))); D = env.rd8(IYd); cycleCount += 23; } /* LD E, SET 5, (IY+d) */ void Z80::Opc_fdcb_eb() { env.wr8(IYd, set(5, env.rd8(IYd))); E = env.rd8(IYd); cycleCount += 23; } /* LD H, SET 5, (IY+d) */ void Z80::Opc_fdcb_ec() { env.wr8(IYd, set(5, env.rd8(IYd))); H = env.rd8(IYd); cycleCount += 23; } /* LD L, SET 5, (IY+d) */ void Z80::Opc_fdcb_ed() { env.wr8(IYd, set(5, env.rd8(IYd))); L = env.rd8(IYd); cycleCount += 23; } /* SET 5, (IY+d) */ void Z80::Opc_fdcb_ee() { env.wr8(IYd, set(5, env.rd8(IYd))); cycleCount += 23; } /* LD A, SET 5, (IY+d) */ void Z80::Opc_fdcb_ef() { env.wr8(IYd, set(5, env.rd8(IYd))); A = env.rd8(IYd); cycleCount += 23; } /* LD B, SET 6, (IY+d) */ void Z80::Opc_fdcb_f0() { env.wr8(IYd, set(6, env.rd8(IYd))); B = env.rd8(IYd); cycleCount += 23; } /* LD C, SET 6, (IY+d) */ void Z80::Opc_fdcb_f1() { env.wr8(IYd, set(6, env.rd8(IYd))); C = env.rd8(IYd); cycleCount += 23; } /* LD D, SET 6, (IY+d) */ void Z80::Opc_fdcb_f2() { env.wr8(IYd, set(6, env.rd8(IYd))); D = env.rd8(IYd); cycleCount += 23; } /* LD E, SET 6, (IY+d) */ void Z80::Opc_fdcb_f3() { env.wr8(IYd, set(6, env.rd8(IYd))); E = env.rd8(IYd); cycleCount += 23; } /* LD H, SET 6, (IY+d) */ void Z80::Opc_fdcb_f4() { env.wr8(IYd, set(6, env.rd8(IYd))); H = env.rd8(IYd); cycleCount += 23; } /* LD L, SET 6, (IY+d) */ void Z80::Opc_fdcb_f5() { env.wr8(IYd, set(6, env.rd8(IYd))); L = env.rd8(IYd); cycleCount += 23; } /* SET 6, (IY+d) */ void Z80::Opc_fdcb_f6() { env.wr8(IYd, set(6, env.rd8(IYd))); cycleCount += 23; } /* LD A, SET 6, (IY+d) */ void Z80::Opc_fdcb_f7() { env.wr8(IYd, set(6, env.rd8(IYd))); A = env.rd8(IYd); cycleCount += 23; } /* LD B, SET 7, (IY+d) */ void Z80::Opc_fdcb_f8() { env.wr8(IYd, set(7, env.rd8(IYd))); B = env.rd8(IYd); cycleCount += 23; } /* LD C, SET 7, (IY+d) */ void Z80::Opc_fdcb_f9() { env.wr8(IYd, set(7, env.rd8(IYd))); C = env.rd8(IYd); cycleCount += 23; } /* LD D, SET 7, (IY+d) */ void Z80::Opc_fdcb_fa() { env.wr8(IYd, set(7, env.rd8(IYd))); D = env.rd8(IYd); cycleCount += 23; } /* LD E, SET 7, (IY+d) */ void Z80::Opc_fdcb_fb() { env.wr8(IYd, set(7, env.rd8(IYd))); E = env.rd8(IYd); cycleCount += 23; } /* LD H, SET 7, (IY+d) */ void Z80::Opc_fdcb_fc() { env.wr8(IYd, set(7, env.rd8(IYd))); H = env.rd8(IYd); cycleCount += 23; } /* LD L, SET 7, (IY+d) */ void Z80::Opc_fdcb_fd() { env.wr8(IYd, set(7, env.rd8(IYd))); L = env.rd8(IYd); cycleCount += 23; } /* SET 7, (IY+d) */ void Z80::Opc_fdcb_fe() { env.wr8(IYd, set(7, env.rd8(IYd))); cycleCount += 23; } /* LD A, SET 7, (IY+d) */ void Z80::Opc_fdcb_ff() { env.wr8(IYd, set(7, env.rd8(IYd))); A = env.rd8(IYd); cycleCount += 23; } Z80::Opc_handler Z80::Opc_fdcb[256] = { &Z80::Opc_fdcb_00, &Z80::Opc_fdcb_01, &Z80::Opc_fdcb_02, &Z80::Opc_fdcb_03, &Z80::Opc_fdcb_04, &Z80::Opc_fdcb_05, &Z80::Opc_fdcb_06, &Z80::Opc_fdcb_07, &Z80::Opc_fdcb_08, &Z80::Opc_fdcb_09, &Z80::Opc_fdcb_0a, &Z80::Opc_fdcb_0b, &Z80::Opc_fdcb_0c, &Z80::Opc_fdcb_0d, &Z80::Opc_fdcb_0e, &Z80::Opc_fdcb_0f, &Z80::Opc_fdcb_10, &Z80::Opc_fdcb_11, &Z80::Opc_fdcb_12, &Z80::Opc_fdcb_13, &Z80::Opc_fdcb_14, &Z80::Opc_fdcb_15, &Z80::Opc_fdcb_16, &Z80::Opc_fdcb_17, &Z80::Opc_fdcb_18, &Z80::Opc_fdcb_19, &Z80::Opc_fdcb_1a, &Z80::Opc_fdcb_1b, &Z80::Opc_fdcb_1c, &Z80::Opc_fdcb_1d, &Z80::Opc_fdcb_1e, &Z80::Opc_fdcb_1f, &Z80::Opc_fdcb_20, &Z80::Opc_fdcb_21, &Z80::Opc_fdcb_22, &Z80::Opc_fdcb_23, &Z80::Opc_fdcb_24, &Z80::Opc_fdcb_25, &Z80::Opc_fdcb_26, &Z80::Opc_fdcb_27, &Z80::Opc_fdcb_28, &Z80::Opc_fdcb_29, &Z80::Opc_fdcb_2a, &Z80::Opc_fdcb_2b, &Z80::Opc_fdcb_2c, &Z80::Opc_fdcb_2d, &Z80::Opc_fdcb_2e, &Z80::Opc_fdcb_2f, &Z80::Opc_fdcb_30, &Z80::Opc_fdcb_31, &Z80::Opc_fdcb_32, &Z80::Opc_fdcb_33, &Z80::Opc_fdcb_34, &Z80::Opc_fdcb_35, &Z80::Opc_fdcb_36, &Z80::Opc_fdcb_37, &Z80::Opc_fdcb_38, &Z80::Opc_fdcb_39, &Z80::Opc_fdcb_3a, &Z80::Opc_fdcb_3b, &Z80::Opc_fdcb_3c, &Z80::Opc_fdcb_3d, &Z80::Opc_fdcb_3e, &Z80::Opc_fdcb_3f, &Z80::Opc_fdcb_40, &Z80::Opc_fdcb_41, &Z80::Opc_fdcb_42, &Z80::Opc_fdcb_43, &Z80::Opc_fdcb_44, &Z80::Opc_fdcb_45, &Z80::Opc_fdcb_46, &Z80::Opc_fdcb_47, &Z80::Opc_fdcb_48, &Z80::Opc_fdcb_49, &Z80::Opc_fdcb_4a, &Z80::Opc_fdcb_4b, &Z80::Opc_fdcb_4c, &Z80::Opc_fdcb_4d, &Z80::Opc_fdcb_4e, &Z80::Opc_fdcb_4f, &Z80::Opc_fdcb_50, &Z80::Opc_fdcb_51, &Z80::Opc_fdcb_52, &Z80::Opc_fdcb_53, &Z80::Opc_fdcb_54, &Z80::Opc_fdcb_55, &Z80::Opc_fdcb_56, &Z80::Opc_fdcb_57, &Z80::Opc_fdcb_58, &Z80::Opc_fdcb_59, &Z80::Opc_fdcb_5a, &Z80::Opc_fdcb_5b, &Z80::Opc_fdcb_5c, &Z80::Opc_fdcb_5d, &Z80::Opc_fdcb_5e, &Z80::Opc_fdcb_5f, &Z80::Opc_fdcb_60, &Z80::Opc_fdcb_61, &Z80::Opc_fdcb_62, &Z80::Opc_fdcb_63, &Z80::Opc_fdcb_64, &Z80::Opc_fdcb_65, &Z80::Opc_fdcb_66, &Z80::Opc_fdcb_67, &Z80::Opc_fdcb_68, &Z80::Opc_fdcb_69, &Z80::Opc_fdcb_6a, &Z80::Opc_fdcb_6b, &Z80::Opc_fdcb_6c, &Z80::Opc_fdcb_6d, &Z80::Opc_fdcb_6e, &Z80::Opc_fdcb_6f, &Z80::Opc_fdcb_70, &Z80::Opc_fdcb_71, &Z80::Opc_fdcb_72, &Z80::Opc_fdcb_73, &Z80::Opc_fdcb_74, &Z80::Opc_fdcb_75, &Z80::Opc_fdcb_76, &Z80::Opc_fdcb_77, &Z80::Opc_fdcb_78, &Z80::Opc_fdcb_79, &Z80::Opc_fdcb_7a, &Z80::Opc_fdcb_7b, &Z80::Opc_fdcb_7c, &Z80::Opc_fdcb_7d, &Z80::Opc_fdcb_7e, &Z80::Opc_fdcb_7f, &Z80::Opc_fdcb_80, &Z80::Opc_fdcb_81, &Z80::Opc_fdcb_82, &Z80::Opc_fdcb_83, &Z80::Opc_fdcb_84, &Z80::Opc_fdcb_85, &Z80::Opc_fdcb_86, &Z80::Opc_fdcb_87, &Z80::Opc_fdcb_88, &Z80::Opc_fdcb_89, &Z80::Opc_fdcb_8a, &Z80::Opc_fdcb_8b, &Z80::Opc_fdcb_8c, &Z80::Opc_fdcb_8d, &Z80::Opc_fdcb_8e, &Z80::Opc_fdcb_8f, &Z80::Opc_fdcb_90, &Z80::Opc_fdcb_91, &Z80::Opc_fdcb_92, &Z80::Opc_fdcb_93, &Z80::Opc_fdcb_94, &Z80::Opc_fdcb_95, &Z80::Opc_fdcb_96, &Z80::Opc_fdcb_97, &Z80::Opc_fdcb_98, &Z80::Opc_fdcb_99, &Z80::Opc_fdcb_9a, &Z80::Opc_fdcb_9b, &Z80::Opc_fdcb_9c, &Z80::Opc_fdcb_9d, &Z80::Opc_fdcb_9e, &Z80::Opc_fdcb_9f, &Z80::Opc_fdcb_a0, &Z80::Opc_fdcb_a1, &Z80::Opc_fdcb_a2, &Z80::Opc_fdcb_a3, &Z80::Opc_fdcb_a4, &Z80::Opc_fdcb_a5, &Z80::Opc_fdcb_a6, &Z80::Opc_fdcb_a7, &Z80::Opc_fdcb_a8, &Z80::Opc_fdcb_a9, &Z80::Opc_fdcb_aa, &Z80::Opc_fdcb_ab, &Z80::Opc_fdcb_ac, &Z80::Opc_fdcb_ad, &Z80::Opc_fdcb_ae, &Z80::Opc_fdcb_af, &Z80::Opc_fdcb_b0, &Z80::Opc_fdcb_b1, &Z80::Opc_fdcb_b2, &Z80::Opc_fdcb_b3, &Z80::Opc_fdcb_b4, &Z80::Opc_fdcb_b5, &Z80::Opc_fdcb_b6, &Z80::Opc_fdcb_b7, &Z80::Opc_fdcb_b8, &Z80::Opc_fdcb_b9, &Z80::Opc_fdcb_ba, &Z80::Opc_fdcb_bb, &Z80::Opc_fdcb_bc, &Z80::Opc_fdcb_bd, &Z80::Opc_fdcb_be, &Z80::Opc_fdcb_bf, &Z80::Opc_fdcb_c0, &Z80::Opc_fdcb_c1, &Z80::Opc_fdcb_c2, &Z80::Opc_fdcb_c3, &Z80::Opc_fdcb_c4, &Z80::Opc_fdcb_c5, &Z80::Opc_fdcb_c6, &Z80::Opc_fdcb_c7, &Z80::Opc_fdcb_c8, &Z80::Opc_fdcb_c9, &Z80::Opc_fdcb_ca, &Z80::Opc_fdcb_cb, &Z80::Opc_fdcb_cc, &Z80::Opc_fdcb_cd, &Z80::Opc_fdcb_ce, &Z80::Opc_fdcb_cf, &Z80::Opc_fdcb_d0, &Z80::Opc_fdcb_d1, &Z80::Opc_fdcb_d2, &Z80::Opc_fdcb_d3, &Z80::Opc_fdcb_d4, &Z80::Opc_fdcb_d5, &Z80::Opc_fdcb_d6, &Z80::Opc_fdcb_d7, &Z80::Opc_fdcb_d8, &Z80::Opc_fdcb_d9, &Z80::Opc_fdcb_da, &Z80::Opc_fdcb_db, &Z80::Opc_fdcb_dc, &Z80::Opc_fdcb_dd, &Z80::Opc_fdcb_de, &Z80::Opc_fdcb_df, &Z80::Opc_fdcb_e0, &Z80::Opc_fdcb_e1, &Z80::Opc_fdcb_e2, &Z80::Opc_fdcb_e3, &Z80::Opc_fdcb_e4, &Z80::Opc_fdcb_e5, &Z80::Opc_fdcb_e6, &Z80::Opc_fdcb_e7, &Z80::Opc_fdcb_e8, &Z80::Opc_fdcb_e9, &Z80::Opc_fdcb_ea, &Z80::Opc_fdcb_eb, &Z80::Opc_fdcb_ec, &Z80::Opc_fdcb_ed, &Z80::Opc_fdcb_ee, &Z80::Opc_fdcb_ef, &Z80::Opc_fdcb_f0, &Z80::Opc_fdcb_f1, &Z80::Opc_fdcb_f2, &Z80::Opc_fdcb_f3, &Z80::Opc_fdcb_f4, &Z80::Opc_fdcb_f5, &Z80::Opc_fdcb_f6, &Z80::Opc_fdcb_f7, &Z80::Opc_fdcb_f8, &Z80::Opc_fdcb_f9, &Z80::Opc_fdcb_fa, &Z80::Opc_fdcb_fb, &Z80::Opc_fdcb_fc, &Z80::Opc_fdcb_fd, &Z80::Opc_fdcb_fe, &Z80::Opc_fdcb_ff }; osmose-emulator-1.4/src/Opc_std.cpp000066400000000000000000001000641341430144300173750ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "Z80.h" #include /* NOP */ void Z80::Opc_std_00() { cycleCount += 4; } /* LD BC,nn */ void Z80::Opc_std_01() { cycleCount += 10; C = env.rd8( PC++ ); B = env.rd8( PC++ ); } /* LD (BC),A */ void Z80::Opc_std_02() { cycleCount += 7; setBCi( A ); } /* INC BC */ void Z80::Opc_std_03() { cycleCount += 6; setBC( getBC() + 1 ); } /* INC B */ void Z80::Opc_std_04() { cycleCount += 4; B = inc8( B ); } /* DEC B */ void Z80::Opc_std_05() { cycleCount += 4; B = dec8( B ); } /* LD B,n */ void Z80::Opc_std_06() { cycleCount += 7; B = env.rd8( PC++ ); } /* RLCA & FF necessary ?*/ void Z80::Opc_std_07() { cycleCount += 4; F = ( F &0xec ) | ( A >> 7 ); /* Outgoing bit is set in carry */ A = (( A << 1 ) | (( A &0x80 ) >> 7 )) &0xff; } /* EX AF, AF1 */ void Z80::Opc_std_08() { //u8 tmp1; cycleCount += 4; u16 tmp1 = A; A = A1; A1 = tmp1; tmp1 = F; F = F1; F1 = tmp1; } /* ADD HL, BC */ void Z80::Opc_std_09() { cycleCount += 11; setHL( add16( getHL(), getBC())); } /* LD A,(BC) */ void Z80::Opc_std_0a() { cycleCount += 7; A = getBCi(); } /* DEC BC */ void Z80::Opc_std_0b() { cycleCount += 6; if ( C-- == 0 ) --B; } /* INC C */ void Z80::Opc_std_0c() { cycleCount += 4; C = inc8( C ); } /* DEC C */ void Z80::Opc_std_0d() { cycleCount += 4; C = dec8( C ); } /* LD C,n */ void Z80::Opc_std_0e() { cycleCount += 7; C = env.rd8( PC++ ); } /* RRCA & FF necessary ?*/ void Z80::Opc_std_0f() { cycleCount += 4; F = ( F &0xec ) | ( A &0x29 ); /* Outgoing bit 0 set to carry */ A = (( A >> 1 ) | (( A &1 ) << 7 )) &0xff; } /* DJNZ */ void Z80::Opc_std_10() { B = ( B - 1 ) &0xff; if ( B != 0 ) { cycleCount += 13; PC += (s8)env.rd8(PC); PC++; } else { cycleCount += 8; PC++; } } /* LD DE,nn */ void Z80::Opc_std_11() { cycleCount += 10; E = env.rd8( PC++ ); D = env.rd8( PC++ ); } /* LD (DE),A */ void Z80::Opc_std_12() { cycleCount += 7; setDEi( A ); } /* INC DE */ void Z80::Opc_std_13() { cycleCount += 6; setDE( getDE() + 1 ); } /* INC D */ void Z80::Opc_std_14() { cycleCount += 4; D = inc8( D ); } /* DEC D */ void Z80::Opc_std_15() { cycleCount += 4; D = dec8( D ); } /* LD D,n */ void Z80::Opc_std_16() { cycleCount += 7; D = env.rd8( PC++ ); } /* RLA */ void Z80::Opc_std_17() { u16 tmp1 = A; cycleCount += 4; A = ( A << 1 ) &0xff; A |= ( F &1 ); /* Get bit 1 from Carry */ F = ( F &0xEC ) | ( tmp1 >> 7 ); /* Save outgoing bit7 in Carry */ } /* JR d */ void Z80::Opc_std_18() { // PC += (s8)env.rd8(PC++); Doesn't work anymore with GCC 4.1.1 // So Split the expression on two differents lines. cycleCount += 12; PC += (s8)env.rd8(PC); PC++; } /* ADD HL, DE */ void Z80::Opc_std_19() { cycleCount += 11; setHL( add16( getHL(), getDE())); } /* LD A,(DE) */ void Z80::Opc_std_1a() { cycleCount += 7; A = getDEi(); } /* DEC DE */ void Z80::Opc_std_1b() { cycleCount += 6; setDE( getDE() - 1 ); } /* INC E */ void Z80::Opc_std_1c() { cycleCount += 4; E = inc8( E ); } /* DEC E */ void Z80::Opc_std_1d() { cycleCount += 4; E = dec8( E ); } /* LD E,n */ void Z80::Opc_std_1e() { cycleCount += 7; E = env.rd8( PC++ ); } /* RRA */ void Z80::Opc_std_1f() { u16 tmp1 = A; /* Save value */ A = (( A >> 1 ) | (( F &1 ) << 7 )); /* Set carry into Accu. bit7 */ F = ( F &0xEC ) | ( tmp1 &1 ); /* Carry = outgoing A bit0 */ cycleCount += 4; } /* JR NZ,n */ void Z80::Opc_std_20() { if (!(F & ZF)) { PC += (s8)env.rd8( PC ); cycleCount += 12; // Mame timing. } else { cycleCount += 7; } PC++; } /* LD HL,nn */ void Z80::Opc_std_21() { cycleCount += 10; L = env.rd8( PC++ ); H = env.rd8( PC++ ); } /* LD (nn),HL */ void Z80::Opc_std_22() { cycleCount += 16; setNNi16( getHL()); PC += 2; } /* INC HL */ void Z80::Opc_std_23() { cycleCount += 6; if (++L == 0) ++H; // HL++ } /* INC H */ void Z80::Opc_std_24() { cycleCount += 4; H = inc8( H ); } /* DEC H */ void Z80::Opc_std_25() { cycleCount += 4; H = dec8( H ); } /* LD H,n */ void Z80::Opc_std_26() { cycleCount += 7; H = env.rd8( PC++ ); } /* DAA */ void Z80::Opc_std_27() { u8 t1 = A; u8 t2 = 0; u8 t3 = ( F &1 ); u8 t = t3; cycleCount += 4; if ((( F &0x10 ) != 0 ) || (( t1 &0x0f ) > 0x09 )) { t2 |= 0x06; } if (( t3 == 1 ) || ( t1 > 0x9f ) || (( t1 > 0x8f ) && (( t1 &0x0f ) > 0x09 ))) { t2 |= 0x60; t = 1; } if ( t1 > 0x99 ) { t = 1; } if (( F &0x02 ) != 0 ) { A = sub8( A, t2 ); } else { A = add8( A, t2 ); } F = ( F &0xfe ) | t; F = ( F &0xfb ); F |= PF_[A]; } /* JR Z,d */ void Z80::Opc_std_28() { if (( F & ZF ) != 0 ) { cycleCount += 12; PC += (s8)env.rd8( PC ); PC++; } else { cycleCount += 7; PC++; } } /* ADD HL,HL */ void Z80::Opc_std_29() { cycleCount += 11; setHL( add16( getHL(), getHL())); } /* LD HL,nn */ void Z80::Opc_std_2a() { cycleCount += 16; setHL( getNNi16()); PC += 2; } /* DEC HL */ void Z80::Opc_std_2b() { cycleCount += 6; setHL( getHL() - 1 ); } /* INC L */ void Z80::Opc_std_2c() { cycleCount += 4; L = inc8( L ); } /* DEC L */ void Z80::Opc_std_2d() { cycleCount += 4; L = dec8( L ); } /* LD L,n */ void Z80::Opc_std_2e() { cycleCount += 7; L = env.rd8( PC++ ); } /* CPL */ void Z80::Opc_std_2f() { cycleCount += 4; A ^= 0xff; /* Invert all bits */ F = (( F &0xc5 ) | 0x12 | ( A &0x28 )); /* Undoc bits set */ } /* JR NC,d */ void Z80::Opc_std_30() { if (( F &CF ) == 0 ) { cycleCount += 12; PC += (s8)env.rd8( PC ); PC++; } else { cycleCount += 7; PC++; } } /* LD SP,nn */ void Z80::Opc_std_31() { cycleCount += 10; SP = env.rd16( PC ); PC += 2; } /* LD (nn),a */ void Z80::Opc_std_32() { cycleCount += 13; setNNi8( A ); PC += 2; } /* INC SP */ void Z80::Opc_std_33() { cycleCount += 6; SP++; } /* INC (HL) */ void Z80::Opc_std_34() { cycleCount += 11; setHLi( inc8( getHLi())); } /* DEC (HL) */ void Z80::Opc_std_35() { cycleCount += 11; setHLi( dec8( getHLi())); } /* LD (HL),n */ void Z80::Opc_std_36() { cycleCount += 10; setHLi( env.rd8( PC++ )); } /* SCF */ void Z80::Opc_std_37() { cycleCount += 4; F = ( F &0xC4 ) | 1; /* Set Carry */ } /* JR C,d */ void Z80::Opc_std_38() { if (( F &CF ) != 0 ) { cycleCount += 12; PC += (s8)env.rd8( PC ); PC++; } else { cycleCount += 7; PC++; } } /* ADD HL, SP */ void Z80::Opc_std_39() { cycleCount += 11; setHL( add16( getHL(), SP )); } /* LD A,(nn) */ void Z80::Opc_std_3a() { cycleCount += 13; A = getNNi8(); PC += 2; } /* DEC SP */ void Z80::Opc_std_3b() { cycleCount += 6; SP--; } /* INC A */ void Z80::Opc_std_3c() { cycleCount += 4; A = inc8( A ); } /* DEC A */ void Z80::Opc_std_3d() { cycleCount += 4; A = dec8( A ); } /* LD A,n */ void Z80::Opc_std_3e() { cycleCount += 7; A = env.rd8( PC++ ); } /* CCF */ void Z80::Opc_std_3f() { cycleCount += 4; F = (( F &0xc5 ) | (( F &1 ) << 4 ) | ( A &0x28 )) ^ 1; } /* LD B, B */ void Z80::Opc_std_40() { nop(); } /* LD B, C */ void Z80::Opc_std_41() { B = C; cycleCount += 4; } /* LD B, D */ void Z80::Opc_std_42() { B = D; cycleCount += 4; } /* LD B, E */ void Z80::Opc_std_43() { B = E; cycleCount += 4; } /* LD B, H */ void Z80::Opc_std_44() { B = H; cycleCount += 4; } /* LD B, L */ void Z80::Opc_std_45() { B = L; cycleCount += 4; } /* LD B, (HL) */ void Z80::Opc_std_46() { B = getHLi(); cycleCount += 7; } /* LD B, A */ void Z80::Opc_std_47() { B = A; cycleCount += 4; } /* LD C, B */ void Z80::Opc_std_48() { C = B; cycleCount += 4; } /* LD C, C */ void Z80::Opc_std_49() { nop(); } /* LD C, D */ void Z80::Opc_std_4a() { C = D; cycleCount += 4; } /* LD C, E */ void Z80::Opc_std_4b() { C = E; cycleCount += 4; } /* LD C, H */ void Z80::Opc_std_4c() { C = H; cycleCount += 4; } /* LD C, L */ void Z80::Opc_std_4d() { C = L; cycleCount += 4; } /* LD C, (HL) */ void Z80::Opc_std_4e() { C = getHLi(); cycleCount += 7; } /* LD C, A */ void Z80::Opc_std_4f() { C = A; cycleCount += 4; } /* LD D, B */ void Z80::Opc_std_50() { D = B; cycleCount += 4; } /* LD D, C */ void Z80::Opc_std_51() { D = C; cycleCount += 4; } /* LD D, D */ void Z80::Opc_std_52() { nop(); } /* LD D, E */ void Z80::Opc_std_53() { D = E; cycleCount += 4; } /* LD D, H */ void Z80::Opc_std_54() { D = H; cycleCount += 4; } /* LD D, L */ void Z80::Opc_std_55() { D = L; cycleCount += 4; } /* LD D, (HL) */ void Z80::Opc_std_56() { D = getHLi(); cycleCount += 7; } /* LD D, A */ void Z80::Opc_std_57() { D = A; cycleCount += 4; } /* LD E, B */ void Z80::Opc_std_58() { E = B; cycleCount += 4; } /* LD E, C */ void Z80::Opc_std_59() { E = C; cycleCount += 4; } /* LD E, D */ void Z80::Opc_std_5a() { E = D; cycleCount += 4; } /* LD E, E */ void Z80::Opc_std_5b() { nop(); } /* LD E, H */ void Z80::Opc_std_5c() { E = H; cycleCount += 4; } /* LD E, L */ void Z80::Opc_std_5d() { E = L; cycleCount += 4; } /* LD E, (HL) */ void Z80::Opc_std_5e() { E = getHLi(); cycleCount += 7; } /* LD E, A */ void Z80::Opc_std_5f() { E = A; cycleCount += 4; } /* LD H, B */ void Z80::Opc_std_60() { H = B; cycleCount += 4; } /* LD H, C */ void Z80::Opc_std_61() { H = C; cycleCount += 4; } /* LD H, D */ void Z80::Opc_std_62() { H = D; cycleCount += 4; } /* LD H, E */ void Z80::Opc_std_63() { H = E; cycleCount += 4; } /* LD H, H */ void Z80::Opc_std_64() { nop(); } /* LD H, L */ void Z80::Opc_std_65() { H = L; cycleCount += 4; } /* LD H, (HL) */ void Z80::Opc_std_66() { H = getHLi(); cycleCount += 7; } /* LD H, A */ void Z80::Opc_std_67() { H = A; cycleCount += 4; } /* LD L, B */ void Z80::Opc_std_68() { L = B; cycleCount += 4; } /* LD L, C */ void Z80::Opc_std_69() { L = C; cycleCount += 4; } /* LD L, D */ void Z80::Opc_std_6a() { L = D; cycleCount += 4; } /* LD L, E */ void Z80::Opc_std_6b() { L = E; cycleCount += 4; } /* LD L, H */ void Z80::Opc_std_6c() { L = H; cycleCount += 4; } /* LD L, L */ void Z80::Opc_std_6d() { nop(); } /* LD L, (HL) */ void Z80::Opc_std_6e() { L = getHLi(); cycleCount += 7; } /* LD L, A */ void Z80::Opc_std_6f() { L = A; cycleCount += 4; } /* LD (HL), B */ void Z80::Opc_std_70() { setHLi(B); cycleCount += 7; } /* LD (HL), C */ void Z80::Opc_std_71() { setHLi(C); cycleCount += 7; } /* LD (HL), D */ void Z80::Opc_std_72() { setHLi(D); cycleCount += 7; } /* LD (HL), E */ void Z80::Opc_std_73() { setHLi(E); cycleCount += 7; } /* LD (HL), H */ void Z80::Opc_std_74() { setHLi(H); cycleCount += 7; } /* LD (HL), L */ void Z80::Opc_std_75() { setHLi(L); cycleCount += 7; } /* HALT */ void Z80::Opc_std_76() { cycleCount += 4; cpuHalted = true; /* Put CPU in Halted state */ } /* LD (HL), A */ void Z80::Opc_std_77() { setHLi(A); cycleCount += 7; } /* LD A, B */ void Z80::Opc_std_78() { A = B; cycleCount += 4; } /* LD A, C */ void Z80::Opc_std_79() { A = C; cycleCount += 4; } /* LD A, D */ void Z80::Opc_std_7a() { A = D; cycleCount += 4; } /* LD A, E */ void Z80::Opc_std_7b() { A = E; cycleCount += 4; } /* LD A, H */ void Z80::Opc_std_7c() { A = H; cycleCount += 4; } /* LD A, L */ void Z80::Opc_std_7d() { A = L; cycleCount += 4; } /* LD A, (HL) */ void Z80::Opc_std_7e() { A = getHLi(); cycleCount += 7; } /* LD A, A */ void Z80::Opc_std_7f() { nop(); } /* ADD B */ void Z80::Opc_std_80() { A = add8(A, B); cycleCount += 4; } /* ADD C */ void Z80::Opc_std_81() { A = add8(A, C); cycleCount += 4; } /* ADD D */ void Z80::Opc_std_82() { A = add8(A, D); cycleCount += 4; } /* ADD E */ void Z80::Opc_std_83() { A = add8(A, E); cycleCount += 4; } /* ADD H */ void Z80::Opc_std_84() { A = add8(A, H); cycleCount += 4; } /* ADD L */ void Z80::Opc_std_85() { A = add8(A, L); cycleCount += 4; } /* ADD (HL) */ void Z80::Opc_std_86() { A = add8(A, getHLi()); cycleCount += 7; } /* ADD A */ void Z80::Opc_std_87() { A = add8(A, A); cycleCount += 4; } /* ADC B */ void Z80::Opc_std_88() { A = adc8(A, B); cycleCount += 4; } /* ADC C */ void Z80::Opc_std_89() { A = adc8(A, C); cycleCount += 4; } /* ADC D */ void Z80::Opc_std_8a() { A = adc8(A, D); cycleCount += 4; } /* ADC E */ void Z80::Opc_std_8b() { A = adc8(A, E); cycleCount += 4; } /* ADC H */ void Z80::Opc_std_8c() { A = adc8(A, H); cycleCount += 4; } /* ADC L */ void Z80::Opc_std_8d() { A = adc8(A, L); cycleCount += 4; } /* ADC (HL) */ void Z80::Opc_std_8e() { A = adc8(A, getHLi()); cycleCount += 7; } /* ADC A */ void Z80::Opc_std_8f() { A = adc8(A, A); cycleCount += 4; } /* SUB B */ void Z80::Opc_std_90() { A = sub8(A, B); cycleCount += 4; } /* SUB C */ void Z80::Opc_std_91() { A = sub8(A, C); cycleCount += 4; } /* SUB D */ void Z80::Opc_std_92() { A = sub8(A, D); cycleCount += 4; } /* SUB E */ void Z80::Opc_std_93() { A = sub8(A, E); cycleCount += 4; } /* SUB H */ void Z80::Opc_std_94() { A = sub8(A, H); cycleCount += 4; } /* SUB L */ void Z80::Opc_std_95() { A = sub8(A, L); cycleCount += 4; } /* SUB (HL) */ void Z80::Opc_std_96() { A = sub8(A, getHLi()); cycleCount += 7; } /* SUB A */ void Z80::Opc_std_97() { A = sub8(A, A); cycleCount += 4; } /* SBC B */ void Z80::Opc_std_98() { A = sbc8(A, B); cycleCount += 4; } /* SBC C */ void Z80::Opc_std_99() { A = sbc8(A, C); cycleCount += 4; } /* SBC D */ void Z80::Opc_std_9a() { A = sbc8(A, D); cycleCount += 4; } /* SBC E */ void Z80::Opc_std_9b() { A = sbc8(A, E); cycleCount += 4; } /* SBC H */ void Z80::Opc_std_9c() { A = sbc8(A, H); cycleCount += 4; } /* SBC L */ void Z80::Opc_std_9d() { A = sbc8(A, L); cycleCount += 4; } /* SBC (HL) */ void Z80::Opc_std_9e() { A = sbc8(A, getHLi()); cycleCount += 7; } /* SBC A */ void Z80::Opc_std_9f() { A = sbc8(A, A); cycleCount += 4; } /* AND B */ void Z80::Opc_std_a0() { A = and8(A, B); cycleCount += 4; } /* AND C */ void Z80::Opc_std_a1() { A = and8(A, C); cycleCount += 4; } /* AND D */ void Z80::Opc_std_a2() { A = and8(A, D); cycleCount += 4; } /* AND E */ void Z80::Opc_std_a3() { A = and8(A, E); cycleCount += 4; } /* AND H */ void Z80::Opc_std_a4() { A = and8(A, H); cycleCount += 4; } /* AND L */ void Z80::Opc_std_a5() { A = and8(A, L); cycleCount += 4; } /* AND (HL) */ void Z80::Opc_std_a6() { A = and8(A, getHLi()); cycleCount += 7; } /* AND A */ void Z80::Opc_std_a7() { A = and8(A, A); cycleCount += 4; } /* XOR B */ void Z80::Opc_std_a8() { A = xor8(A, B); cycleCount += 4; } /* XOR C */ void Z80::Opc_std_a9() { A = xor8(A, C); cycleCount += 4; } /* XOR D */ void Z80::Opc_std_aa() { A = xor8(A, D); cycleCount += 4; } /* XOR E */ void Z80::Opc_std_ab() { A = xor8(A, E); cycleCount += 4; } /* XOR H */ void Z80::Opc_std_ac() { A = xor8(A, H); cycleCount += 4; } /* XOR L */ void Z80::Opc_std_ad() { A = xor8(A, L); cycleCount += 4; } /* XOR (HL) */ void Z80::Opc_std_ae() { A = xor8(A, getHLi()); cycleCount += 7; } /* XOR A */ void Z80::Opc_std_af() { A = xor8(A, A); cycleCount += 4; } /* OR B */ void Z80::Opc_std_b0() { A = or8(A, B); cycleCount += 4; } /* OR C */ void Z80::Opc_std_b1() { A = or8(A, C); cycleCount += 4; } /* OR D */ void Z80::Opc_std_b2() { A = or8(A, D); cycleCount += 4; } /* OR E */ void Z80::Opc_std_b3() { A = or8(A, E); cycleCount += 4; } /* OR H */ void Z80::Opc_std_b4() { A = or8(A, H); cycleCount += 4; } /* OR L */ void Z80::Opc_std_b5() { A = or8(A, L); cycleCount += 4; } /* OR (HL) */ void Z80::Opc_std_b6() { A = or8(A, getHLi()); cycleCount += 7; } /* OR A */ void Z80::Opc_std_b7() { A = or8(A, A); cycleCount += 4; } /* CP B */ void Z80::Opc_std_b8() { cp8(A, B); cycleCount += 4; } /* CP C */ void Z80::Opc_std_b9() { cp8(A, C); cycleCount += 4; } /* CP D */ void Z80::Opc_std_ba() { cp8(A, D); cycleCount += 4; } /* CP E */ void Z80::Opc_std_bb() { cp8(A, E); cycleCount += 4; } /* CP H */ void Z80::Opc_std_bc() { cp8(A, H); cycleCount += 4; } /* CP L */ void Z80::Opc_std_bd() { cp8(A, L); cycleCount += 4; } /* CP (HL) */ void Z80::Opc_std_be() { cp8(A, getHLi()); cycleCount += 7; } /* CP A */ void Z80::Opc_std_bf() { cp8(A, A); cycleCount += 4; } /* RET NZ */ void Z80::Opc_std_c0() { if (( F &ZF ) == 0 ) { cycleCount += 11; PC = pop(); } else { cycleCount += 5; } } /* POP BC */ void Z80::Opc_std_c1() { cycleCount += 10; setBC( pop()); } /* JP NZ */ void Z80::Opc_std_c2() { cycleCount += 10; if (!(F & ZF)) { PC = env.rd16( PC ); } else { PC += 2; } } /* JP nn */ void Z80::Opc_std_c3() { cycleCount += 10; PC = env.rd16( PC ); } /* CALL NZ */ void Z80::Opc_std_c4() { if (( F &ZF ) == 0 ) { cycleCount += 17; push( PC + 2 ); PC = env.rd16( PC ); } else { cycleCount += 10; PC += 2; } } /* PUSH BC */ void Z80::Opc_std_c5() { cycleCount += 11; push( getBC()); } /* ADD A,n */ void Z80::Opc_std_c6() { cycleCount += 7; A = add8( A, env.rd8( PC++ )); } /* RST 0x0 */ void Z80::Opc_std_c7() { rst(0x0); } /* RET Z */ void Z80::Opc_std_c8() { if (( F &ZF ) != 0 ) { cycleCount += 11; PC = pop(); } else { cycleCount += 5; } } /* RET */ void Z80::Opc_std_c9() { cycleCount += 10; PC = pop(); } /* JP Z */ void Z80::Opc_std_ca() { cycleCount += 10; if (( F &ZF ) != 0 ) { PC = env.rd16( PC ); } else { PC += 2; } } /* PREFIXED INSTRUCTION */ void Z80::Opc_std_cb() { exec_cb(); } /* CALL Z */ void Z80::Opc_std_cc() { if (( F &ZF ) != 0 ) { cycleCount += 17; push( PC + 2 ); PC = env.rd16( PC ); } else { cycleCount += 10; PC += 2; } } /* CALL */ void Z80::Opc_std_cd() { cycleCount += 17; push(PC + 2); PC = env.rd16( PC ); } /* ADC A,n */ void Z80::Opc_std_ce() { cycleCount += 7; A = adc8( A, env.rd8( PC++ )); } /* RST 0x8 */ void Z80::Opc_std_cf() { rst(0x8); } /* RET NC */ void Z80::Opc_std_d0() { if (( F &CF ) == 0 ) { cycleCount += 11; PC = pop(); } else { cycleCount += 5; } } /* POP DE */ void Z80::Opc_std_d1() { cycleCount += 10; setDE(pop()); } /* JP NC,nn */ void Z80::Opc_std_d2() { cycleCount += 10; if (( F &CF ) == 0 ) { PC = env.rd16( PC ); } else { PC += 2; } } /* OUT N, A */ void Z80::Opc_std_d3() { cycleCount += 11; env.out( env.rd8( PC++ ), A ); } /* CALL NC */ void Z80::Opc_std_d4() { if (( F & CF ) == 0 ) { cycleCount += 17; push( PC + 2 ); PC = env.rd16( PC ); } else { cycleCount += 10; PC += 2; } } /* PUSH DE */ void Z80::Opc_std_d5() { cycleCount += 11; push( getDE()); } /* SUB A,n */ void Z80::Opc_std_d6() { cycleCount += 7; A = sub8( A, env.rd8( PC++ )); } /* RST 0x10 */ void Z80::Opc_std_d7() { rst(0x10); } /* RET C */ void Z80::Opc_std_d8() { if (( F & CF ) != 0 ) { cycleCount += 11; PC = pop(); } else { cycleCount += 5; } } /* EXX */ void Z80::Opc_std_d9() { u16 tmp1 = B; B = B1; B1 = tmp1; tmp1 = C; C = C1; C1 = tmp1; tmp1 = D; D = D1; D1 = tmp1; tmp1 = E; E = E1; E1 = tmp1; tmp1 = H; H = H1; H1 = tmp1; tmp1 = L; L = L1; L1 = tmp1; cycleCount += 4; } /* JP C */ void Z80::Opc_std_da() { cycleCount += 10; if (( F &CF ) != 0 ) { PC = env.rd16( PC ); } else { PC += 2; } } /* IN A,n */ void Z80::Opc_std_db() { cycleCount += 11; A = env.in((u16)( ( A << 8 ) | env.rd8( PC++ ))); } /* CALL C */ void Z80::Opc_std_dc() { if (( F &CF ) != 0 ) { cycleCount += 17; push( PC + 2 ); PC = env.rd16( PC ); } else { cycleCount += 10; PC += 2; } } /* PREFIXED INSTRUCTION */ void Z80::Opc_std_dd() { exec_dd(); } /* SBC A,n */ void Z80::Opc_std_de() { cycleCount += 7; A = sbc8( A, env.rd8( PC++ )); } /* RST 0x18 */ void Z80::Opc_std_df() { rst(0x18); } /* RET PO */ void Z80::Opc_std_e0() { if (( F & PF ) == 0 ) { cycleCount += 11; PC = pop(); } else { cycleCount += 5; } } /* POP HL */ void Z80::Opc_std_e1() { cycleCount += 10; setHL(pop()); } /* JP PO */ void Z80::Opc_std_e2() { cycleCount += 10; if ((F & PF) == 0 ) { PC = env.rd16( PC ); } else { PC += 2; } } /* EX (SP), HL */ void Z80::Opc_std_e3() { cycleCount += 19; u16 tmp1 = env.rd16( SP ); env.wr16( SP, getHL()); setHL( tmp1 ); } /* CALL PO */ void Z80::Opc_std_e4() { if (( F &PF ) == 0 ) { cycleCount += 17; push( PC + 2 ); PC = env.rd16( PC ); } else { cycleCount += 10; PC += 2; } } /* PUSH HL */ void Z80::Opc_std_e5() { cycleCount += 11; push(getHL()); } /* AND A,n */ void Z80::Opc_std_e6() { cycleCount += 7; A = and8( A, env.rd8( PC++ )); } /* RST 0x20 */ void Z80::Opc_std_e7() { rst(0x20); } /* RET PE */ void Z80::Opc_std_e8() { if (( F &PF ) != 0 ) { cycleCount += 11; PC = pop(); } else { cycleCount += 5; } } /* LD PC, HL or JP HL */ void Z80::Opc_std_e9() { cycleCount += 4; /* SEE MANUAL */ PC = getHL(); /* JMP HL_value, not (HL) */ } /* JP PE */ void Z80::Opc_std_ea() { cycleCount += 10; if (( F &PF ) != 0 ) { PC = env.rd16( PC ); } else { PC += 2; } } /* EX DE, HL */ void Z80::Opc_std_eb() { u16 tmp1 = getDE(); setDE( getHL()); setHL( tmp1 ); cycleCount += 4; } /* CALL PE */ void Z80::Opc_std_ec() { if (( F &PF ) != 0 ) { cycleCount += 17; push( PC + 2 ); PC = env.rd16( PC ); } else { cycleCount += 10; PC += 2; } } /* PREFIXED INSTRUCTION */ void Z80::Opc_std_ed() { exec_ed(); } /* XOR A,n */ void Z80::Opc_std_ee() { cycleCount += 7; A = xor8( A, env.rd8( PC++ )); } /* RST 0x28 */ void Z80::Opc_std_ef() { rst(0x28); } /* RET P */ void Z80::Opc_std_f0() { if (( F &SF ) == 0 ) { cycleCount += 11; PC = pop(); } else { cycleCount += 5; } } /* POP AF */ void Z80::Opc_std_f1() { cycleCount += 10; setAF( pop()); } /* JP P */ void Z80::Opc_std_f2() { cycleCount += 10; if (!(F & SF)) { PC = env.rd16( PC ); } else { PC += 2; } } /* DI */ void Z80::Opc_std_f3() { cycleCount += 4; IFF1 = false; IFF2 = false; #ifdef BUILT_IN_DEBUGGER throwDebugEvent(DbgEvtCpuDisableInterrupt, "CPU", "Interrupt Disabled (DI)."); #endif } /* CALL P */ void Z80::Opc_std_f4() { if (( F &SF ) == 0 ) { cycleCount += 17; push( PC + 2 ); PC = env.rd16( PC ); } else { cycleCount += 10; PC += 2; } } /* PUSH AF */ void Z80::Opc_std_f5() { cycleCount += 11; push(getAF()); } /* OR A,n */ void Z80::Opc_std_f6() { cycleCount += 7; A = or8( A, env.rd8( PC++ )); } /* RST 0x30 */ void Z80::Opc_std_f7() { rst(0x30); } /* RET M */ void Z80::Opc_std_f8() { if (( F &SF ) != 0 ) { cycleCount += 11; PC = pop(); } else { cycleCount += 5; } } /* LD SP, HL */ void Z80::Opc_std_f9() { cycleCount += 6; SP = getHL(); } /* JP M */ void Z80::Opc_std_fa() { cycleCount += 10; if (F & SF) { PC = env.rd16( PC ); } else { PC += 2; } } /* EI */ void Z80::Opc_std_fb() { static bool executing_ei = false; cycleCount += 4; if ( !executing_ei ) { executing_ei = true; // Zilog doc says exec one instruction before clearing flags. // This is done to exec retn after EI in interrupt routines. step(); executing_ei = false; } IFF1 = true; /* CPU accepts interrupts */ IFF2 = true; env.onInterruptsEnabled(); #ifdef BUILT_IN_DEBUGGER throwDebugEvent(DbgEvtCpuEnableInterrupt, "CPU", "Interrupt Enabled (EI)."); #endif } /* CALL M */ void Z80::Opc_std_fc() { if (( F &SF ) != 0 ) { cycleCount += 17; push( PC + 2 ); PC = env.rd16( PC ); } else { cycleCount += 10; PC += 2; } } /* PREFIXED INSTRUCTION */ void Z80::Opc_std_fd() { exec_fd(); } /* CP A,n */ void Z80::Opc_std_fe() { cycleCount += 7; sub8( A, env.rd8( PC++ )); } /* RST 0x38 */ void Z80::Opc_std_ff() { rst(0x38); } Z80::Opc_handler Z80::Opc_std[256] = { &Z80::Opc_std_00, &Z80::Opc_std_01, &Z80::Opc_std_02, &Z80::Opc_std_03, &Z80::Opc_std_04, &Z80::Opc_std_05, &Z80::Opc_std_06, &Z80::Opc_std_07, &Z80::Opc_std_08, &Z80::Opc_std_09, &Z80::Opc_std_0a, &Z80::Opc_std_0b, &Z80::Opc_std_0c, &Z80::Opc_std_0d, &Z80::Opc_std_0e, &Z80::Opc_std_0f, &Z80::Opc_std_10, &Z80::Opc_std_11, &Z80::Opc_std_12, &Z80::Opc_std_13, &Z80::Opc_std_14, &Z80::Opc_std_15, &Z80::Opc_std_16, &Z80::Opc_std_17, &Z80::Opc_std_18, &Z80::Opc_std_19, &Z80::Opc_std_1a, &Z80::Opc_std_1b, &Z80::Opc_std_1c, &Z80::Opc_std_1d, &Z80::Opc_std_1e, &Z80::Opc_std_1f, &Z80::Opc_std_20, &Z80::Opc_std_21, &Z80::Opc_std_22, &Z80::Opc_std_23, &Z80::Opc_std_24, &Z80::Opc_std_25, &Z80::Opc_std_26, &Z80::Opc_std_27, &Z80::Opc_std_28, &Z80::Opc_std_29, &Z80::Opc_std_2a, &Z80::Opc_std_2b, &Z80::Opc_std_2c, &Z80::Opc_std_2d, &Z80::Opc_std_2e, &Z80::Opc_std_2f, &Z80::Opc_std_30, &Z80::Opc_std_31, &Z80::Opc_std_32, &Z80::Opc_std_33, &Z80::Opc_std_34, &Z80::Opc_std_35, &Z80::Opc_std_36, &Z80::Opc_std_37, &Z80::Opc_std_38, &Z80::Opc_std_39, &Z80::Opc_std_3a, &Z80::Opc_std_3b, &Z80::Opc_std_3c, &Z80::Opc_std_3d, &Z80::Opc_std_3e, &Z80::Opc_std_3f, &Z80::Opc_std_40, &Z80::Opc_std_41, &Z80::Opc_std_42, &Z80::Opc_std_43, &Z80::Opc_std_44, &Z80::Opc_std_45, &Z80::Opc_std_46, &Z80::Opc_std_47, &Z80::Opc_std_48, &Z80::Opc_std_49, &Z80::Opc_std_4a, &Z80::Opc_std_4b, &Z80::Opc_std_4c, &Z80::Opc_std_4d, &Z80::Opc_std_4e, &Z80::Opc_std_4f, &Z80::Opc_std_50, &Z80::Opc_std_51, &Z80::Opc_std_52, &Z80::Opc_std_53, &Z80::Opc_std_54, &Z80::Opc_std_55, &Z80::Opc_std_56, &Z80::Opc_std_57, &Z80::Opc_std_58, &Z80::Opc_std_59, &Z80::Opc_std_5a, &Z80::Opc_std_5b, &Z80::Opc_std_5c, &Z80::Opc_std_5d, &Z80::Opc_std_5e, &Z80::Opc_std_5f, &Z80::Opc_std_60, &Z80::Opc_std_61, &Z80::Opc_std_62, &Z80::Opc_std_63, &Z80::Opc_std_64, &Z80::Opc_std_65, &Z80::Opc_std_66, &Z80::Opc_std_67, &Z80::Opc_std_68, &Z80::Opc_std_69, &Z80::Opc_std_6a, &Z80::Opc_std_6b, &Z80::Opc_std_6c, &Z80::Opc_std_6d, &Z80::Opc_std_6e, &Z80::Opc_std_6f, &Z80::Opc_std_70, &Z80::Opc_std_71, &Z80::Opc_std_72, &Z80::Opc_std_73, &Z80::Opc_std_74, &Z80::Opc_std_75, &Z80::Opc_std_76, &Z80::Opc_std_77, &Z80::Opc_std_78, &Z80::Opc_std_79, &Z80::Opc_std_7a, &Z80::Opc_std_7b, &Z80::Opc_std_7c, &Z80::Opc_std_7d, &Z80::Opc_std_7e, &Z80::Opc_std_7f, &Z80::Opc_std_80, &Z80::Opc_std_81, &Z80::Opc_std_82, &Z80::Opc_std_83, &Z80::Opc_std_84, &Z80::Opc_std_85, &Z80::Opc_std_86, &Z80::Opc_std_87, &Z80::Opc_std_88, &Z80::Opc_std_89, &Z80::Opc_std_8a, &Z80::Opc_std_8b, &Z80::Opc_std_8c, &Z80::Opc_std_8d, &Z80::Opc_std_8e, &Z80::Opc_std_8f, &Z80::Opc_std_90, &Z80::Opc_std_91, &Z80::Opc_std_92, &Z80::Opc_std_93, &Z80::Opc_std_94, &Z80::Opc_std_95, &Z80::Opc_std_96, &Z80::Opc_std_97, &Z80::Opc_std_98, &Z80::Opc_std_99, &Z80::Opc_std_9a, &Z80::Opc_std_9b, &Z80::Opc_std_9c, &Z80::Opc_std_9d, &Z80::Opc_std_9e, &Z80::Opc_std_9f, &Z80::Opc_std_a0, &Z80::Opc_std_a1, &Z80::Opc_std_a2, &Z80::Opc_std_a3, &Z80::Opc_std_a4, &Z80::Opc_std_a5, &Z80::Opc_std_a6, &Z80::Opc_std_a7, &Z80::Opc_std_a8, &Z80::Opc_std_a9, &Z80::Opc_std_aa, &Z80::Opc_std_ab, &Z80::Opc_std_ac, &Z80::Opc_std_ad, &Z80::Opc_std_ae, &Z80::Opc_std_af, &Z80::Opc_std_b0, &Z80::Opc_std_b1, &Z80::Opc_std_b2, &Z80::Opc_std_b3, &Z80::Opc_std_b4, &Z80::Opc_std_b5, &Z80::Opc_std_b6, &Z80::Opc_std_b7, &Z80::Opc_std_b8, &Z80::Opc_std_b9, &Z80::Opc_std_ba, &Z80::Opc_std_bb, &Z80::Opc_std_bc, &Z80::Opc_std_bd, &Z80::Opc_std_be, &Z80::Opc_std_bf, &Z80::Opc_std_c0, &Z80::Opc_std_c1, &Z80::Opc_std_c2, &Z80::Opc_std_c3, &Z80::Opc_std_c4, &Z80::Opc_std_c5, &Z80::Opc_std_c6, &Z80::Opc_std_c7, &Z80::Opc_std_c8, &Z80::Opc_std_c9, &Z80::Opc_std_ca, &Z80::Opc_std_cb, &Z80::Opc_std_cc, &Z80::Opc_std_cd, &Z80::Opc_std_ce, &Z80::Opc_std_cf, &Z80::Opc_std_d0, &Z80::Opc_std_d1, &Z80::Opc_std_d2, &Z80::Opc_std_d3, &Z80::Opc_std_d4, &Z80::Opc_std_d5, &Z80::Opc_std_d6, &Z80::Opc_std_d7, &Z80::Opc_std_d8, &Z80::Opc_std_d9, &Z80::Opc_std_da, &Z80::Opc_std_db, &Z80::Opc_std_dc, &Z80::Opc_std_dd, &Z80::Opc_std_de, &Z80::Opc_std_df, &Z80::Opc_std_e0, &Z80::Opc_std_e1, &Z80::Opc_std_e2, &Z80::Opc_std_e3, &Z80::Opc_std_e4, &Z80::Opc_std_e5, &Z80::Opc_std_e6, &Z80::Opc_std_e7, &Z80::Opc_std_e8, &Z80::Opc_std_e9, &Z80::Opc_std_ea, &Z80::Opc_std_eb, &Z80::Opc_std_ec, &Z80::Opc_std_ed, &Z80::Opc_std_ee, &Z80::Opc_std_ef, &Z80::Opc_std_f0, &Z80::Opc_std_f1, &Z80::Opc_std_f2, &Z80::Opc_std_f3, &Z80::Opc_std_f4, &Z80::Opc_std_f5, &Z80::Opc_std_f6, &Z80::Opc_std_f7, &Z80::Opc_std_f8, &Z80::Opc_std_f9, &Z80::Opc_std_fa, &Z80::Opc_std_fb, &Z80::Opc_std_fc, &Z80::Opc_std_fd, &Z80::Opc_std_fe, &Z80::Opc_std_ff }; osmose-emulator-1.4/src/Options.cpp000066400000000000000000000035041341430144300174360ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "Options.h" #include "MemoryMapper.h" #include // Global emulator options instance. Options opt; EmulatorOptions emu_opt; void Options::reset() { // Setup defaut machine options. WorldVersion = true; // Not japanese sms, Export machine. MachineType = SMS; // Default Machine Type. inputType = DEFAULT_PAD; // Default PAD instead SPORT PAD. acceleration = DEFAULT_ACCELERATION; // Default Paddle acceleration. ntsc = true; // Default NTSC video timing. mapperType = SegaMapper; // No codemaster mapper. irq_hack = false; videoFilter = NEAREST; } void EmulatorOptions::reset() { // Setup defaut emulator options. fullscreen_flag = false; sound = true; bright_palette = true; default_config = true; display_fps = false; tracejoy = false; memset(ini_file,0,512); } osmose-emulator-1.4/src/Options.h000066400000000000000000000041611341430144300171030ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef OPTIONS_H #define OPTIONS_H #include #include #include "Bits.h" #define JAPAN 0 #define EXPORT 1 #define DEFAULT_ACCELERATION 0.5 enum { DEFAULT_PAD = 0, PADDLE = 1, JOYSTICK = 2 }; // Video Filters Enumeration. enum { NEAREST = 0, BILINEAR = 1 }; enum { SMS, GAMEGEAR }; using namespace std; class Options { public: bool WorldVersion; // 0 is Jap, 1 Export machine. int MachineType; // SMS or GameGear ? int inputType; // Input device type. float acceleration; // Paddle acceleration. int mapperType; // Use Sega/Codemaster/Korean Mapper. bool ntsc; // true = ntsc false = pal/secam. bool irq_hack; int videoFilter; // void reset(); }; class EmulatorOptions { public: bool bright_palette; // Bright palette or not ? bool fullscreen_flag; // Emu must run in fullscreen. bool sound; // Emu must emulate SN76489. bool default_config; // Does the emulator use default conf ? bool display_fps; // FPS in Title bar option. char ini_file[512]; // For name of file containing conf. bool tracejoy; void reset(); }; #endif osmose-emulator-1.4/src/OsmoseConfigurationFile.cpp000066400000000000000000000312251341430144300226010ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "OsmoseConfigurationFile.h" /** * Constructor. */ OsmoseConfigurationFile::OsmoseConfigurationFile() { homeDir = OsmoseConfigurationFile::getHomeDirectory(); } /** * Return the user's home directory. It first checks into the pw * structure and then in HOME envirnoment variable. If $HOME exists * it is taken first. */ string OsmoseConfigurationFile::getHomeDirectory() { struct passwd *pw = getpwuid(getuid()); string homeDirectory = string(pw->pw_dir); // If $HOME variable exists, override homeDirectory with its content. string user_home_directory = string (getenv("HOME")); if (!user_home_directory.empty()) { homeDirectory = string(user_home_directory.c_str()); } return homeDirectory; } /** * Destructor. */ OsmoseConfigurationFile::~OsmoseConfigurationFile() { } /** * Load the configuration file. Throws an exception in case of problem. */ void OsmoseConfigurationFile::load() { string fullname = homeDir + "/.osmose-emulator.ini"; ifstream file(fullname.c_str(), ios::in); if (file.is_open() == false ) { string msg = "Unable to load '"; msg = msg + fullname + "' configuration file."; throw string(msg); } // Parse the config file and update members. string line; while ( file.good() ) { getline (file,line); parseLine(line); } file.close(); } /** * Receive a line from configuration file. If it contains a valid identifier * and value, the corresponding member value is updated. Every symbols after * '#' char are considered to be commented out. */ void OsmoseConfigurationFile::parseLine(string &line) { // Remove beginning space and control char if any. while((line[0] <= ' ') && (line.length() != 0)) line.erase(0, 1); // Remove all after '#' char if any. size_t pos = line.find('#', 0); if (pos != string::npos) line.erase(pos); // Remove all control chars in the string. pos = 0; while ((pos < line.length()) && (line.length() > 0)) { while((line[pos] <= ' ') && (pos < line.length())) { line.erase(pos, 1); } pos++; } // Extract identifier from line[0] to char '='. pos = line.find('=', 0); if (pos == string::npos) return; // No '=' char found. string identifier = line.substr(0, pos); // Extract value between two simple quotes. pos = line.find('\'', 0); if (pos == string::npos) return; // No '\'' char found. pos++; // Index of first char after ' size_t pos2 = line.find('\'', pos); if (pos2 == string::npos) return; // No second '\'' char found. string value = line.substr(pos, pos2-pos); updateItem(identifier, value); } /** * This method extract new value and affects it to the concerned identifier. * If identifier is unknown, or value not parsable, an error string is thrown\ * via an exception. */ void OsmoseConfigurationFile::updateItem(string &identifier, string &value) { if (identifier == "ScreenshotPath") { screenshotPath = value; return; } else if (identifier == "SaveStatePath") { saveStatePath = value; return; } else if (identifier == "SoundCapturePath") { soundCapturePath = value; return; } else if (identifier == "TileCapturePath") { tileCapturePath = value; return; } else if (identifier == "BatteryBackedRAMPath") { BBRPath = value; return; } else if (identifier == "JoystickDevice") { joystickDevice = value; return; } // At this point, value is interepreted only as ascii int. // Basic verification. for (unsigned int i=0; i < value.length(); i++) { if ((value[i] < '0' || value[i]>'9') && value[i] != '-') { string msg = "Unable to extract value for "; msg = msg + identifier; msg = msg + " : value is "; msg = msg + value; throw string(msg); } } istringstream iss(value, istringstream::in); int int_value; iss >> int_value; if (identifier == "Player1Up") { setPad(0, UP, int_value); return; } else if (identifier == "Player1Down") { setPad(0, DOWN, int_value); return; } else if (identifier == "Player1Left") { setPad(0, LEFT, int_value); return; } else if (identifier == "Player1Right") { setPad(0, RIGHT, int_value); return; } else if (identifier == "Player1ButtonA") { setPad(0, BUTTON_A, int_value); return; } else if (identifier == "Player1ButtonB") { setPad(0, BUTTON_B, int_value); return; } if (identifier == "Player2Up") { setPad(1, UP, int_value); return; } else if (identifier == "Player2Down") { setPad(1, DOWN, int_value); return; } else if (identifier == "Player2Left") { setPad(1, LEFT, int_value); return; } else if (identifier == "Player2Right") { setPad(1, RIGHT, int_value); return; } else if (identifier == "Player2ButtonA") { setPad(1, BUTTON_A, int_value); return; } else if (identifier == "Player2ButtonB") { setPad(1, BUTTON_B, int_value); return; } else if (identifier == "Pause") { pauseButton = int_value; return; } else if (identifier == "Start") { startButton = int_value; return; } else if (identifier == "Joy0Button0") { joystick0Button[0] = (padKey)int_value; return; } else if (identifier == "Joy0Button1") { joystick0Button[1] = (padKey)int_value; return; } else if (identifier == "Joy0Button2") { joystick0Button[2] = (padKey)int_value; return; } else if (identifier == "Joy0Button3") { joystick0Button[3] = (padKey)int_value; return; } else if (identifier == "Joy0Button4") { joystick0Button[4] = (padKey)int_value; return; } else if (identifier == "Joy0Button5") { joystick0Button[5] = (padKey)int_value; return; } else if (identifier == "Joy0Button6") { joystick0Button[6] = (padKey)int_value; return; } else if (identifier == "Joy0Button7") { joystick0Button[7] = (padKey)int_value; return; } // At this point identifier is unknown ! string msg = "Unknown identifier :"; msg = msg + identifier; throw string(msg); } /** * Save the configuration file. Throws an exception in case of problem. */ void OsmoseConfigurationFile::save() { string fullname = homeDir + "/.osmose-emulator.ini"; ofstream file(fullname.c_str(), ios::out); if (file.is_open() == false ) { string msg = "Unable to write '"; msg = msg + fullname + "' configuration file."; throw string(msg); } else // Default ini file creation { file << "#" << endl << "# Osmose Sega MasterSystem/Gamegear emulator configuration file." << endl; file << "# Identifiers are case sensitive, do not edit this file manually," << endl; file << "# it will be overwritten in case of error or configuration change !" << endl << "#" << endl << endl; file << "ScreenshotPath = '" << screenshotPath << "'" << endl; file << "SaveStatePath = '" << saveStatePath << "'" << endl; file << "SoundCapturePath = '" << soundCapturePath << "'" << endl; file << "TileCapturePath = '" << tileCapturePath << "'" << endl; file << "BatteryBackedRAMPath = '" << BBRPath << "'" << endl << endl; file << "#" << endl << "# Played 1 Pad:" << endl << "#" << endl << endl; file << "Player1Up = '" << (int) pad1[UP] << "'" << endl; file << "Player1Down = '" << (int) pad1[DOWN] << "'" << endl; file << "Player1Left = '" << (int) pad1[LEFT] << "'" << endl; file << "Player1Right = '" << (int) pad1[RIGHT] << "'" << endl; file << "Player1ButtonA = '" << (int) pad1[BUTTON_A] << "'" << endl; file << "Player1ButtonB = '" << (int) pad1[BUTTON_B] << "'" << endl << endl; file << "#" << endl << "# Played 2 Pad:" << endl << "#" << endl << endl; file << "Player2Up = '" << (int) pad2[UP] << "'" << endl; file << "Player2Down = '" << (int) pad2[DOWN] << "'" << endl; file << "Player2Left = '" << (int) pad2[LEFT] << "'" << endl; file << "Player2Right = '" << (int) pad2[RIGHT] << "'" << endl; file << "Player2ButtonA = '" << (int) pad2[BUTTON_A] << "'" << endl; file << "Player2ButtonB = '" << (int) pad2[BUTTON_B] << "'" << endl << endl; file << "#" << endl << "# Pause, Gamer Gear Start :" << endl << "#" << endl << endl; file << "Pause = '" << (int) pauseButton << "'" << endl; file << "Start = '" << (int) startButton << "'" << endl << endl; file << "#" << endl << "# Joystick 0 buttons assignations :" << endl << "#" << endl << endl; for (int i=0; i < MAX_JOYSTICK_BUTTON ; i++) { file << "Joy0Button" << (int) i << " = '"<< (int) joystick0Button[i] << "'" << endl; } file << endl << "#" << endl << "# Joystick Linux device :" << endl << "#" << endl << endl; file << "JoystickDevice = '" << joystickDevice << "'" << endl; } file << endl << endl; file.close(); } /** * Restore Osmose default configuration of Paths and key mapping. */ void OsmoseConfigurationFile::resetToDefault() { saveStatePath = homeDir; soundCapturePath= homeDir; tileCapturePath = homeDir; BBRPath = homeDir; screenshotPath = homeDir; pad1[UP] = 16777235; // Up arrow. pad1[DOWN] = 16777237; // Down arrow. pad1[LEFT] = 16777234; // Left arrow. pad1[RIGHT] = 16777236; // Right arrow. pad1[BUTTON_A] = 90; // Z key. pad1[BUTTON_B] = 88; // X key. pad2[UP] = 56; // KeyPad/Keyboard 8. pad2[DOWN] = 50; // KeyPad/Keyboard 2. pad2[LEFT] = 52; // KeyPad/Keyboard 4. pad2[RIGHT] = 54; // KeyPad/Keyboard 6. pad2[BUTTON_A] = 48; // KeyPad/Keyboard 0. pad2[BUTTON_B] = 16777221; //KeyPad/Keyboard Enter. startButton = 83; // S key. pauseButton = 80; // P key. joystick0Button[0] = P1BUTTON_A; joystick0Button[1] = P1BUTTON_B; joystick0Button[2] = START_GG; joystick0Button[3] = PAUSE_NMI; joystick0Button[4] = UNKNOWN; joystick0Button[5] = UNKNOWN; joystick0Button[6] = UNKNOWN; joystick0Button[7] = UNKNOWN; joystickDevice = string(DEFAULT_JOYSTICK_DEVICE); } /** * Restore Osmose default configuration of Paths and key mapping and save * the configuration file. */ void OsmoseConfigurationFile::createDefautConfigurationFile() { resetToDefault(); save(); } /** * This method associate pad direction or button to a key binding. * Param1 : Pad number 0 = first, other is second pad. * Param2 : Direction or Button enum to map to a QT key. * Param3 : The Qt key ID associated to the pad touch. */ void OsmoseConfigurationFile::setPad(int padNumber, padInput i, unsigned int key) { if (padNumber == 0) { pad1[i] = key; } else { pad2[i] = key; } } /** * This method returns key associated to a pad direction. * Param1 : Pad number 0 = first, other is second pad. * Param2 : Direction or Button enum to map to a QT key. */ int OsmoseConfigurationFile::getPad(int padNumber, padInput i) { if (padNumber == 0) { return pad1[i]; } else { return pad2[i]; } } /** * This method set key associated to a joystick button. * Param1 : button number. * Param2 : SMS equivalent key. */ void OsmoseConfigurationFile::assignJoyButton(int button, padKey assignation) { if (button >=0 && button < MAX_JOYSTICK_BUTTON) { joystick0Button[button] = assignation; } } padKey OsmoseConfigurationFile::getJoyButtonAssignation(int button) { if ((button >=0) && (button < MAX_JOYSTICK_BUTTON)) { return joystick0Button[button]; } return UNKNOWN; } /** * This method convert the key pressed to SMS/GG key pad, depending on * the actual configuration. */ padKey OsmoseConfigurationFile::keyToKeyPad(int key) { if (key == pad1[0]) return P1UP; if (key == pad1[1]) return P1DOWN; if (key == pad1[2]) return P1LEFT; if (key == pad1[3]) return P1RIGHT; if (key == pad1[4]) return P1BUTTON_A; if (key == pad1[5]) return P1BUTTON_B; if (key == pad2[0]) return P2UP; if (key == pad2[1]) return P2DOWN; if (key == pad2[2]) return P2LEFT; if (key == pad2[3]) return P2RIGHT; if (key == pad2[4]) return P2BUTTON_A; if (key == pad2[5]) return P2BUTTON_B; if (key == pauseButton) return PAUSE_NMI; if (key == startButton) return START_GG; return UNKNOWN; } osmose-emulator-1.4/src/OsmoseConfigurationFile.h000066400000000000000000000071361341430144300222520ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef OSMOSECONFIGURATIONFILE_H #define OSMOSECONFIGURATIONFILE_H #include #include #include #include #include #include #include #include #include using namespace std; typedef enum { UP = 0, DOWN, LEFT, RIGHT, BUTTON_A, BUTTON_B } padInput; typedef enum { P1UP = 0, P1DOWN, P1LEFT, P1RIGHT, P1BUTTON_A, P1BUTTON_B, P2UP, P2DOWN, P2LEFT, P2RIGHT, P2BUTTON_A, P2BUTTON_B, START_GG, PAUSE_NMI, SCREENSHOT, SOUNDSHOT, UNKNOWN = 0x80000000 } padKey; #define MAX_JOYSTICK_BUTTON 8 #define DEFAULT_JOYSTICK_DEVICE "/dev/input/js0" class OsmoseConfigurationFile { public: OsmoseConfigurationFile(); void save(); void load(); void createDefautConfigurationFile(); void resetToDefault(); padKey keyToKeyPad(int key); static string getHomeDirectory(); ~OsmoseConfigurationFile(); // Button setters. void setPad(int padNumber, padInput i, unsigned int key); void setPause(unsigned int key){pauseButton = key;} void setStart(unsigned int key){startButton = key;} void assignJoyButton(int button, padKey assignation); // Path setters. void setScreenshotPath(string path) {screenshotPath = path;} void setSoundCapturePath(string path) {soundCapturePath = path;} void setTileCapturePath(string path) {tileCapturePath = path;}; void setBBRPath(string path) {BBRPath = path;}; void setSaveStatePath(string path) {saveStatePath = path;}; // Joystick device setter : void setJoystickDevice(string device) { joystickDevice = device; } // Button getters. int getPad(int padNumber, padInput i); int getPause() {return pauseButton;} int getStart() {return startButton;} padKey getJoyButtonAssignation(int button); // Path getters. string getScreenshotPath() {return screenshotPath;} string getSoundCapturePath() {return soundCapturePath;} string getTileCapturePath() {return tileCapturePath;} string getBBRPath() {return BBRPath;} string getSaveStatePath() {return saveStatePath;} // Joystick device getter : string getJoystickDevice() { return joystickDevice; } protected: private: string homeDir; // Osmose configuration data. string saveStatePath; string soundCapturePath; string tileCapturePath; string BBRPath; string screenshotPath; int pad1[6]; // Keyboard Mapping for P1 pad keys: UP:DOW:LEF:RIG:A:B int pad2[6]; // Keyboard Mapping for P2 pad keys: UP:DOW:LEF:RIG:A:B int startButton; // Keyboard Mapping for Start int pauseButton; // Keyboard Mapping for Pause padKey joystick0Button[MAX_JOYSTICK_BUTTON]; // Joystick button assignation. void parseLine(string &l); void updateItem(string &identifier, string &value); string joystickDevice; }; #endif // OSMOSECONFIGURATIONFILE_H osmose-emulator-1.4/src/OsmoseCore.cpp000066400000000000000000000615561341430144300200740ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include #include "OsmoseCore.h" SN76489 *p; // This method is not from OsmoseCore void sndCallback(void *ud, unsigned char *s, int len); /*--------------------------------------------------------------------*/ /* This method is the OsmoseCore constructor. */ /*--------------------------------------------------------------------*/ OsmoseCore::OsmoseCore(const char *rom_f, unsigned int *output, OsmoseConfigurationFile *conf, pthread_mutex_t *ocm) { osmose_core_mutex = ocm; configuration = conf; buffer = output; nmi = false; sound_shot_toggle = false; snd_started = false; screenshotNbr = 0; tileshotNbr = 0; soundshotNbr = 0; rom_filename = rom_f; gain = 0.00f; opt.reset(); /* Note: After instantiation, opt.MachineType contains SMS or GAMEGEAR type. */ mem = new MemoryMapper(rom_filename, configuration); if (opt.mapperType == CodemasterMapper) mem->setMapperType(CodemasterMapper); if (opt.mapperType == KoreanMapper) mem->setMapperType(KoreanMapper); env = new SmsEnvironment(); cpu = new Z80(*env); p = new SN76489(3579545, 22050); if (opt.MachineType == SMS) { v = new VDP(cpu, opt.ntsc); // Instanciate ntsc or pal SMS VDP. iom = new IOMapper(*v, *p); } else { // Instanciate ntsc (always) GAMEGEAR VDP. Force emulator option too. v = new VDP_GG(cpu, true); opt.ntsc = true; iom = new IOMapper_GG(*v, *p); } env->setIOMapper(iom); env->setMemoryMapper(mem); env->setVDP(v); env->setCPU(cpu); wavW = NULL; game_name = mem->getROMName(); #ifdef BUILT_IN_DEBUGGER dbg = new SmsDebugger(); v->attachDebugEventListener(dbg); this->attachDebugEventListener(dbg); cpu->attachDebugEventListener(dbg); mem->attachDebugEventListener(dbg); iom->attachDebugEventListener(dbg); dasm = new Z80Dasm(*env); dbg->setMemoryMapper(mem); dbg->setEnvironment(env); dbg->setVDP(v); dbg->setIOMapper(iom); dbg->setDasm(dasm); dbg->setCPU(cpu); old_cycles = 0; #endif emu_opt.sound = true; if (emu_opt.sound == true) { try { // The plugdev device is obsolete. Replacing it by "default" made it working with pulseaudio. // Contributed by: Kevin Joly (Kev-J) sndThread = new SoundThread("default", p->getFIFOSoundBuffer()); sndThread->start(); // Start thread, not playing ! string msg = "Creating SoundThread"; QLogWindow::getInstance()->appendLog(msg); } catch(string error) { QLogWindow::getInstance()->appendLog(error); QLogWindow::getInstance()->appendLog("Sound disabled. Sound recording won't work."); sndThread = NULL; emu_opt.sound = false; } } } /*--------------------------------------------------------------------*/ /* This method is the OsmoseCore destructor. */ /*--------------------------------------------------------------------*/ OsmoseCore::~OsmoseCore() { if (wavW != NULL) delete wavW; if (sndThread != NULL) delete sndThread; save_bbr(); /* Save Battery backed memory if needed. */ delete v; delete mem; delete env; delete iom; delete cpu; } /*--------------------------------------------------------------------*/ /* This method performs a reset on all machine components. */ /*--------------------------------------------------------------------*/ void OsmoseCore::reset() { MutexLocker lock(osmose_core_mutex); save_bbr(); cpu->reset(); v->reset(); mem->reset(); iom->reset(); } /*--------------------------------------------------------------------*/ /* This method runs one frame. */ /* Note about frame variable: */ /* This variable is the total number of frame (displayed or not !) */ /* emulated by Osmose. This value is use for speed synchronisation at */ /* 60 Fps. That's why the value is incremented even if the frame isn't*/ /* rendered. */ /*--------------------------------------------------------------------*/ void OsmoseCore::run_frame() { MutexLocker lock(osmose_core_mutex); bool drawline = true; bool played = false; float snd_update = 0; int scanline_number; unsigned int over_cycles = 0; scanline_number = (opt.ntsc == true) ? 262 : 313; // NTSC or PAL if (nmi == true) { cpu->nmi(); nmi = false; } for (v->line=0; v->line < scanline_number; v->line++) { over_cycles = cpu->run(CPU_CYCLES_PER_LINE - over_cycles); if (emu_opt.sound == true) { snd_update+=(float)SND_TOGGLE; // Needed to call update_sound_buffer 367.5/frame played = p->run(1); if ((sound_shot_toggle == true) && (played == true)) { wavW->writeData(p->getLastSample()); } if (snd_update > 1.0f) { played = p->run(1); if (played == true) { snd_update = snd_update - (float)1.0f; } if (sound_shot_toggle == true && played==true) { wavW->writeData(p->getLastSample()); } } } v->update(buffer, drawline); } // For i = 0 to scanline_number //tw->update(buffer, drawline); if ((snd_started == false) && (emu_opt.sound == true)) { // Start playing only if sound buffer is full. // This avoid playing silence on emulator startup. if (!p->getFIFOSoundBuffer()->spaceAvailable()) { snd_started = true; sndThread->resume(); } } // To avoid infinite loop with cycleCounter overflow. cpu->setCycles(0); } /*--------------------------------------------------------------------*/ /* This method will save as bitmap, vdp graphics tiles. */ /* First, a 128x224 SDL_Surface is allocated. */ /* Then tiles are drawn there. */ /* A screenshot is taken */ /* The Surface is freed. */ /* Filename is tiles_rip_ + game_name.bmp. */ /*--------------------------------------------------------------------*/ bool OsmoseCore::captureTiles() { MutexLocker lock(osmose_core_mutex); ostringstream oss; oss << configuration->getTileCapturePath() << "/" << game_name << "-" << tileshotNbr << "_Tiles_Rip.tga"; tileshotNbr++; /* Allocate 128x224 buffer */ unsigned int *local_buffer = new unsigned int[128*224]; unsigned int map_p = 0; /* Render tiles into the buffer. */ // Draw tiles there. for (int o=0; o<28;o++) { for (int i=0; i<16;i++) { int tile = map_p; displayTiles(local_buffer, v, tile, i<<3, o<<3); map_p++; } } /* Save the buffer. */ TGAWriter tgaFile(oss.str().c_str(), 128, 224); if (tgaFile.isOk() == true) { for (int y=223; y>=0; y--) { int index = y * 128; for (int x= 0; x<128; x++) { unsigned char r, g, b; unsigned int d = local_buffer[index++]; b = (d >> 16) & 0xFF; g = (d >> 8) & 0xFF; r = d & 0xFF; tgaFile.writePixel(r, g, b); } } } else { return false; } /* Deallocate buffer. */ delete[] local_buffer; return true; } /*--------------------------------------------------------------------*/ /* This method draws a tile n, at position x,y, assuming that the */ /* Surface is 128 pixels wide. */ /*--------------------------------------------------------------------*/ void OsmoseCore::displayTiles(unsigned int *s, VDP *vd, int tile, int x, int y) { unsigned int *ptr; unsigned char col_index, p0, p1, p2, p3; unsigned int ti, c; ti = tile<<5; ptr = (unsigned int *)s + ((y<<7)+x ); for (int o=0; o<8;o++) { c = (o<<2) + ti; p0 = vd->VRAM[c++]; p1 = vd->VRAM[c++]; p2 = vd->VRAM[c++]; p3 = vd->VRAM[c++]; for (int i=0; i<8;i++) { col_index = (p0 >>7) | (p1 >> 7)<<1 | (p2 >> 7)<<2 | (p3 >> 7)<<3; *(unsigned int *)ptr = vd->colors[col_index]; ptr++; p0<<=1; p1<<=1; p2<<=1; p3<<=1; } ptr += 120; // Complement to next line, based on 256 pixel width. } } /*--------------------------------------------------------------------*/ /* This method is called by SDL sound system, to fill the sound buffer*/ /* s is the place to put sound data, len is length of buffer in bytes.*/ /*--------------------------------------------------------------------*/ void sndCallback(void *, unsigned char *s, int len) { p->getWave(s, len); } /*--------------------------------------------------------------------*/ /* This method takes a screenshot of the game. The filename is */ /* game_name +x .tga , where x is the number of taken screenshot, */ /* which is incremented every time captureScreen() is called. */ /*--------------------------------------------------------------------*/ bool OsmoseCore::captureScreen() { MutexLocker lock(osmose_core_mutex); ostringstream oss; oss << configuration->getScreenshotPath() << "/" << game_name << "-" << screenshotNbr << ".tga"; screenshotNbr++; TGAWriter tgaFile(oss.str().c_str(), 256, 192); if (tgaFile.isOk() == true) { for (int y=191; y>=0; y--) { int index = y * 256; for (int x= 0; x<256; x++) { unsigned char r, g, b; unsigned int d = buffer[index++]; b = (d >> 16) & 0xFF; g = (d >> 8) & 0xFF; r = d & 0xFF; tgaFile.writePixel(r, g, b); } } return true; } else { return false; } } /*--------------------------------------------------------------------*/ /* This method toggles the sound recording on and OFF. The filename */ /* is game_name +x .wav , where x is the number of taken sound shot, */ /* which is incremented every time recordSounds(OFF) is called. */ /* Return : true if operation was successful, false otherwise. */ /*--------------------------------------------------------------------*/ bool OsmoseCore::startRecordingSounds() { MutexLocker lock(osmose_core_mutex); bool retValue = false; ostringstream oss; oss << configuration->getSoundCapturePath() << "/" << game_name << "-" << soundshotNbr << ".wav"; wavW = new WaveWriter(oss.str().c_str()); if (wavW->isOk()) { soundshotNbr++; sound_shot_toggle = true; retValue = true; } return retValue; } /*--------------------------------------------------------------------*/ /* This method toggles the sound recording on and OFF. The filename */ /* is game_name +x .wav , where x is the number of taken sound shot, */ /* which is incremented every time recordSounds(OFF) is called. */ /* Return : true if operation was successful, false otherwise. */ /*--------------------------------------------------------------------*/ void OsmoseCore::stopRecordingSounds() { MutexLocker lock(osmose_core_mutex); wavW->close(); delete wavW; // To avoid memory leak. wavW = NULL; sound_shot_toggle = false; } /*--------------------------------------------------------------------*/ /* This method generates save state file. Here is the format: */ /* File Offset - Data type. */ /* 0000-0003 unsigned char[4] marker "OESS" */ /* 0004-0007 unsigned char[4] 0 + version that create savestate. */ /* 0008-0019 unsigned char[18] z80_8bits_registers. */ /* 001A-0021 unsigned short[4] z80_16bits_registers. */ /*--------------------------------------------------------------------*/ bool OsmoseCore::saveSaveState(int slot) { MutexLocker lock(osmose_core_mutex); ostringstream save_state_name; save_state_name << configuration->getSaveStatePath() << "/" << mem->getROMName() << "_slot_" << slot <<".sta"; ofstream output_file(save_state_name.str().c_str(), ios::out | ios::binary ); if (output_file.is_open() == false ) { string msg = "Cannot create save state file:" + save_state_name.str(); QLogWindow::getInstance()->appendLog(msg); return false; } /* Write cpu data. */ if (!cpu->saveState( output_file ) ) { string msg = "CPU save failed."; QLogWindow::getInstance()->appendLog(msg); return false; } /* Write memory mapper data. */ if (!mem->saveState( output_file ) ) { string msg = "Mem Mapper save failed."; QLogWindow::getInstance()->appendLog(msg); return false; } /* Write VDP data. */ if (!v->saveState( output_file ) ) { string msg = "VDP save failed."; QLogWindow::getInstance()->appendLog(msg); return false; } /* Write SN76489 data. */ if (!p->saveState( output_file ) ) { string msg = "PSG save failed."; QLogWindow::getInstance()->appendLog(msg); return false; } output_file.close(); string msg = "State saved in file :" + save_state_name.str(); QLogWindow::getInstance()->appendLog(msg); return true; } /*--------------------------------------------------------------------*/ /* This method loads an emulation state previously saved. */ /*--------------------------------------------------------------------*/ bool OsmoseCore::loadSaveState(int slot) { MutexLocker lock(osmose_core_mutex); ostringstream load_state_name; load_state_name << configuration->getSaveStatePath() << "/" << mem->getROMName() << "_slot_" << slot <<".sta"; ifstream input_file(load_state_name.str().c_str(), ios::in | ios::binary); if (input_file.is_open() == false ) { string msg = "Fail to load state from file : " + load_state_name.str(); QLogWindow::getInstance()->appendLog(msg); return false; } /* Load cpu data. */ if (!cpu->loadState( input_file ) ) { string msg = "CPU load failed."; QLogWindow::getInstance()->appendLog(msg); return false; } /* Load memory mapper data. */ if (!mem->loadState( input_file ) ) { string msg = "Mem Mapper load failed."; QLogWindow::getInstance()->appendLog(msg); return false; } /* Load VDP data. */ if (!v->loadState( input_file ) ) { string msg = "VDP load failed."; QLogWindow::getInstance()->appendLog(msg); return false; } /* Save SN76489 data. */ if (!p->loadState( input_file ) ) { string msg = "PSG load failed."; QLogWindow::getInstance()->appendLog(msg); return false; } input_file.close(); string msg = "State loaded from file : " + load_state_name.str(); QLogWindow::getInstance()->appendLog(msg); return true; } /*--------------------------------------------------------------------*/ /* This method saves Battery Backed Memory if needed. */ /*--------------------------------------------------------------------*/ void OsmoseCore::save_bbr() { // No need to lock mutex, method is private and only called via reset or locked method. ostringstream bbr_name; bbr_name << configuration->getBBRPath() << "/" << game_name.c_str() << ".bbr"; mem->save_battery_backed_memory(bbr_name.str()); } /*--------------------------------------------------------------------*/ /* This method is called when P1 Up key changed is triggered. */ /* If parameter pressed is false, it means that key is released, */ /* pressed otherwise. This callback is called whatever the input */ /* device is used. */ /*--------------------------------------------------------------------*/ void OsmoseCore::P1UpChanged(bool pressed) { if (pressed) { iom->portPAD1 &= BIT0_MASK;; } else { // Key released. iom->portPAD1 |= BIT0; } } /*--------------------------------------------------------------------*/ /* This method is called when P1 Down key changed is triggered. */ /* If parameter pressed is false, it means that key is released, */ /* pressed otherwise. This callback is called whatever the input */ /* device is used. */ /*--------------------------------------------------------------------*/ void OsmoseCore::P1DownChanged(bool pressed) { if (pressed) { iom->portPAD1 &= BIT1_MASK;; } else { // Key released. iom->portPAD1 |= BIT1; } } /*--------------------------------------------------------------------*/ /* This method is called when P1 Left key changed is triggered. */ /* If parameter pressed is false, it means that key is released, */ /* pressed otherwise. This callback is called whatever the input */ /* device is used. */ /*--------------------------------------------------------------------*/ void OsmoseCore::P1LeftChanged(bool pressed) { if (pressed) { iom->portPAD1 &= BIT2_MASK;; } else { // Key released. iom->portPAD1 |= BIT2; } } /*--------------------------------------------------------------------*/ /* This method is called when P1 right key changed is triggered. */ /* If parameter pressed is false, it means that key is released, */ /* pressed otherwise. This callback is called whatever the input */ /* device is used. */ /*--------------------------------------------------------------------*/ void OsmoseCore::P1RightChanged(bool pressed) { if (pressed) { iom->portPAD1 &= BIT3_MASK;; } else { // Key released. iom->portPAD1 |= BIT3; } } /*--------------------------------------------------------------------*/ /* This method is called when P1 A key changed is triggered. */ /* If parameter pressed is false, it means that key is released, */ /* pressed otherwise. This callback is called whatever the input */ /* device is used. */ /*--------------------------------------------------------------------*/ void OsmoseCore::P1AButtonChanged(bool pressed) { if (pressed) { iom->portPAD1 &= BIT4_MASK;; } else { // Key released. iom->portPAD1 |= BIT4; } } /*--------------------------------------------------------------------*/ /* This method is called when P1 B key changed is triggered. */ /* If parameter pressed is false, it means that key is released, */ /* pressed otherwise. This callback is called whatever the input */ /* device is used. */ /*--------------------------------------------------------------------*/ void OsmoseCore::P1BButtonChanged(bool pressed) { if (pressed) { iom->portPAD1 &= BIT5_MASK;; } else { // Key released. iom->portPAD1 |= BIT5; } } /*--------------------------------------------------------------------*/ /* This method is called when P2 Up key changed is triggered. */ /* If parameter pressed is false, it means that key is released, */ /* pressed otherwise. This callback is called whatever the input */ /* device is used. */ /*--------------------------------------------------------------------*/ void OsmoseCore::P2UpChanged(bool pressed) { if (pressed) { iom->portPAD1 &= BIT6_MASK;; } else { // Key released. iom->portPAD1 |= BIT6; } } /*--------------------------------------------------------------------*/ /* This method is called when P2 Down key changed is triggered. */ /* If parameter pressed is false, it means that key is released, */ /* pressed otherwise. This callback is called whatever the input */ /* device is used. */ /*--------------------------------------------------------------------*/ void OsmoseCore::P2DownChanged(bool pressed) { if (pressed) { iom->portPAD1 &= BIT7_MASK;; } else { // Key released. iom->portPAD1 |= BIT7; } } /*--------------------------------------------------------------------*/ /* This method is called when P2 Left key changed is triggered. */ /* If parameter pressed is false, it means that key is released, */ /* pressed otherwise. This callback is called whatever the input */ /* device is used. */ /*--------------------------------------------------------------------*/ void OsmoseCore::P2LeftChanged(bool pressed) { if (pressed) { iom->portPAD2 &= BIT0_MASK;; } else { // Key released. iom->portPAD2 |= BIT0; } } /*--------------------------------------------------------------------*/ /* This method is called when P2 right key changed is triggered. */ /* If parameter pressed is false, it means that key is released, */ /* pressed otherwise. This callback is called whatever the input */ /* device is used. */ /*--------------------------------------------------------------------*/ void OsmoseCore::P2RightChanged(bool pressed) { if (pressed) { iom->portPAD2 &= BIT1_MASK;; } else { // Key released. iom->portPAD2 |= BIT1; } } /*--------------------------------------------------------------------*/ /* This method is called when P2 A key changed is triggered. */ /* If parameter pressed is false, it means that key is released, */ /* pressed otherwise. This callback is called whatever the input */ /* device is used. */ /*--------------------------------------------------------------------*/ void OsmoseCore::P2AButtonChanged(bool pressed) { if (pressed) { iom->portPAD2 &= BIT2_MASK;; } else { // Key released. iom->portPAD2 |= BIT2; } } /*--------------------------------------------------------------------*/ /* This method is called when P2 B key changed is triggered. */ /* If parameter pressed is false, it means that key is released, */ /* pressed otherwise. This callback is called whatever the input */ /* device is used. */ /*--------------------------------------------------------------------*/ void OsmoseCore::P2BButtonChanged(bool pressed) { if (pressed) { iom->portPAD2 &= BIT3_MASK;; } else { // Key released. iom->portPAD2 |= BIT3; } } /*--------------------------------------------------------------------*/ /* This method is called when Pause button is triggered. */ /* If parameter pressed is false, it means that key is released, */ /* pressed otherwise. This callback is called whatever the input */ /* device is used. */ /*--------------------------------------------------------------------*/ void OsmoseCore::PauseButtonChanged(bool pressed) { if (pressed) { // Game Gear has no pause button ! if (opt.MachineType == SMS) nmi = true; } else { // No NMIes are triggered on pause released. } } /*--------------------------------------------------------------------*/ /* This method is called when Game Gear Start is triggered. */ /* If parameter pressed is false, it means that key is released, */ /* pressed otherwise. This callback is called whatever the input */ /* device is used. */ /*--------------------------------------------------------------------*/ void OsmoseCore::StartButtonChanged(bool pressed) { // SMS has no start button ! if (opt.MachineType != GAMEGEAR) { return; } if (pressed) { iom->port0x0 &= BIT7_MASK; } else { iom->port0x0 |= BIT7; } } /*--------------------------------------------------------------------*/ /* This method is used to force memory mapper selection. */ /*--------------------------------------------------------------------*/ void OsmoseCore::forceMemoryMapper(Mapper mapper) { MutexLocker lock(osmose_core_mutex); mem->setMapperType(mapper); } /*--------------------------------------------------------------------*/ /* This method is used to force NTSC or PAL timings. */ /* true = NTSC false=PAL */ /*--------------------------------------------------------------------*/ void OsmoseCore::forceNTSCTiming(bool ntsc) { MutexLocker lock(osmose_core_mutex); v->setNTSC(ntsc); } osmose-emulator-1.4/src/OsmoseCore.h000066400000000000000000000103721341430144300175270ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef OSMOSE_CORE_H #define OSMOSE_CORE_H #include #include #include #include #include "Z80.h" #include "SmsEnvironment.h" #include "OsmoseConfigurationFile.h" #include "VDP.h" #include "VDP_GG.h" #include "SN76489.h" #include "Options.h" #include "Bits.h" #include "WaveWriter.h" #include "Version.h" #include "Definitions.h" #include "DebugEventThrower.h" #include "SaveState.h" #include "AnsiColorTerminal.h" #include "EmulationThread.h" #include "TGAWriter.h" #include "QLogWindow.h" #include "Pthreadcpp.h" #include "SoundThread.h" using namespace std; /* Use save state slot from 1 to 5. */ enum { minSaveStateSlot = 1, maxSaveStateSlot = 5 }; class OsmoseCore : public DebugEventThrower { public: OsmoseCore(const char *rom_f, unsigned int *output, OsmoseConfigurationFile *c, pthread_mutex_t *ocm); // Constructor. ~OsmoseCore(); void run_frame(); // Run one Frame. void Reshape(int x, int y); void reset(); // Reset all components. void P1UpChanged(bool pressed); void P1DownChanged(bool pressed); void P1LeftChanged(bool pressed); void P1RightChanged(bool pressed); void P1AButtonChanged(bool pressed); void P1BButtonChanged(bool pressed); void P2UpChanged(bool pressed); void P2DownChanged(bool pressed); void P2LeftChanged(bool pressed); void P2RightChanged(bool pressed); void P2AButtonChanged(bool pressed); void P2BButtonChanged(bool pressed); void PauseButtonChanged(bool pressed); void StartButtonChanged(bool pressed); bool captureScreen(); bool captureTiles(); bool startRecordingSounds(); void stopRecordingSounds(); bool saveSaveState(int slot); bool loadSaveState(int slot); void forceMemoryMapper(Mapper m); void forceNTSCTiming(bool); private: unsigned int *buffer; // SMS screen, without modification 256x192. string game_name; // Used as prefix for screenshot, sound shot and save states. VDP *v; // Video Display Processor object. MemoryMapper *mem; // Memory mapper Object. SmsEnvironment *env; // Z80 Cpu environment. IOMapper *iom; // Input/Output mapper Object. Z80 *cpu; // Our Z80 core. WaveWriter *wavW; // Sound ripper. float gain; // gain level. #ifdef BUILT_IN_DEBUGGER unsigned int old_cycles; // Used for cycle count. Z80Dasm *dasm; // Z80 disasembler object. SmsDebugger *dbg; // Sms Debugger. bool exec_f; // Continue cpu exec Flag. #endif bool nmi; // nmi flag, used with keyboard pause. bool sound_shot_toggle; // Flag, for start/stop recording sound. int screenshotNbr; // Screenshot number appended to save. int tileshotNbr; // Tile rip number appended to save. int soundshotNbr; // Sound rip number appended to save. const char *rom_filename; // Pointer to argv[1]. bool snd_started; void save_bbr(); // Save Battery Backed Ram. void displayTiles(unsigned int *s, VDP *vd, int tile, int x, int y); SoundThread *sndThread; OsmoseConfigurationFile *configuration; pthread_mutex_t *osmose_core_mutex; }; #endif osmose-emulator-1.4/src/OsmoseEmulationThread.cpp000066400000000000000000000076131341430144300222630ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "OsmoseEmulationThread.h" /** * Constructor. */ OsmoseEmulationThread::OsmoseEmulationThread(QGLImage *qglimage, char * romName, OsmoseConfigurationFile *conf, pthread_mutex_t *ocm) : EmulationThread(qglimage) { configuration = conf; setRefreshFrequency(60.0f); frameCounter = 0; mode = 1; osmose_core_mutex = ocm; core = new OsmoseCore(romName, videoBuffer, configuration, osmose_core_mutex); } /** * Destructor. */ OsmoseEmulationThread::~OsmoseEmulationThread() { delete core; } /** * This method perform one frame emulation stuff. The videoBuffer must * be updated inside this method. */ void OsmoseEmulationThread::emulateOneFrame() { core->run_frame(); } /** * This method perform one frame emulation stuff. The videoBuffer must * be updated inside this method. */ void OsmoseEmulationThread::resetEmulation() { core->reset(); } /** * We get a Key Pressed event from the QMainWindow. Handle it. The * conversion from Emulator key mapping and user configuration occurs * here. * * Param 1 : SMS/GG key. * * Return : None. */ void OsmoseEmulationThread::keyPressed(padKey key) { switch(key) { case P1UP: core->P1UpChanged(true); break; case P1DOWN: core->P1DownChanged(true); break; case P1LEFT: core->P1LeftChanged(true); break; case P1RIGHT: core->P1RightChanged(true); break; case P1BUTTON_A:core->P1AButtonChanged(true);break; case P1BUTTON_B:core->P1BButtonChanged(true);break; case P2UP: core->P2UpChanged(true); break; case P2DOWN: core->P2DownChanged(true); break; case P2LEFT: core->P2LeftChanged(true); break; case P2RIGHT: core->P2RightChanged(true); break; case P2BUTTON_A:core->P2AButtonChanged(true);break; case P2BUTTON_B:core->P2BButtonChanged(true);break; case PAUSE_NMI: core->PauseButtonChanged(true);break; case START_GG: core->StartButtonChanged(true);break; case SCREENSHOT: core->captureScreen(); case UNKNOWN : break; default: break; } } /** * We get a Key Released event from the QMainWindow. Handle it. The * conversion from Emulator key mapping and user configuration occurs * here. * * Param 1 : QT key() value of the QKeyEvent that signal keyPressed. * * Return : None. */ void OsmoseEmulationThread::keyReleased(padKey key) { switch(key) { case P1UP: core->P1UpChanged(false); break; case P1DOWN: core->P1DownChanged(false); break; case P1LEFT: core->P1LeftChanged(false); break; case P1RIGHT: core->P1RightChanged(false);break; case P1BUTTON_A:core->P1AButtonChanged(false);break; case P1BUTTON_B:core->P1BButtonChanged(false);break; case P2UP: core->P2UpChanged(false); break; case P2DOWN: core->P2DownChanged(false); break; case P2LEFT: core->P2LeftChanged(false); break; case P2RIGHT: core->P2RightChanged(false); break; case P2BUTTON_A:core->P2AButtonChanged(false);break; case P2BUTTON_B:core->P2BButtonChanged(false);break; case PAUSE_NMI: core->PauseButtonChanged(false);break; case START_GG: core->StartButtonChanged(false);break; case UNKNOWN : break; default: break; } } osmose-emulator-1.4/src/OsmoseEmulationThread.h000066400000000000000000000031671341430144300217300ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef OSMOSE_EMULATION_THREAD_H #define OSMOSE_EMULATION_THREAD_H #include #include #include "EmulationThread.h" #include "Z80.h" #include "OsmoseCore.h" #include "OsmoseConfigurationFile.h" class OsmoseEmulationThread : public EmulationThread { public: OsmoseEmulationThread(QGLImage *qglimage, char *romName, OsmoseConfigurationFile *conf, pthread_mutex_t *ocm); ~OsmoseEmulationThread(); void emulateOneFrame(); void resetEmulation(); void keyPressed(padKey key); void keyReleased(padKey key); OsmoseCore *getCore() {return core;} protected: private: int frameCounter; int mode; OsmoseCore *core; OsmoseConfigurationFile *configuration; pthread_mutex_t *osmose_core_mutex; }; #endif // OSMOSE_EMULATION_THREAD_H osmose-emulator-1.4/src/OsmoseGUI.cpp000066400000000000000000000607271341430144300176270ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include #include #include "OsmoseGUI.h" #include #include /** * Constructor. */ OsmoseGUI::OsmoseGUI(QWidget * parent, Qt::WindowFlags flags) : QMainWindow(parent, flags) { isFullscreen = false; rom_name = NULL; osmoseCore = NULL; saveStateSlot = 0; osmose_core_mutex = PTHREAD_MUTEX_INITIALIZER; this->setWindowTitle(__OSMOSE_VERSION__); this->setWindowIcon(QIcon(":/osmose-emulator.png")); QLogWindow::getInstance()->appendLog("Starting Osmose emulator."); /* Instanciate menus.*/ QMenuBar *mb = menuBar(); QMenu *menu = new QMenu("File"); QAction *action = new QAction("&Open SMS/GG ROM", this); action->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_O)); QObject::connect(action, SIGNAL(triggered()), this, SLOT(loadROM())); menu->addAction(action); action = new QAction("&Configure...", this); QObject::connect(action, SIGNAL(triggered()), this, SLOT(configure())); action->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_C)); menu->addAction(action); action = new QAction("&Log window ...", this); QObject::connect(action, SIGNAL(triggered()), this, SLOT(showLogWindow())); action->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_L)); menu->addAction(action); action = new QAction("E&xit Osmose", this); //QObject::connect(action, SIGNAL(triggered()), qApp, SLOT(quit())); QObject::connect(action, SIGNAL(triggered()), this, SLOT(exitApplication())); action->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_X)); menu->addAction(action); mb->addMenu(menu); QGL::FormatOptions format = QGL::DirectRendering | QGL::DoubleBuffer | QGL::NoDepthBuffer | QGL::NoAlphaChannel | QGL::NoAccumBuffer | QGL::NoStencilBuffer | QGL::NoStereoBuffers | QGL::NoOverlay | QGL::NoSampleBuffers; // Build OpenGL renderer widget. glImage = new QGLImage(this, 256, 192, format); setCentralWidget(glImage); // Build emulation thread. //emuThread = new WhiteNoiseEmulationThread(glImage); emuThread = new WhiteNoiseEmulationThread(glImage); menu = new QMenu("Emulation"); paused = false; pauseResume = new QAction("Pause", this); QObject::connect(pauseResume, SIGNAL(triggered()), this, SLOT(pauseResumeEmulation())); menu->addAction(pauseResume); menu->addSeparator(); action = new QAction("Save VDP &GFX", this); action->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_G)); QObject::connect(action, SIGNAL(triggered()), this, SLOT(saveVDPGFX())); menu->addAction(action); action = new QAction("&Save screenshot", this); action->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_S)); QObject::connect(action, SIGNAL(triggered()), this, SLOT(saveScreenshot())); menu->addAction(action); saveSoundQAction = new QAction("&Wave sound record", this); saveSoundQAction->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_W)); saveSoundQAction->setCheckable(true); saveSoundQAction->setChecked(false); QObject::connect(saveSoundQAction, SIGNAL(triggered()), this, SLOT(saveSound())); menu->addAction(saveSoundQAction); menu->addSeparator(); action = new QAction("Hardware reset", this); action->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_R)); QObject::connect(action, SIGNAL(triggered()), this, SLOT(resetEmulation())); menu->addAction(action); menu->addAction(action); mb->addMenu(menu); menu = new QMenu("Machine"); mb->addMenu(menu); QActionGroup *timingGroup = new QActionGroup(this); ntscQAction = new QAction("NTSC Timing 60hz", this); QObject::connect(ntscQAction, SIGNAL(triggered()), this, SLOT(setNTSCTiming())); ntscQAction->setCheckable(true); ntscQAction->setChecked(true); menu->addAction(ntscQAction); timingGroup->addAction(ntscQAction); palQAction = new QAction("PAL Timing 50hz", this); QObject::connect(palQAction, SIGNAL(triggered()), this, SLOT(setPALTiming())); palQAction->setCheckable(true); palQAction->setChecked(false); menu->addAction(palQAction); timingGroup->addAction(palQAction); menu->addSeparator(); QActionGroup *regionGroup = new QActionGroup(this); japaneseQAction = new QAction("Japanese machine", this); QObject::connect(japaneseQAction, SIGNAL(triggered()), this, SLOT(setJapanese())); japaneseQAction->setCheckable(true); japaneseQAction->setChecked(true); menu->addAction(japaneseQAction); regionGroup->addAction(japaneseQAction); europeanQAction = new QAction("European machine", this); QObject::connect(europeanQAction, SIGNAL(triggered()), this, SLOT(setEuropean())); europeanQAction->setCheckable(true); europeanQAction->setChecked(false); menu->addAction(europeanQAction); regionGroup->addAction(europeanQAction); mb->addMenu(menu); menu->addSeparator(); irqHackQAction = new QAction("IRQ Hack (not recommended)", this); QObject::connect(irqHackQAction, SIGNAL(triggered()), this, SLOT(toggleIrqHack())); irqHackQAction->setCheckable(true); irqHackQAction->setChecked(false); menu->addAction(irqHackQAction); menu->addSeparator(); QActionGroup *mapperGroup = new QActionGroup(this); segaMapperQAction = new QAction("Default mapper", this); QObject::connect(segaMapperQAction, SIGNAL(triggered()), this, SLOT(setDefaultMapper())); segaMapperQAction->setCheckable(true); segaMapperQAction->setChecked(true); menu->addAction(segaMapperQAction); mapperGroup->addAction(segaMapperQAction); codemasterMapperQAction = new QAction("Codemaster mapper", this); QObject::connect(codemasterMapperQAction, SIGNAL(triggered()), this, SLOT(setCodeMasterMapper())); codemasterMapperQAction->setCheckable(true); codemasterMapperQAction->setChecked(false); menu->addAction(codemasterMapperQAction); mapperGroup->addAction(codemasterMapperQAction); mb->addMenu(menu); koreanMapperQAction = new QAction("Koreand mapper", this); QObject::connect(koreanMapperQAction, SIGNAL(triggered()), this, SLOT(setKoreanMapper())); koreanMapperQAction->setCheckable(true); koreanMapperQAction->setChecked(false); menu->addAction(koreanMapperQAction); mapperGroup->addAction(koreanMapperQAction); mb->addMenu(menu); /* Create video filtering checkable group. */ menu = new QMenu("Video"); QActionGroup *filteringGroup = new QActionGroup(this); filteringGroup->setExclusive(true); // Bilinear OR Nearest neighboor. action = new QAction("&Bilinear filtering", this); action->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_B)); QObject::connect(action, SIGNAL(triggered()), glImage, SLOT(bilinearFilteringOn())); action->setCheckable(true); action->setChecked(false); menu->addAction(action); filteringGroup->addAction(action); action = new QAction("&Nearest neighboor filtering", this); action->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_N)); QObject::connect(action, SIGNAL(triggered()), glImage, SLOT(nearestNeighboorFilteringOn())); action->setCheckable(true); action->setChecked(true); menu->addAction(action); filteringGroup->addAction(action); menu->addSeparator(); QActionGroup *videoSizeGroup = new QActionGroup(this); action = new QAction("Original size (512x384)", this); QObject::connect(action, SIGNAL(triggered()), this, SLOT(sizeX1())); action->setCheckable(true); action->setChecked(true); menu->addAction(action); videoSizeGroup->addAction(action); action = new QAction("Size x2 (768x576)", this); QObject::connect(action, SIGNAL(triggered()), this, SLOT(sizeX2())); action->setCheckable(true); action->setChecked(false); menu->addAction(action); videoSizeGroup->addAction(action); action = new QAction("Size x3 (1024x768)", this); QObject::connect(action, SIGNAL(triggered()), this, SLOT(sizeX3())); action->setCheckable(true); action->setChecked(false); menu->addAction(action); videoSizeGroup->addAction(action); action = new QAction("Size x4 (1280x860)", this); QObject::connect(action, SIGNAL(triggered()), this, SLOT(sizeX4())); action->setCheckable(true); action->setChecked(false); menu->addAction(action); videoSizeGroup->addAction(action); menu->addSeparator(); action = new QAction("Fullscreen", this); QObject::connect(action, SIGNAL(triggered()), this, SLOT(fullscreen())); action->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_F)); menu->addAction(action); mb->addMenu(menu); // SAVES Menu menu = new QMenu("Saves"); action = new QAction("Save machine state", this); action->setShortcut( QKeySequence(Qt::Key_F11)); QObject::connect(action, SIGNAL(triggered()), this, SLOT(saveState())); menu->addAction(action); action = new QAction("Load machine state", this); action->setShortcut( QKeySequence(Qt::Key_F12)); QObject::connect(action, SIGNAL(triggered()), this, SLOT(loadState())); menu->addAction(action); menu->addSeparator(); /* Save state slot selection. */ QActionGroup *selectSlotGroup = new QActionGroup(this); selectSlotGroup->setExclusive(true); // Only one slot selected at a time. action = new QAction("Select slot 1", this); QObject::connect(action, SIGNAL(triggered()), this, SLOT(selectSlot0())); action->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_1)); action->setCheckable(true); action->setChecked(true); selectSlotGroup->addAction(action); menu->addAction(action); action = new QAction("Select slot 2", this); QObject::connect(action, SIGNAL(triggered()), this, SLOT(selectSlot1())); action->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_2)); action->setCheckable(true); action->setChecked(false); selectSlotGroup->addAction(action); menu->addAction(action); action = new QAction("Select slot 3", this); QObject::connect(action, SIGNAL(triggered()), this, SLOT(selectSlot2())); action->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_3)); action->setCheckable(true); action->setChecked(false); selectSlotGroup->addAction(action); menu->addAction(action); action = new QAction("Select slot 4", this); QObject::connect(action, SIGNAL(triggered()), this, SLOT(selectSlot3())); action->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_4)); action->setCheckable(true); action->setChecked(false); selectSlotGroup->addAction(action); menu->addAction(action); mb->addMenu(menu); // ABOUT Menu menu = new QMenu("About", this); action = new QAction("&About emulator", this); action->setShortcut(tr("F1")); connect(action, &QAction::triggered, this, &OsmoseGUI::aboutDialog); menu->addAction(action); mb->addMenu(menu); // Instanciate Configuration object. configuration = new OsmoseConfigurationFile(); // Try to load configuration file. try { configuration->load(); } catch(string error) { // Unable to load or create configuration file. Display a message. error = error + "\nCreating default configuration in user's directory."; QMessageBox::critical(this, "Configuration file not found", error.c_str()); // Unable to load configuration file, try to create a new one. try { configuration->createDefautConfigurationFile(); } catch(string error) { // Unable to load or create configuration file. Display a message. QMessageBox::critical(this, "Unable to create default Configuration file", error.c_str()); } } /* Try to find a Joystick*/ js0 = NULL; try { js0 = new Joystick(configuration->getJoystickDevice().c_str(), this); string msg = "Found Joystick :"; msg = msg + js0->getStrID(); QLogWindow::getInstance()->appendLog(msg); } catch(string &err) { js0 = NULL; string msg = "No joystick found (device : "; msg = msg + configuration->getJoystickDevice(); msg = msg + ")."; QLogWindow::getInstance()->appendLog(msg); } // Enable Drop events. setAcceptDrops(true); // Start emulation thread. It does not means that emulation is started ! emuThread->start(); emuThread->startEmulation(); } /** * Destructor. */ OsmoseGUI::~OsmoseGUI() { } void OsmoseGUI::configure() { QOsmoseConfiguration *configWindow; if (js0 == NULL) { configWindow = new QOsmoseConfiguration(configuration, "No joystick found", this); } else { configWindow = new QOsmoseConfiguration(configuration, js0->getStrID(), this); js0->setListener(configWindow); } configWindow->exec(); if (js0 != NULL) js0->setListener(this); } void OsmoseGUI::sizeX1() { resize(512, 384 + MENU_HEIGHT); string msg = "Video set to original size (512x384)."; QLogWindow::getInstance()->appendLog(msg); } /** * Resize X2 slot. * Resize the main window to new size. */ void OsmoseGUI::sizeX2() { resize(768, 576 + MENU_HEIGHT); string msg = "Video set to original size x2 (768x576)."; QLogWindow::getInstance()->appendLog(msg); } /** * Resize X3 slot. * Resize the main window to new size. */ void OsmoseGUI::sizeX3() { resize(1024, 768 + MENU_HEIGHT); string msg = "Video set to original size x3 (1024x768)."; QLogWindow::getInstance()->appendLog(msg); } /** * Resize X4 slot. * Resize the main window to new size. */ void OsmoseGUI::sizeX4() { resize(1280, 860 + MENU_HEIGHT); string msg = "Video set to original size x4 (1280x860)."; QLogWindow::getInstance()->appendLog(msg); } /** * Fullscreen toggle. */ void OsmoseGUI::fullscreen() { toggleFullscreen(); } void OsmoseGUI::toggleFullscreen() { isFullscreen ^= 1; if (isFullscreen) { showFullScreen(); // Now do this on QLImage to hide menus. string msg = "Video mode set to fullscreen."; QLogWindow::getInstance()->appendLog(msg); } else { showNormal(); string msg = "Video mode set to windowed."; QLogWindow::getInstance()->appendLog(msg); } } /** * loadROM (menu) slot. */ void OsmoseGUI::loadROM() { QString filename = QFileDialog::getOpenFileName(this, "Load File", "./", "SMS/GG Roms (*.sms *.gg)"); if (!filename.isEmpty()) { loadTheROM(filename); } } /** * This method will load a ROM, instanciate emulator core and start it. * It also disconnect and reconnect emuThread QObject signals/slots. */ void OsmoseGUI::loadTheROM(QString filename) { if (rom_name != NULL) delete rom_name; //rom_name = qstrdup(qPrintable(filename)); rom_name = qstrdup( (const char *)filename.toStdString().c_str() ); try { // Stop and kill previous thread. emuThread->abortEmulation(); bool killed = emuThread->wait(1000); // Wait for thread end for 1 second. if (!killed) { string msg = "Warning: could not kill emulation thread !"; QLogWindow::getInstance()->appendLog(msg); } delete emuThread; // Stop recording sound if needed. saveSoundQAction->setChecked(false); QLogWindow::getInstance()->addSeparator(); QLogWindow::getInstance()->appendLog("Trying to load new ROM."); QLogWindow::getInstance()->appendLog(rom_name); // Build new Emulation thread. OsmoseEmulationThread *osm = new OsmoseEmulationThread(glImage, rom_name, configuration, &osmose_core_mutex); emuThread = osm; emuThread->start(); emuThread->startEmulation(); QLogWindow::getInstance()->appendLog("Starting emulation !"); osmoseCore = osm->getCore(); // Tmp is OsmoseEmuThread, not just EmuThread ! // Disconnect / reconnect pause SLOT. QObject::disconnect(pauseResume, SIGNAL(triggered()), this, SLOT(pauseResumeEmulation())); QObject::connect(pauseResume, SIGNAL(triggered()), this, SLOT(pauseResumeEmulation())); paused = false; pauseResume->setText("Pause"); updateMachineMenu(); } catch(string error_msg) { // An exception occurs while creation OsmoseEmulationCore. Launch // White noise animation instead. emuThread = new WhiteNoiseEmulationThread(glImage); emuThread->start(); emuThread->startEmulation(); QLogWindow::getInstance()->appendLog(error_msg); QString msg(error_msg.c_str()); QMessageBox::critical(this, "Oops, we have an error in the emulator", msg); } } /** * pauseResumeEmulation (menu) slot. * This slot is called when emulation is asked for pause and resume. It * is responsible for toggle action label from Pause to Resume. */ void OsmoseGUI::pauseResumeEmulation() { if (!paused) { pauseResume->setText("Resume"); emuThread->pauseEmulation(); paused = true; string msg = "Emulation paused."; QLogWindow::getInstance()->appendLog(msg); } else { pauseResume->setText("Pause"); emuThread->startEmulation(); paused = false; string msg = "Emulation resumed."; QLogWindow::getInstance()->appendLog(msg); } } /** * resetEmulation (menu) slot. * This slot is called when emulation is asked for Reset. */ void OsmoseGUI::resetEmulation() { emuThread->resetEmulation(); pauseResume->setText("Pause"); emuThread->startEmulation(); paused = false; string msg = "Hardware reset."; QLogWindow::getInstance()->appendLog(msg); } /** */ void OsmoseGUI::keyPressEvent(QKeyEvent *event) { event->accept(); // Event is comsumed by our handler. if (!event->isAutoRepeat()) { padKey k = configuration->keyToKeyPad(event->key()); if (k != UNKNOWN) emuThread->keyPressed(k); } } /** */ void OsmoseGUI::keyReleaseEvent(QKeyEvent *event) { event->accept(); // Event is comsumed by our handler. if (!event->isAutoRepeat()) { padKey k = configuration->keyToKeyPad(event->key()); if (k != UNKNOWN) emuThread->keyReleased(k); } } /** */ void OsmoseGUI::saveScreenshot() { // Simulate a fake 'screenshot' key. emuThread->keyPressed(SCREENSHOT); } /** */ void OsmoseGUI::saveSound() { if (osmoseCore == NULL) return; // Simulate a fake 'save wave sound' key. emuThread->keyPressed(SOUNDSHOT); if (saveSoundQAction->isChecked()) { // Save sound has just been selected. bool success = osmoseCore->startRecordingSounds(); if (!success) { // Unable to save wav file. saveSoundQAction->setChecked(false); } } else { // Stop sound recording has just been selected. osmoseCore->stopRecordingSounds(); } } /** * Select the save/load state slot. */ void OsmoseGUI::selectSlot0() { saveStateSlot = 0; } /** * Select the save/load state slot. */ void OsmoseGUI::selectSlot1() { saveStateSlot = 1; } /** * Select the save/load state slot. */ void OsmoseGUI::selectSlot2() { saveStateSlot = 2; } /** * Select the save/load state slot. */ void OsmoseGUI::selectSlot3() { saveStateSlot = 3; } /** * Select the save/load state slot. */ void OsmoseGUI::selectSlot4() { saveStateSlot = 4; } /** */ void OsmoseGUI::saveState() { if (osmoseCore == NULL) return; osmoseCore->saveSaveState(saveStateSlot); } /** */ void OsmoseGUI::loadState() { if (osmoseCore == NULL) return; osmoseCore->loadSaveState(saveStateSlot); } /** */ void OsmoseGUI::exitApplication() { emuThread->abortEmulation(); bool killed = emuThread->wait(1000); // Wait for thread end for 1 second. if (!killed) cerr << "Warning : could not kill emulation thread !" << endl; delete emuThread; qApp->quit(); } /** * This method overrides the default closeEvent handler. */ void OsmoseGUI::closeEvent(QCloseEvent * ) { exitApplication(); } /** */ void OsmoseGUI::saveVDPGFX() { if (osmoseCore == NULL) return; osmoseCore->captureTiles(); } /** */ void OsmoseGUI::setDefaultMapper() { if (osmoseCore == NULL) return; osmoseCore->forceMemoryMapper(SegaMapper); osmoseCore->reset(); string msg = "Forced Sega mapper, then hardware reset."; QLogWindow::getInstance()->appendLog(msg); } /** */ void OsmoseGUI::setCodeMasterMapper() { if (osmoseCore == NULL) return; osmoseCore->forceMemoryMapper(CodemasterMapper); osmoseCore->reset(); string msg = "Forced Codemaster mapper, then hardware reset."; QLogWindow::getInstance()->appendLog(msg); } /** */ void OsmoseGUI::setKoreanMapper() { if (osmoseCore == NULL) return; osmoseCore->forceMemoryMapper(KoreanMapper); osmoseCore->reset(); string msg = "Forced Korean mapper, then hardware reset."; QLogWindow::getInstance()->appendLog(msg); } /** */ void OsmoseGUI::setNTSCTiming() { if (osmoseCore == NULL) return; osmoseCore->forceNTSCTiming(true); string msg = "Forced NTSC timing, no hardware reset."; QLogWindow::getInstance()->appendLog(msg); } /** */ void OsmoseGUI::setPALTiming() { if (osmoseCore == NULL) return; osmoseCore->forceNTSCTiming(false); string msg = "Forced PAL timing, no hardware reset."; QLogWindow::getInstance()->appendLog(msg); } /** */ void OsmoseGUI::setJapanese() { if (osmoseCore == NULL) return; opt.WorldVersion = false; string msg = "Forced Japanese hardware, no hardware reset."; QLogWindow::getInstance()->appendLog(msg); } /** */ void OsmoseGUI::setEuropean() { if (osmoseCore == NULL) return; opt.WorldVersion = true; string msg = "Forced European hardware, no hardware reset."; QLogWindow::getInstance()->appendLog(msg); } /** * Loading a rom sometimes changes Osmose's option e.g. * Codemaster mapper required for some games. This method * synchronize opt structure and Machine menu. */ void OsmoseGUI::updateMachineMenu() { if (opt.WorldVersion == true) { europeanQAction->setChecked(true); } else { japaneseQAction->setChecked(true); } if (opt.ntsc == true) { ntscQAction->setChecked(true); } else { palQAction->setChecked(true); } if (opt.irq_hack == true) { irqHackQAction->setChecked(true); } else { irqHackQAction->setChecked(false); } switch(opt.mapperType) { case SegaMapper: segaMapperQAction->setChecked(true); break; case CodemasterMapper: codemasterMapperQAction->setChecked(true); break; case KoreanMapper: koreanMapperQAction->setChecked(true); break; } } /** * This method toggles IRQ Hack. */ void OsmoseGUI::toggleIrqHack() { if (irqHackQAction->isChecked()) { opt.irq_hack = true; string msg = "IRQ hack turned ON."; QLogWindow::getInstance()->appendLog(msg); } else { opt.irq_hack = false; string msg = "IRQ hack turned OFF."; QLogWindow::getInstance()->appendLog(msg); } } void OsmoseGUI::showLogWindow() { QLogWindow::getInstance()->setVisible(true); } /* JoystickListener interface */ void OsmoseGUI::buttonChanged(unsigned int button, bool pressed) { if (osmoseCore == NULL) return; padKey b = configuration->getJoyButtonAssignation(button); switch(b) { case P1BUTTON_A: osmoseCore->P1AButtonChanged(pressed); break; case P1BUTTON_B: osmoseCore->P1BButtonChanged(pressed); break; case PAUSE_NMI: osmoseCore->PauseButtonChanged(pressed); break; case START_GG: osmoseCore->StartButtonChanged(pressed); break; default: break; } } void OsmoseGUI::xAxisChanged(int value) { int sensitivity = 10000; if (osmoseCore == NULL) return; if (abs(value) < sensitivity) { osmoseCore->P1RightChanged(false); osmoseCore->P1LeftChanged(false); } else if (value > sensitivity) { osmoseCore->P1RightChanged(true); osmoseCore->P1LeftChanged(false); } else if (value < sensitivity * -1) { osmoseCore->P1RightChanged(false); osmoseCore->P1LeftChanged(true); } } void OsmoseGUI::yAxisChanged(int value) { int sensitivity = 10000; // Duplicated from xAxisChanged if (osmoseCore == NULL) return; if (abs(value) < sensitivity) { osmoseCore->P1UpChanged(false); osmoseCore->P1DownChanged(false); } else if (value > sensitivity) { osmoseCore->P1UpChanged(false); osmoseCore->P1DownChanged(true); } else if (value < sensitivity * -1) { osmoseCore->P1UpChanged(true); osmoseCore->P1DownChanged(false); } } void OsmoseGUI::joystickError() { } void OsmoseGUI::dropEvent(QDropEvent *event) { QString fileDroped; if (event->mimeData()->hasUrls()) { QList urls = event->mimeData()->urls(); fileDroped = urls.at(0).toString(); fileDroped.replace("file://", ""); loadTheROM(fileDroped); } } void OsmoseGUI::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasUrls()) { event->accept(); } } void OsmoseGUI::aboutDialog() { QMessageBox::about(this,tr("About"), \ tr("
OSMOSE EMULATOR
\ \n
Version: 1.4
\ \n
Sega Master System and Game Gear console emulator

\ Many thanks to Vedder Bruno [2001-2011]\ the original author of Osmose Emulator.
\ Work continued by Carlos Donizete [2016-2018]. \

\ This program comes with absolutely no warranty and can be redistributed and/or \ modified under the terms of the \ GNU GPL versions 3 or later.
")); } osmose-emulator-1.4/src/OsmoseGUI.h000066400000000000000000000063761341430144300172740ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef OSMOSE_GUI_H #define OSMOSE_GUI_H #include #include #include #include #include #include #include #include #include #include #include "QGLImage.h" #include "OsmoseEmulationThread.h" #include "WhiteNoiseEmulationThread.h" #include "QOsmoseConfiguration.h" #include "OsmoseConfigurationFile.h" #include "OsmoseCore.h" #include "MemoryMapper.h" #include "QLogWindow.h" #include "Joystick.h" #define MENU_HEIGHT 20 class OsmoseGUI : public QMainWindow, JoystickListener { Q_OBJECT; public: OsmoseGUI(QWidget * parent = 0, Qt::WindowFlags flags = 0); ~OsmoseGUI(); /* JoystickListener interface */ void buttonChanged(unsigned int button, bool pressed); /* True when pressed */ void xAxisChanged(int value); void yAxisChanged(int value); void joystickError(); void loadTheROM(QString name); void toggleFullscreen(); void aboutDialog(); protected: void closeEvent(QCloseEvent * ); void dropEvent(QDropEvent *e); void dragEnterEvent(QDragEnterEvent *event); protected slots: void sizeX1(); void sizeX2(); void sizeX3(); void sizeX4(); void fullscreen(); void loadROM(); void pauseResumeEmulation(); void resetEmulation(); void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); void configure(); void saveScreenshot(); void saveSound(); void saveState(); void saveVDPGFX(); void loadState(); void selectSlot0(); void selectSlot1(); void selectSlot2(); void selectSlot3(); void selectSlot4(); void exitApplication(); void setDefaultMapper(); void setCodeMasterMapper(); void setKoreanMapper(); void setNTSCTiming(); void setPALTiming(); void setJapanese(); void setEuropean(); void toggleIrqHack(); void showLogWindow(); private: bool paused; QGLImage *glImage; EmulationThread *emuThread; char *rom_name; QAction *pauseResume; QAction *saveSoundQAction; QAction *ntscQAction; QAction *palQAction; QAction *japaneseQAction; QAction *europeanQAction; QAction *codemasterMapperQAction; QAction *segaMapperQAction; QAction *koreanMapperQAction; QAction *irqHackQAction; OsmoseConfigurationFile *configuration; OsmoseCore *osmoseCore; int saveStateSlot; pthread_mutex_t osmose_core_mutex; // OsmoseCore access mutex. void updateMachineMenu(); bool isFullscreen; Joystick *js0; }; #endif // OsmoseGUI osmose-emulator-1.4/src/OsmoseResources.qrc000066400000000000000000000001511341430144300211410ustar00rootroot00000000000000 ./osmose-emulator.png osmose-emulator-1.4/src/Pthreadcpp.cpp000066400000000000000000000060771341430144300201050ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "Pthreadcpp.h" /** * Description : This class is the most basic pthread C++ encapsulation. * It's used to handle JOINABLE / UNDETACHED posix threads. * To create a thread, simply inherit this class, and override the run() * method, and call the start method with input argument if any. Finally * call Join(...) to wait the Thread if needed. * * Author : B.Vedder * * Date : Wed Dec 15 15:44:04 2010 * */ /** * Constructor. */ Thread::Thread() { // The posix thread has not been created yet. _created = false; _joined = false; } /** * Destructor. */ Thread::~Thread() { /* Posix pthread_join() says : When a joinable thread terminates, its memory resources (thread descriptor and stack) are not deallocated until another thread performs pthread_join on it. Therefore, pthread_join must be called once for each joinable thread created to avoid memory leaks. */ if ((_created == true) && (_joined == false)) { pthread_join(_thread, NULL); } } /** * Start, by entering the Thread main loop. The created thread is JOINABLE. * Default value of param is NULL. * Returned value is pthread_create(...) return value. */ int Thread::start(void *param) { _inputArg = param; int retValue = pthread_create(&_thread, NULL, Thread::entryPoint, (void *)this); _created = (retValue == 0) ? true : false; return retValue; } /** * This static method is here because pthread_create cannot take member function * as start_routine, except if it's static. So we made a private static that can * only be called by non static member start(). EntryPoint method received a this * pointer, and use it to call the runnable run() method. */ void *Thread::entryPoint(void *instance) { Thread *myself = (Thread *)instance; return myself->run( myself->getArg()); } /** * Wait for termination of this thread. If retVal is not NULL, the value returned * by the thread will be stored in the location pointed to by thread_return. * On success, zero is returned, else the error code given by pthread_join. */ int Thread::join(void **thread_return) { if (_created != true) return ESRCH; /* Not started again. */ _joined = true; return pthread_join(_thread, thread_return); } osmose-emulator-1.4/src/Pthreadcpp.h000066400000000000000000000044101341430144300175370ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef PTHREADCPP_H #define PTHREADCPP_H #include #include /** * Tiny utility class to benefit from C++ auto destruction of objects. * Creating a LOCAL Mutex object will lock the mutex. Leaving the method * will destroy the object automatically and free the mutex. So in order * to get a method thread safe, simply add at the beginning : * MutexLocker(the_mutex); */ class MutexLocker { public: MutexLocker(pthread_mutex_t *mutex) {the_mutex = mutex; pthread_mutex_lock(the_mutex); } ~MutexLocker() {pthread_mutex_unlock(the_mutex);} private: pthread_mutex_t *the_mutex; }; /** * * Description : This class is the most basic pthread C++ encapsulation. * It's used to handle JOINABLE / UNDETACHED posix threads. * To create a thread, simply inherit this class, and override the run() * method, and call the start method with input argument if any. Finally * call Join(...) to wait the Thread if needed. * * Author : B.Vedder * * Date : Wed Dec 15 15:44:04 2010 * */ class Thread { public: Thread(); int start(void *param = NULL); int join(void **retVal); virtual ~Thread(); protected: virtual void* run(void *p) = 0; /* Override this with your own. */ private: bool _created; bool _joined; pthread_t _thread; void *_inputArg; void *getArg() {return _inputArg;} static void *entryPoint(void *); }; #endif // PTHREADCPP_H osmose-emulator-1.4/src/QGLImage.cpp000066400000000000000000000167401341430144300173770ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #define GL_GLEXT_LEGACY #define GLX_GLXEXT_LEGACY #include "QGLImage.h" #include #include #include #include #define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 #define GL_QUADS 0x0007 #define GL_CLAMP 0x2900 #define GL_MODELVIEW 0x1700 #define GL_PROJECTION 0x1701 using namespace std; /** * Constructor. * * Param1 : Parent QWidget. * * Param2 : texture Width. * * Param3 : texture Height. * */ QGLImage::QGLImage(QWidget *parent, int w, int h, QGL::FormatOptions f) : QGLWidget(QGLFormat(f), parent) { textureBuffer = NULL; viewPortWidth = 1; viewPortHeight = 1; adjustTextureDimension(w, h); bilinearFiltering = false; } /** * Destructor. */ QGLImage::~QGLImage() { } /** * This slot is called when an object signals a resolution of the * textureBuffer change. Note that the depth is FIXED an cannot be changed. * * Return : None. */ void QGLImage::resolutionChanged(int newWidth, int newHeight) { //cout << "New resolution :" << newWidth << "x" << newHeight << endl; adjustTextureDimension(newWidth, newHeight); } /** * This method is called on resize event. * * Return : None. */ void QGLImage::resizeGL(int width, int height) { viewPortWidth = width; viewPortHeight = height; setupViewport(viewPortWidth, viewPortHeight); } /** * This method is called on paint event. * * Return : None. */ void QGLImage::paintGL() { QMutexLocker locker(& textureBufferMutex); setupViewport(viewPortWidth, viewPortHeight); glLoadIdentity(); glBindTexture(GL_TEXTURE_2D, textureName[0]); glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, adjustedTextureWidth, adjustedTextureHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, textureBuffer); glBegin(GL_QUADS); glTexCoord2f(0,0); glVertex2i(0, 0); glTexCoord2f(glTextCoordX,0); glVertex2i(viewPortWidth, 0); glTexCoord2f(glTextCoordX, glTextCoordY); glVertex2i(viewPortWidth, viewPortHeight); glTexCoord2f(0, glTextCoordY); glVertex2i(0, viewPortHeight); glEnd(); } /** * This method is when opengl initialisation is needed by QT. * * Return : None. */ void QGLImage::initializeGL() { glClearColor(0.0, 0.0, 0.0, 0.0); glEnable(GL_TEXTURE_2D); /* Delete previous texture if any. OGL ignores free on non alloc. textures */ glDeleteTextures(1, textureName); glGenTextures(1,textureName); glBindTexture(GL_TEXTURE_2D, textureName[0]); if (bilinearFiltering == true) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); } /** * This method setup viewport in order to get 0,0 coord into upper * left corner, and width, height in bottom right with a given * dimension width, height. * * Param 1: openGL viewPort width. * * Param 2: openGL viewPort height. * * Return : None. */ void QGLImage::setupViewport(int width, int height) { if (height==0) height=1; glViewport(0,0,width,height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0f,width,height,0.0f,-1.0f,1.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glEnd(); } /** * This method compute texture dimension and coordinate to fit the widget * dimension despite OpenGL texture constraints (size power of two). * Note that textureBuffer is allocated, with the adjusted texture size. * Before drawing, the original picture must be blitted into the * adjusted texture. * * Param 1: image source width. * * Param 2: image source height. * * Return : None. */ void QGLImage::adjustTextureDimension(int w, int h) { QMutexLocker locker(& textureBufferMutex); textureWidth = w; textureHeight = h; delete [] textureBuffer; // Legal also if textureBuffer is NULL. adjustedTextureWidth = getNearestGreaterPowerOfTwo(textureWidth); adjustedTextureHeight = getNearestGreaterPowerOfTwo(textureHeight); glTextCoordX = ((float)textureWidth / (float)adjustedTextureWidth); glTextCoordY = ((float)textureHeight / (float)adjustedTextureHeight); textureBuffer = new unsigned int[adjustedTextureWidth * adjustedTextureHeight]; /* cout << "texture width = "<< textureWidth << " adjusted width = " << adjustedTextureWidth << endl; cout << "texture height = "<< textureHeight << " adjusted height = " << adjustedTextureHeight << endl; cout << "glTextCoordX = "<< glTextCoordX << endl; cout << "glTextCoordY = "<< glTextCoordY << endl; */ } /** * This image blit original pixel buffer to the size adjusted openGL * texture. * * Param 1: image source pixel data (RGBA 32bits). * * Return : None. */ void QGLImage::blit(unsigned int *source) { QMutexLocker locker(& textureBufferMutex); unsigned int *scaledTexture = textureBuffer; int sizeLine = textureWidth * sizeof(unsigned int); for (int i = 0; i < textureHeight; i++) { memcpy(scaledTexture, source, sizeLine); source += textureWidth; scaledTexture += adjustedTextureWidth; } // Ask for refresh ! update(); } /** * OpenGL texture only accepts power of two size. * The QGLImage object will not have such limitation, and will hide a * work around to use any texture size as image source. This is done * by allocation the next bigger size which is a power of two, and * adjust texture coordinate accodingly, to fill the object surface. * * This method calculate the nearest greater power of two texture size * for the given image size. e.g : image size is 259 pixel, the texture * size allocated will be 512. * * Param 1: Original image resolution. * * Return : The nearest greater size power of two. */ int QGLImage::getNearestGreaterPowerOfTwo(int size) { if (size <= 2) return 2; if (size <= 4) return 4; if (size <= 8) return 8; if (size <= 16) return 16; if (size <= 32) return 32; if (size <= 64) return 64; if (size <= 128) return 128; if (size <= 256) return 256; if (size <= 512) return 512; if (size <= 1024) return 1024; if (size <= 2048) return 2048; return 4096; } /** * This slot is called when an bilinear filtering is turned ON. * * Return : None. */ void QGLImage::bilinearFilteringOn() { if (bilinearFiltering != true) { bilinearFiltering = true; initializeGL(); } } /** * This slot is called when an bilinear filtering is turned OFF. * * Return : None. */ void QGLImage::nearestNeighboorFilteringOn() { if (bilinearFiltering == true) { bilinearFiltering = false; initializeGL(); } } osmose-emulator-1.4/src/QGLImage.h000066400000000000000000000041771341430144300170450ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef QGLIMAGE_H #define QGLIMAGE_H #include #include #include #include #include class QGLImage : public QGLWidget { Q_OBJECT; public: QGLImage(QWidget *parent = 0, int w = 320, int h = 240, QGL::FormatOptions f = QGL::DirectRendering); ~QGLImage(); void blit(unsigned int *source); int getTextureWidth() { return textureWidth;} int getTextureHeight() { return textureHeight;} bool isBilinearFiltering() { return bilinearFiltering;} bool isNearestNeighboorFiltering() { return (!bilinearFiltering);} public slots: void resolutionChanged(int newx, int newy); void bilinearFilteringOn(); void nearestNeighboorFilteringOn(); protected: void resizeGL(int width, int height); void paintGL(); void initializeGL(); private: void setupViewport(int w, int h); int viewPortWidth; int viewPortHeight; int textureWidth; int textureHeight; int adjustedTextureWidth; int adjustedTextureHeight; float glTextCoordX; float glTextCoordY; bool bilinearFiltering; // Texture used to render the Quad. QMutex textureBufferMutex; GLuint textureName[1]; unsigned int *textureBuffer; void adjustTextureDimension(int w, int h); int getNearestGreaterPowerOfTwo(int size); }; #endif // QGLIMAGE_H osmose-emulator-1.4/src/QLogWindow.cpp000066400000000000000000000042541341430144300200400ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "QLogWindow.h" // Initialise self ptr to NULL. QLogWindow *QLogWindow::self = NULL; QLogWindow *QLogWindow::getInstance(QWidget *parent) { if (self == NULL) { self = new QLogWindow(parent); } return self; } void QLogWindow::appendLog(const char *str) { QString msg(str); QString time = getTimePrefix(); time.append(msg); logQPlainTextEdit->appendPlainText(time); } void QLogWindow::appendLog(string &str) { QString msg(str.c_str()); QString time = getTimePrefix(); time.append(msg); logQPlainTextEdit->appendPlainText(time); } void QLogWindow::addSeparator() { logQPlainTextEdit->appendPlainText("________________________________________________________________\n"); } QString QLogWindow::getTimePrefix() { QString ascii_time = "["; ascii_time.append(QTime::currentTime().toString()); ascii_time.append("] "); return ascii_time; } void QLogWindow::clearLogs() { logQPlainTextEdit->clear(); } /** * Private Constructor. */ QLogWindow::QLogWindow(QWidget *p) : QWidget(p) { setupUi((QWidget*)this); QObject::connect(hideButton, SIGNAL(clicked()), this, SLOT(hideWindow())); QObject::connect(clearLogsButton, SIGNAL(clicked()), this, SLOT(clearLogs())); } /** * Destructor. */ QLogWindow::~QLogWindow() { } void QLogWindow::hideWindow() { self->setVisible(false); } osmose-emulator-1.4/src/QLogWindow.h000066400000000000000000000026571341430144300175120ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef QLOGWINDOW_H #define QLOGWINDOW_H #include #include #include "ui_LogWindow.h" using namespace std; class QLogWindow : public QWidget, private Ui::LogWindow { Q_OBJECT public: ~QLogWindow(); static QLogWindow *getInstance(QWidget *parent = 0); void appendLog(string &); void appendLog(const char *); void addSeparator(); protected slots: void hideWindow(); void clearLogs(); protected: private: static QLogWindow *self; QLogWindow(QWidget *parent = 0); QString getTimePrefix(); }; #endif // QLOGWINDOW_H osmose-emulator-1.4/src/QOsmoseConfiguration.cpp000066400000000000000000000532361341430144300221300ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "QOsmoseConfiguration.h" #include using namespace std; /** * Constructor. */ QOsmoseConfiguration::QOsmoseConfiguration(OsmoseConfigurationFile *conf, const char *joyName, QWidget *parent) : QDialog(parent) { homeDirectory = QString(OsmoseConfigurationFile::getHomeDirectory().c_str()); setupUi((QDialog*)this); completeConnections(); joystickNameQLabel->setText(joyName); ocf = conf; synchronizeWithConfiguration(); this->setFixedSize(this->width(),this->height()); } /** * Destructor. */ QOsmoseConfiguration::~QOsmoseConfiguration() { delete ocf; } /** * selectBBRPath slot : * * This slot is called when the tool button is clicked. It then open a file * selection dialog to get an existing directory to store Battery Backed RAM. * The corresponding QLineEdit is also updated with the chosen path. */ void QOsmoseConfiguration::selectBBRPath() { QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"), homeDirectory, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); if (dir.isEmpty() || dir.isNull()) return; bbrPathLineEdit->setText(dir); } /** * selectScreenshotPath slot : * * This slot is called when the tool button is clicked. It then open a file * selection dialog to get an existing directory to store screenshots. * The corresponding QLineEdit is also updated with the chosen path. */ void QOsmoseConfiguration::selectScreenshotPath() { QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"), homeDirectory, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); if (dir.isEmpty() || dir.isNull()) return; screenshotsPathLineEdit->setText(dir); } /** * selectSaveStatePath slot : * * This slot is called when the tool button is clicked. It then open a file * selection dialog to get an existing directory to store save states. * The corresponding QLineEdit is also updated with the chosen path. */ void QOsmoseConfiguration::selectSaveStatePath() { QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"), homeDirectory, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); if (dir.isEmpty() || dir.isNull()) return; saveStatePathLineEdit->setText(dir); } /** * selectTileRipPath slot : * * This slot is called when the tool button is clicked. It then open a file * selection dialog to get an existing directory to store ripped tiles. * The corresponding QLineEdit is also updated with the chosen path. */ void QOsmoseConfiguration::selectTileRipPath() { QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"), homeDirectory, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); if (dir.isEmpty() || dir.isNull()) return; tileSavePathLineEdit->setText(dir); } /** * selectTileRipPath slot : * * This slot is called when the tool button is clicked. It then open a file * selection dialog to get an existing directory to store ripped sounds. * The corresponding QLineEdit is also updated with the chosen path. */ void QOsmoseConfiguration::selectSoundRipPath() { QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"), homeDirectory, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); if (dir.isEmpty() || dir.isNull()) return; soundSavePathLineEdit->setText(dir); } /** * completeConnections() : * This method perform the SLOT/SIGNAL connections. */ void QOsmoseConfiguration::completeConnections() { // Connect directory file selectors. QObject::connect(bbrSelectPath, SIGNAL(clicked()), this, SLOT(selectBBRPath())); QObject::connect(screenshotsSelectPath, SIGNAL(clicked()), this, SLOT(selectScreenshotPath())); QObject::connect(saveStateSelectPath, SIGNAL(clicked()), this, SLOT(selectSaveStatePath())); QObject::connect(tileSaveSelectPath, SIGNAL(clicked()), this, SLOT(selectTileRipPath())); QObject::connect(soundSaveSelectPath, SIGNAL(clicked()), this, SLOT(selectSoundRipPath())); // Connect player 1 pad redefine buttons. QObject::connect(changeP1UpButton, SIGNAL(clicked()), this, SLOT(redefineP1Up())); QObject::connect(changeP1DownButton, SIGNAL(clicked()), this, SLOT(redefineP1Down())); QObject::connect(changeP1LeftButton, SIGNAL(clicked()), this, SLOT(redefineP1Left())); QObject::connect(changeP1RightButton, SIGNAL(clicked()), this, SLOT(redefineP1Right())); QObject::connect(changeP1AButton, SIGNAL(clicked()), this, SLOT(redefineP1A())); QObject::connect(changeP1BButton, SIGNAL(clicked()), this, SLOT(redefineP1B())); // Connect player 2 pad redefine buttons. QObject::connect(changeP2UpButton, SIGNAL(clicked()), this, SLOT(redefineP2Up())); QObject::connect(changeP2DownButton, SIGNAL(clicked()), this, SLOT(redefineP2Down())); QObject::connect(changeP2LeftButton, SIGNAL(clicked()), this, SLOT(redefineP2Left())); QObject::connect(changeP2RightButton, SIGNAL(clicked()), this, SLOT(redefineP2Right())); QObject::connect(changeP2AButton, SIGNAL(clicked()), this, SLOT(redefineP2A())); QObject::connect(changeP2BButton, SIGNAL(clicked()), this, SLOT(redefineP2B())); // Connect Pause/Start redefine buttons. QObject::connect(changeStartButton, SIGNAL(clicked()), this, SLOT(redefineStart())); QObject::connect(changePauseButton, SIGNAL(clicked()), this, SLOT(redefinePause())); // Connect save config button. QObject::connect(saveButton, SIGNAL(clicked()), this, SLOT(saveConfiguration())); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(applyConfiguration())); // Connect Joystick 0 combobox to button assignations routines. QObject::connect(button1ComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(joy0Button1Assigned(int))); QObject::connect(button2ComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(joy0Button2Assigned(int))); QObject::connect(button3ComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(joy0Button3Assigned(int))); QObject::connect(button4ComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(joy0Button4Assigned(int))); QObject::connect(button5ComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(joy0Button5Assigned(int))); QObject::connect(button6ComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(joy0Button6Assigned(int))); QObject::connect(button7ComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(joy0Button7Assigned(int))); QObject::connect(button8ComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(joy0Button8Assigned(int))); // Queued connection for QLabel background color because joystick event come from a different thread. QObject::connect(this, SIGNAL(joyButton1Event(bool)), this, SLOT(joyButton1Changed(bool)), Qt::QueuedConnection); QObject::connect(this, SIGNAL(joyButton2Event(bool)), this, SLOT(joyButton2Changed(bool)), Qt::QueuedConnection); QObject::connect(this, SIGNAL(joyButton3Event(bool)), this, SLOT(joyButton3Changed(bool)), Qt::QueuedConnection); QObject::connect(this, SIGNAL(joyButton4Event(bool)), this, SLOT(joyButton4Changed(bool)), Qt::QueuedConnection); QObject::connect(this, SIGNAL(joyButton5Event(bool)), this, SLOT(joyButton5Changed(bool)), Qt::QueuedConnection); QObject::connect(this, SIGNAL(joyButton6Event(bool)), this, SLOT(joyButton6Changed(bool)), Qt::QueuedConnection); QObject::connect(this, SIGNAL(joyButton7Event(bool)), this, SLOT(joyButton7Changed(bool)), Qt::QueuedConnection); QObject::connect(this, SIGNAL(joyButton8Event(bool)), this, SLOT(joyButton8Changed(bool)), Qt::QueuedConnection); } /** * Update the QWidget with the values of the configuration. */ void QOsmoseConfiguration::synchronizeWithConfiguration() { // Synchronize paths. screenshotsPathLineEdit->setText(ocf->getScreenshotPath().c_str()); bbrPathLineEdit->setText(ocf->getBBRPath().c_str()); saveStatePathLineEdit->setText(ocf->getSaveStatePath().c_str()); tileSavePathLineEdit->setText(ocf->getTileCapturePath().c_str()); soundSavePathLineEdit->setText(ocf->getSoundCapturePath().c_str()); // Synchronize PAD1. p1UpLabel->setText(KeyMapper::getKeyDescription(ocf->getPad(0, UP))); p1DownLabel->setText(KeyMapper::getKeyDescription(ocf->getPad(0, DOWN))); p1LeftLabel->setText(KeyMapper::getKeyDescription(ocf->getPad(0, LEFT))); p1RightLabel->setText(KeyMapper::getKeyDescription(ocf->getPad(0, RIGHT))); p1ALabel->setText(KeyMapper::getKeyDescription(ocf->getPad(0, BUTTON_A))); p1BLabel->setText(KeyMapper::getKeyDescription(ocf->getPad(0, BUTTON_B))); // Synchronize PAD2. p2UpLabel->setText(KeyMapper::getKeyDescription(ocf->getPad(1, UP))); p2DownLabel->setText(KeyMapper::getKeyDescription(ocf->getPad(1, DOWN))); p2LeftLabel->setText(KeyMapper::getKeyDescription(ocf->getPad(1, LEFT))); p2RightLabel->setText(KeyMapper::getKeyDescription(ocf->getPad(1, RIGHT))); p2ALabel->setText(KeyMapper::getKeyDescription(ocf->getPad(1, BUTTON_A))); p2BLabel->setText(KeyMapper::getKeyDescription(ocf->getPad(1, BUTTON_B))); // Synchronize Start/Pause. pauseLabel->setText(KeyMapper::getKeyDescription(ocf->getPause())); startLabel->setText(KeyMapper::getKeyDescription(ocf->getStart())); // Synchronise Joystick0 button. button1ComboBox->setCurrentIndex(buttonAssignationToComboBox(ocf->getJoyButtonAssignation(0))); button2ComboBox->setCurrentIndex(buttonAssignationToComboBox(ocf->getJoyButtonAssignation(1))); button3ComboBox->setCurrentIndex(buttonAssignationToComboBox(ocf->getJoyButtonAssignation(2))); button4ComboBox->setCurrentIndex(buttonAssignationToComboBox(ocf->getJoyButtonAssignation(3))); button5ComboBox->setCurrentIndex(buttonAssignationToComboBox(ocf->getJoyButtonAssignation(4))); button6ComboBox->setCurrentIndex(buttonAssignationToComboBox(ocf->getJoyButtonAssignation(5))); button7ComboBox->setCurrentIndex(buttonAssignationToComboBox(ocf->getJoyButtonAssignation(6))); button8ComboBox->setCurrentIndex(buttonAssignationToComboBox(ocf->getJoyButtonAssignation(7))); // Synchronize QLineEdit with joystick device. joystickDeviceQLineEdit->setText(QString(ocf->getJoystickDevice().c_str())); } /** * Convert given padKey to joystick button combo box index. */ int QOsmoseConfiguration::buttonAssignationToComboBox(padKey k) { int ret; switch(k) { case START_GG: ret = 4; break; case PAUSE_NMI: ret = 3; break; case P1BUTTON_A: ret = 1; break; case P1BUTTON_B: ret = 2; break; default : ret = 0; break; } return ret; } /** * Convert given combo box index to padKey. */ padKey QOsmoseConfiguration::comboBoxToButtonAssignation(int index) { padKey ret; switch(index) { case 4: ret = START_GG; break; case 3: ret = PAUSE_NMI; break; case 1: ret = P1BUTTON_A; break; case 2: ret = P1BUTTON_B; break; default : ret = UNKNOWN; break; } return ret; } /** * This slot is call when user clicks on save button. */ void QOsmoseConfiguration::saveConfiguration() { try { ocf->setScreenshotPath(screenshotsPathLineEdit->text().toStdString()); ocf->setSoundCapturePath(soundSavePathLineEdit->text().toStdString()); ocf->setTileCapturePath(tileSavePathLineEdit->text().toStdString()); ocf->setBBRPath(bbrPathLineEdit->text().toStdString()); ocf->setSaveStatePath(saveStatePathLineEdit->text().toStdString()); ocf->setJoystickDevice(joystickDeviceQLineEdit->text().toStdString()); ocf->save(); accept(); /* Call the accept slot. */ } catch(string error) { QMessageBox::critical(this, "Configuration save failed", error.c_str()); } } /** * This slot is call when user clicks on apply button. */ void QOsmoseConfiguration::applyConfiguration() { ocf->setScreenshotPath(screenshotsPathLineEdit->text().toStdString()); ocf->setSoundCapturePath(soundSavePathLineEdit->text().toStdString()); ocf->setTileCapturePath(tileSavePathLineEdit->text().toStdString()); ocf->setBBRPath(bbrPathLineEdit->text().toStdString()); ocf->setSaveStatePath(saveStatePathLineEdit->text().toStdString()); ocf->setJoystickDevice(joystickDeviceQLineEdit->text().toStdString()); accept(); /* Call the accept slot. */ } /** * This slot is call when user redefines joystick 0 button 1 */ void QOsmoseConfiguration::joy0Button1Assigned(int v) { ocf->assignJoyButton(0, comboBoxToButtonAssignation(v)); } /** * This slot is call when user redefines joystick 0 button 2 */ void QOsmoseConfiguration::joy0Button2Assigned(int v) { ocf->assignJoyButton(1, comboBoxToButtonAssignation(v)); } /** * This slot is call when user redefines joystick 0 button 3 */ void QOsmoseConfiguration::joy0Button3Assigned(int v) { ocf->assignJoyButton(2, comboBoxToButtonAssignation(v)); } /** * This slot is call when user redefines joystick 0 button 4 */ void QOsmoseConfiguration::joy0Button4Assigned(int v) { ocf->assignJoyButton(3, comboBoxToButtonAssignation(v)); } /** * This slot is call when user redefines joystick 0 button 5 */ void QOsmoseConfiguration::joy0Button5Assigned(int v) { ocf->assignJoyButton(4, comboBoxToButtonAssignation(v)); } /** * This slot is call when user redefines joystick 0 button 6 */ void QOsmoseConfiguration::joy0Button6Assigned(int v) { ocf->assignJoyButton(5, comboBoxToButtonAssignation(v)); } /** * This slot is call when user redefines joystick 0 button 7 */ void QOsmoseConfiguration::joy0Button7Assigned(int v) { ocf->assignJoyButton(6, comboBoxToButtonAssignation(v)); } /** * This slot is call when user redefines joystick 0 button 8 */ void QOsmoseConfiguration::joy0Button8Assigned(int v) { ocf->assignJoyButton(7, comboBoxToButtonAssignation(v)); } /** * This slot is call when user clicks on Player 1 Up redefine button. */ void QOsmoseConfiguration::redefineP1Up() { unsigned int the_key = pickupKey(p1UpLabel); ocf->setPad(0, UP, the_key); } /** * This slot is call when user clicks on Player 1 down redefine button. */ void QOsmoseConfiguration::redefineP1Down() { unsigned int the_key = pickupKey(p1DownLabel); ocf->setPad(0, DOWN, the_key); } /** * This slot is call when user clicks on Player 1 Left redefine button. */ void QOsmoseConfiguration::redefineP1Left() { unsigned int the_key = pickupKey(p1LeftLabel); ocf->setPad(0, LEFT, the_key); } /** * This slot is call when user clicks on Player 1 right redefine button. */ void QOsmoseConfiguration::redefineP1Right() { unsigned int the_key = pickupKey(p1RightLabel); ocf->setPad(0, RIGHT, the_key); } /** * This slot is call when user clicks on Player 1 A redefine button. */ void QOsmoseConfiguration::redefineP1A() { unsigned int the_key = pickupKey(p1ALabel); ocf->setPad(0, BUTTON_A, the_key); } /** * This slot is call when user clicks on Player 1 B redefine button. */ void QOsmoseConfiguration::redefineP1B() { unsigned int the_key = pickupKey(p1BLabel); ocf->setPad(0, BUTTON_B, the_key); } /** * This slot is call when user clicks on Player 2 Up redefine button. */ void QOsmoseConfiguration::redefineP2Up() { unsigned int the_key = pickupKey(p2UpLabel); ocf->setPad(1, UP, the_key); } /** * This slot is call when user clicks on Player 2 down redefine button. */ void QOsmoseConfiguration::redefineP2Down() { unsigned int the_key = pickupKey(p2DownLabel); ocf->setPad(1, DOWN, the_key); } /** * This slot is call when user clicks on Player 2 Left redefine button. */ void QOsmoseConfiguration::redefineP2Left() { unsigned int the_key = pickupKey(p2LeftLabel); ocf->setPad(1, LEFT, the_key); } /** * This slot is call when user clicks on Player 2 right redefine button. */ void QOsmoseConfiguration::redefineP2Right() { unsigned int the_key = pickupKey(p2RightLabel); ocf->setPad(1, RIGHT, the_key); } /** * This slot is call when user clicks on Player 2 A redefine button. */ void QOsmoseConfiguration::redefineP2A() { unsigned int the_key = pickupKey(p2ALabel); ocf->setPad(1, BUTTON_A, the_key); } /** * This slot is call when user clicks on Player 2 B redefine button. */ void QOsmoseConfiguration::redefineP2B() { unsigned int the_key = pickupKey(p2BLabel); ocf->setPad(1, BUTTON_B, the_key); } /** * This slot is call when user clicks on Pause button. */ void QOsmoseConfiguration::redefinePause() { unsigned int the_key = pickupKey(pauseLabel); ocf->setPause(the_key); } /** * This slot is call when user clicks on Start button. */ void QOsmoseConfiguration::redefineStart() { unsigned int the_key = pickupKey(startLabel); ocf->setStart(the_key); } /** * It popups a dialog asking to hit the new key, then convert the key into an * ASCII description and update the given lQLabel. */ unsigned int QOsmoseConfiguration::pickupKey(QLabel *label) { unsigned the_key; KeyGrabber * kg = new KeyGrabber(this); kg->exec(); the_key = kg->getKeyPressed(); label->setText(KeyMapper::getKeyDescription(the_key)); delete kg; return the_key; } /** * KeyGrabber constructor. */ KeyGrabber::KeyGrabber(QWidget *parent) : QDialog(parent) { setFixedSize(320, 200); QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom, this); QLabel *label = new QLabel("Hit the new key"); layout->addWidget(label); keyPressed = 0xFFFFFFFF; } /** * KeyGrabber keyPressedEvent callback, save the pressed key, and close * the QDialog. */ void KeyGrabber::keyPressEvent(QKeyEvent *evt) { evt->accept(); keyPressed = evt->key(); //cout << keyPressed << endl; setVisible(false); } /** * This slot is called when a Joystick has been pressed or released. */ void QOsmoseConfiguration::joyButton1Changed(bool pressed) { if (pressed == true) { button1QLabel->setStyleSheet("QLabel { background-color: rgb(192, 0, 0) }"); } else { button1QLabel->setStyleSheet(""); } } /** * This slot is called when a Joystick has been pressed or released. */ void QOsmoseConfiguration::joyButton2Changed(bool pressed) { if (pressed == true) { button2QLabel->setStyleSheet("QLabel { background-color: rgb(192, 0, 0) }"); } else { button2QLabel->setStyleSheet(""); } } /** * This slot is called when a Joystick has been pressed or released. */ void QOsmoseConfiguration::joyButton3Changed(bool pressed) { if (pressed == true) { button3QLabel->setStyleSheet("QLabel { background-color: rgb(192, 0, 0) }"); } else { button3QLabel->setStyleSheet(""); } } /** * This slot is called when a Joystick has been pressed or released. */ void QOsmoseConfiguration::joyButton4Changed(bool pressed) { if (pressed == true) { button4QLabel->setStyleSheet("QLabel { background-color: rgb(192, 0, 0) }"); } else { button4QLabel->setStyleSheet(""); } } /** * This slot is called when a Joystick has been pressed or released. */ void QOsmoseConfiguration::joyButton5Changed(bool pressed) { if (pressed == true) { button5QLabel->setStyleSheet("QLabel { background-color: rgb(192, 0, 0) }"); } else { button5QLabel->setStyleSheet(""); } } /** * This slot is called when a Joystick has been pressed or released. */ void QOsmoseConfiguration::joyButton6Changed(bool pressed) { if (pressed == true) { button6QLabel->setStyleSheet("QLabel { background-color: rgb(192, 0, 0) }"); } else { button6QLabel->setStyleSheet(""); } } /** * This slot is called when a Joystick has been pressed or released. */ void QOsmoseConfiguration::joyButton7Changed(bool pressed) { if (pressed == true) { button7QLabel->setStyleSheet("QLabel { background-color: rgb(192, 0, 0) }"); } else { button7QLabel->setStyleSheet(""); } } /** * This slot is called when a Joystick has been pressed or released. */ void QOsmoseConfiguration::joyButton8Changed(bool pressed) { if (pressed == true) { button8QLabel->setStyleSheet("QLabel { background-color: rgb(192, 0, 0) }"); } else { button8QLabel->setStyleSheet(""); } } /* JoystickListener interface */ void QOsmoseConfiguration::buttonChanged(unsigned int button, bool pressed) { switch(button) { case 0: emit joyButton1Event(pressed); break; case 1: emit joyButton2Event(pressed); break; case 2: emit joyButton3Event(pressed); break; case 3: emit joyButton4Event(pressed); break; case 4: emit joyButton5Event(pressed); break; case 5: emit joyButton6Event(pressed); break; case 6: emit joyButton7Event(pressed); break; case 7: emit joyButton8Event(pressed); break; } } void QOsmoseConfiguration::xAxisChanged(int value) { Q_UNUSED(value) } void QOsmoseConfiguration::yAxisChanged(int value) { Q_UNUSED(value) } void QOsmoseConfiguration::joystickError() { } osmose-emulator-1.4/src/QOsmoseConfiguration.h000066400000000000000000000070111341430144300215630ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef QOSMOSECONFIGURATION_H #define QOSMOSECONFIGURATION_H #include #include #include #include "ui_Configuration.h" #include "KeyMapper.h" #include "Joystick.h" #include "OsmoseConfigurationFile.h" class KeyGrabber : public QDialog { Q_OBJECT public: KeyGrabber(QWidget *parent = 0); unsigned int getKeyPressed() {return keyPressed;} protected: void keyPressEvent(QKeyEvent *e); unsigned int keyPressed; }; class QOsmoseConfiguration : public QDialog, public JoystickListener, private Ui::Configuration { Q_OBJECT public: QOsmoseConfiguration(OsmoseConfigurationFile *conf, const char *joyName, QWidget *parent = 0); void synchronizeWithConfiguration(); // Joystick listener interface. void buttonChanged(unsigned int button, bool pressed); /* True when pressed */ void xAxisChanged(int value); void yAxisChanged(int value); void joystickError(); ~QOsmoseConfiguration(); protected: public slots: void selectBBRPath(); void selectScreenshotPath(); void selectSaveStatePath(); void selectTileRipPath(); void selectSoundRipPath(); void redefineP1Up(); void redefineP1Down(); void redefineP1Left(); void redefineP1Right(); void redefineP1A(); void redefineP1B(); void redefineP2Up(); void redefineP2Down(); void redefineP2Left(); void redefineP2Right(); void redefineP2A(); void redefineP2B(); void redefinePause(); void redefineStart(); void saveConfiguration(); void applyConfiguration(); void joy0Button1Assigned(int assign); void joy0Button2Assigned(int assign); void joy0Button3Assigned(int assign); void joy0Button4Assigned(int assign); void joy0Button5Assigned(int assign); void joy0Button6Assigned(int assign); void joy0Button7Assigned(int assign); void joy0Button8Assigned(int assign); void joyButton1Changed(bool pressed); void joyButton2Changed(bool pressed); void joyButton3Changed(bool pressed); void joyButton4Changed(bool pressed); void joyButton5Changed(bool pressed); void joyButton6Changed(bool pressed); void joyButton7Changed(bool pressed); void joyButton8Changed(bool pressed); signals: void joyButton1Event(bool pressed); void joyButton2Event(bool pressed); void joyButton3Event(bool pressed); void joyButton4Event(bool pressed); void joyButton5Event(bool pressed); void joyButton6Event(bool pressed); void joyButton7Event(bool pressed); void joyButton8Event(bool pressed); private: void completeConnections(); unsigned int pickupKey(QLabel *label); int buttonAssignationToComboBox(padKey k); padKey comboBoxToButtonAssignation(int); QString homeDirectory; OsmoseConfigurationFile *ocf; }; #endif // QOSMOSECONFIGURATION_H osmose-emulator-1.4/src/RomSpecificOption.cpp000066400000000000000000000104021341430144300213720ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "RomSpecificOption.h" #include "MemoryMapper.h" /* Osmose embedded Database. */ const RSO_DB_Entry SpecificRomOptionDatabase::db[] = { /* SMS ROMS. */ { 0x8dbdf0c7, VIDEO_PAL}, /* Addams Family, The (UE) [!].sms */ { 0x06244acc, SPORT_PADDLE_INPUT}, /* Alex Kidd BMX Trial (UE) [!].sms */ { 0xd2b73e2c, VIDEO_PAL}, /* Back to the Future 3 (UE) [!] */ { 0x3f1da29d, VIDEO_PAL}, /* California Games 2 (UE) [!].sms */ { 0xa0a2ec50, VIDEO_PAL}, /* California Games 2 (UE) [b1].sms */ { 0x76486188, KOREAN_MAPPER}, /* Dodgeball King (Korean).sms*/ { 0x5905bd2f, SPORT_PADDLE_INPUT}, /* Galactic Protector (UE) [!].sms */ { 0xd6438052, SPORT_PADDLE_INPUT | JAPANESE_MACHINE}, /* Megumi Rescue (J) [!].sms */ { 0xffb849ea, VIDEO_PAL}, /* Predator 2 (UE) [!].sms */ { 0x682fcabe, KOREAN_MAPPER}, /* Sangokushi 3 (Korean).sms */ { 0x57f9e510, INTERRUPT_HACK}, /* Sega Chess (UE) [!].sms */ { 0xcea6e82b, SPORT_PADDLE_INPUT | JAPANESE_MACHINE}, /* Woody Pop (J) [!].sms */ { 0x6262f5a0, INTERRUPT_HACK}, /* Zool (UE) [!].sms */ /* Game Gear ROMS. */ { 0x94f0313c, INTERRUPT_HACK}, /* Chicago Syndicate (JUE) [!].gg */ { 0xead0f233, CODE_MASTER_MAPPER}, /* Drop Zone (U) [!].gg */ { 0xbac3a313, INTERRUPT_HACK}, /* Monster Truck Wars (JUE) [!] */ { 0x3e8a9411, CODE_MASTER_MAPPER}, /* Pete Sampras Tennis (E) [!].gg */ { 0x26580e8f, CODE_MASTER_MAPPER}, /* S.S. Lucifer - Man Overboard! (UE) [!].gg*/ { 0x1ca10812, INTERRUPT_HACK}, /* Zool (J).gg */ { 0x00000000, 0}, /* Use as end of list */ }; /* This method return specific options if given CRC match database CRC. */ /* Zero is returned if no CRC is found, meaning no specific options. */ unsigned int SpecificRomOptionDatabase::getOptions(unsigned int rom_crc32, Options *op) { bool rom_identified = false; unsigned int index = 0; unsigned int option = 0; /* Search in db until CRC and specific_options = 0 (end of list) or CRC is found. */ while ((rom_identified == false) && ((db[index].crc32 != 0)&&(db[index].specific_options != 0))) { if (db[index].crc32 == rom_crc32) { option = db[index].specific_options ; rom_identified = true; } index++; } /* Now set the specific options. */ if (option & INTERRUPT_HACK) { op->irq_hack = true; string msg =" * IRQ Hack ON."; QLogWindow::getInstance()->appendLog(msg); } else { op->irq_hack = false; } if (option & CODE_MASTER_MAPPER) { op->mapperType = CodemasterMapper; string msg =" * Using Codemaster mapper."; QLogWindow::getInstance()->appendLog(msg); } if (option & KOREAN_MAPPER) { op->mapperType = KoreanMapper; string msg =" * Using Korean mapper."; QLogWindow::getInstance()->appendLog(msg); } if (option & VIDEO_PAL) { op->ntsc = false; string msg =" * Using PAL video mode."; QLogWindow::getInstance()->appendLog(msg); } if (option & SPORT_PADDLE_INPUT) { op->inputType = PADDLE; string msg =" * Using SPORT PADDLE input device."; QLogWindow::getInstance()->appendLog(msg); } if (option & JAPANESE_MACHINE) { op->WorldVersion = JAPAN; string msg =" * Using JAPANESE SMS."; QLogWindow::getInstance()->appendLog(msg); } return option; } osmose-emulator-1.4/src/RomSpecificOption.h000066400000000000000000000031401341430144300210400ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef ROM_SPECIFIC_OPTION_H #define ROM_SPECIFIC_OPTION_H #include "Options.h" #include #include "QLogWindow.h" enum { CODE_MASTER_MAPPER = 0x1, KOREAN_MAPPER = 0x2, VIDEO_PAL = 0x4, INTERRUPT_HACK = 0x8, SPORT_PADDLE_INPUT = 0x10, JAPANESE_MACHINE = 0x20 }; /* Entry into our database. */ typedef struct { unsigned int crc32; unsigned int specific_options; } RSO_DB_Entry; class SpecificRomOptionDatabase { public: static unsigned int getOptions(unsigned int rom_crc32, Options *o); private: /* Private Constructor. This class is never instanciated. */ SpecificRomOptionDatabase(); static const RSO_DB_Entry db[]; }; #endif osmose-emulator-1.4/src/SN76489.cpp000066400000000000000000000222711341430144300167470ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "SN76489.h" #include "Bits.h" /* Values ripped from MEKA. They've been controlled against a real SMS.*/ const u16 SN76489::volume_table[16] = {892*5, 892*5, 892*5, 760*5, 623*5, 497*5, 404*5, 323*5, 257*5, 198*5, 159*5, 123*5, 96*5, 75*5, 60*5, 0}; #define MAX_OUTPUT 0x7FFF /*--------------------------------------------------------------*/ /* Constructor. */ /*--------------------------------------------------------------*/ SN76489::SN76489(u32 chip_frequency, u32 samplingRate) { if (chip_frequency > sn76489_max_clock) chip_frequency = sn76489_max_clock; if (chip_frequency < sn76489_min_clock) chip_frequency = sn76489_min_clock; chip_frequency_ = chip_frequency; clock_ = chip_frequency_ >> 4; update_step_ = (clock_ << 10) / samplingRate; Fifo_ = new FIFOSoundBuffer( 4096 ); reset(); } /*-------------------------------------------------------------*/ /* This method handles write operation on the PSG port. */ /*-------------------------------------------------------------*/ void SN76489::writePort(u8 value) { u8 channel; if (value & BIT7) // Latch { lastRegister_ = (value >> 4) & 0x7; channel = lastRegister_ >> 1; if (value & BIT4) { volume_[channel] = value & 0xF; #ifdef PSG_DEBUG printf("vol%d=%x.\n",(int)channel, (int)value & 0xF); #endif } else { /* Like said in Maxim's doc, immediately update tone registers.*/ freqDiv_[channel] = (freqDiv_[channel] & 0x3F0) | (value & 0xF); /* Channel 3 uses the same Freq Div than Channel 2. So when Ch2 is updated, we must update Ch3 too. */ if (channel==2 && follow_tone2_frequency_) { freqDiv_[3] = freqDiv_[2]; } #ifdef PSG_DEBUG if (channel !=3) printf("fd%d=%x.\n",(int)channel, freqDiv_[channel]); #endif } } else // Data byte write { channel = lastRegister_ >> 1; if (lastRegister_ & BIT0) // If true, it's volume register. { volume_[channel] = value & 0xF; #ifdef PSG_DEBUG printf("vol%d=%x.\n",(int)channel, (int)value & 0xF); #endif } else { if (channel !=3) { freqDiv_[channel] = (freqDiv_[channel] & 0xF) | ((value & 0x3F) << 4); #ifdef PSG_DEBUG printf("fd%d=%x.\n",(int)channel, freqDiv_[channel]); #endif } } } if (lastRegister_ == 0x6) { #ifdef PSG_DEBUG printf("fd3=%x ",(int)channel, value & 0x3); if ((value & 0x3)== 3) printf("as ch2.\n"); else printf(".\n"); #endif LFSR_ = NOISE_INITIAL_STATE; // Channel 3: writing 4bits 'tone' register. /* Only two bits are used with this Channel. */ switch (value & 0x3) { case 0x0: freqDiv_[channel] = 0x10; follow_tone2_frequency_ = false; break; case 0x1: freqDiv_[channel] = 0x20; follow_tone2_frequency_ = false; break; case 0x2: freqDiv_[channel] = 0x40; follow_tone2_frequency_ = false; break; case 0x3: freqDiv_[channel] = freqDiv_[2]; follow_tone2_frequency_ = true; break; } /* Select WhiteNoise/Periodic Noise from Noise BIT2. */ whiteNoise_ = (value & BIT2); } } /*-------------------------------------------------------------*/ /* This method resets the PSG to it's initial values */ /*-------------------------------------------------------------*/ void SN76489::reset() { lastRegister_ = 0; whiteNoise_ = true; // Default Periodic Noise. follow_tone2_frequency_ = false; LFSR_ = WHITE_NOISE_FEEDBACK; for (u32 i=0; i<4; i++) { volume_[i] = 0xF; half_period_[i] = 0; channel_output_[i] = 1; period_counter_[i] = 0; } Fifo_->reset(); } /*-------------------------------------------------------------*/ /*-------------------------------------------------------------*/ void SN76489::getWave(u8 *s, s32 len) { s16 *dst = (s16 *)s; len >>= 1; Fifo_->read(dst, len); } /*-------------------------------------------------------------*/ /* This method returns parity of the given value. */ /* Given by Maxim's SN76489 Documentation. */ /*-------------------------------------------------------------*/ u8 SN76489::parity(u16 val) { val^=val>>8; val^=val>>4; val^=val>>2; val^=val>>1; return val & 1; } /*---------------------------------------------------------------*/ /* This method returns false is a sample is not accepted by Fifo.*/ /*---------------------------------------------------------------*/ bool SN76489::run(u32 cycles) { if (!Fifo_->spaceAvailable()) return false; while ( cycles ) { s16 snd = 0; /* Compute half periods for all channels. */ for (u32 channel = 0; channel < 4; channel++) { half_period_[channel] = freqDiv_[channel] << 10; if (period_counter_[channel] >= half_period_[channel]) { period_counter_[channel] = 0; } } /* Generate output for 3 channels (0 or 1) */ for (u32 channel = 0; channel < 3; channel++) { period_counter_[channel] += update_step_; if (period_counter_[channel] >= half_period_[channel]) { period_counter_[channel] -= half_period_[channel]; channel_output_[channel] ^= 1; } } /* Generate output for Noise generator. */ period_counter_[3] += update_step_; if (period_counter_[3] >= half_period_[3]) { period_counter_[3] -= half_period_[3]; LFSR_=(LFSR_>>1) | ((whiteNoise_ ? parity(LFSR_ & 0x9):LFSR_ & 1)<<15); channel_output_[3] =(LFSR_ & 1); } /* Now, generate samples for channels A, B and C. */ for (u32 channel = 0; channel < 3; channel++) { s16 polarity; /* If freqdiv is 0 or 1 the channel output is always 1 */ if (freqDiv_[channel] <= 1) channel_output_[channel] = 1; if (channel_output_[channel]) polarity = 1; else polarity = -1; snd += polarity * volume_table[volume_[channel]]; } /* Now, generate samples for Noise generator. */ if (channel_output_[3] == 1) { snd += volume_table[volume_[3]]; } /*if (!Fifo_->write ( snd / 2)) return false; is better. No saturation.*/ if (!Fifo_->write ( snd )) return false; last_sample_ = snd; cycles--; } return true; } /*-------------------------------------------------------------*/ /* Fill the given save state structure for save. */ /*-------------------------------------------------------------*/ bool SN76489::saveState( ofstream &ofs) { SN76489SaveState s; s.lastRegister_ = lastRegister_; // Last written register for (u8 i=0; i < 4; i++) s.volume_[i] = volume_[i]; for (u8 i=0; i < 4; i++) s.freqDiv_[i] = freqDiv_[i]; for (u8 i=0; i < 4; i++) s.half_period_[i] = half_period_[i]; for (u8 i=0; i < 4; i++) s.period_counter_[i] = period_counter_[i]; s.whiteNoise_ = whiteNoise_; s.follow_tone2_frequency_ = follow_tone2_frequency_; ofs.write((char *)&s, sizeof(s)); return ofs.good(); } /*-------------------------------------------------------------*/ /* Restore state from the given save state structure. */ /*-------------------------------------------------------------*/ bool SN76489::loadState( ifstream &ifs) { SN76489SaveState s; ifs.read((char *)&s, sizeof(s)); if (!ifs.good()) return false; lastRegister_ = s.lastRegister_; // Last written register for (u8 i=0; i < 4; i++) volume_[i] = s.volume_[i]; for (u8 i=0; i < 4; i++) freqDiv_[i] = s.freqDiv_[i]; for (u8 i=0; i < 4; i++) half_period_[i] = s.half_period_[i]; for (u8 i=0; i < 4; i++) period_counter_[i] = s.period_counter_[i]; whiteNoise_ = s.whiteNoise_; follow_tone2_frequency_ = s.follow_tone2_frequency_; return true; } osmose-emulator-1.4/src/SN76489.h000066400000000000000000000063151341430144300164150ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef SN76489_H #define SN76489_H #include "FIFOSoundBuffer.h" #include "SaveState.h" using namespace std; #define NOISE_INITIAL_STATE 0x4000 #define WHITE_NOISE_FEEDBACK 0xF037 #define PERIODIC_NOISE_FEEDBACK 0x8000 /* #define PSG_DEBUG */ /* Hardware clock. */ enum { sn76489_max_clock = 4000000, // 4.0 Mhz sn76489_min_clock = 500000, // 500 khz }; typedef struct { u8 lastRegister_; // Last written register u8 volume_[4]; // 4 bits volume registers. u16 freqDiv_[4]; // Frequence divider / 10 bits Tone registers. u32 half_period_[4]; u32 period_counter_[4]; bool whiteNoise_; // WhiteNoise/Periodic mode flag. bool follow_tone2_frequency_; u16 LFSR_; } SN76489SaveState; class SN76489 : public ImplementsSaveState { public: /* Constructor. */ SN76489(u32 chip_frequency, u32 samplingRate); /* Destructor. */ ~SN76489() { delete Fifo_; } /* Handle port writing. */ void writePort(u8); /* Write wave to audio buffer. */ void getWave(u8 *, s32); /* run for N cycles. */ bool run(u32); /* Method used by WaveWriter to save samples.*/ s16 getLastSample() { return last_sample_; } /* Reset PSG. */ void reset(); /* Get FIFO Object for mixer for example.*/ FIFOSoundBuffer *getFIFOSoundBuffer() { return Fifo_; } /* Implemetntation of ImplementsSaveState. */ bool saveState( ofstream &ofs); bool loadState( ifstream &ifs); private: FIFOSoundBuffer *Fifo_; u32 chip_frequency_; u32 clock_; // Chip Frequency / 16 u8 lastRegister_; // Last written register u8 volume_[4]; // 4 bits volume registers. u16 freqDiv_[4]; // Frequence divider / 10 bits Tone registers. u32 half_period_[4]; u32 period_counter_[4]; u16 channel_output_[4]; u32 update_step_; s16 last_sample_; bool whiteNoise_; // WhiteNoise/Periodic mode flag. u16 LFSR_; static const u16 volume_table[16]; bool follow_tone2_frequency_; /* Internal utility method to compute parity.*/ u8 parity(u16 v); }; #endif osmose-emulator-1.4/src/SaveState.h000066400000000000000000000023351341430144300173500ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef SAVESTATE_H #define SAVESTATE_H #include #include #include #include "BasicTypes.h" using namespace std; class ImplementsSaveState { public: virtual bool saveState(ofstream &ofs) = 0; virtual bool loadState(ifstream &ifs) = 0; virtual ~ImplementsSaveState() {}; }; #endif osmose-emulator-1.4/src/SmsDebugger.cpp000066400000000000000000000475661341430144300202320ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include #include #include "SmsDebugger.h" /*--------------------------------------------------------------------*/ /* SmsDebugger class constructor. */ /*--------------------------------------------------------------------*/ SmsDebugger::SmsDebugger() { end_session = false; any_breakpoint = false; breakpoint_on_irq = false; breakpoint_on_enable_interrupt = false; breakpoint_on_disable_interrupt = false; clearBreakpoints(); scanlineBreakpoint = -1; cpu_steping = false; } /*--------------------------------------------------------------------*/ /* This method is the debugger entry point. It read command line and */ /* interpret it, and call associated method. */ /*--------------------------------------------------------------------*/ void SmsDebugger::enter() { char *line; size_t n_byte = 256; char cmd[32]; int param1; int param2; int param3; unsigned char par_nbr; while (end_session == false) { dumpRegisters(); dasm->disasm(cpu->PC); cout << endl << "Cmd:"; line = (char *) malloc(n_byte+1); getline(&line,&n_byte,stdin); par_nbr = sscanf(line,"%s %x %x %x", cmd, ¶m1, ¶m2, ¶m3); free(line); switch (par_nbr) { case 1: exec_cmd( cmd, param1); break; case 2: exec_cmd( cmd, param1, param2); break; default: break; } } } /*--------------------------------------------------------------------*/ /* This method displays help message. */ /*--------------------------------------------------------------------*/ void SmsDebugger::help() { cout << "'dpr' -> Dump Paging Registers." << endl; cout << "'dvdpr' -> Dump VDP registers." << endl; cout << "'vdpi' -> VDP human readable info." << endl; cout << "'dcram' -> Dump VDP Color RAM." << endl; cout << "'dvram XXXX' -> Dump VDP RAM from XXXX."<< endl; cout << "'dsram XXXX' -> Dump SRAM from XXXX."<< endl; cout << "'help' -> This help." << endl; cout << "'quit' -> Exit emulator." << endl; cout << "'c' -> Exit debugger, until next breakpoint." << endl; cout << "'s' -> Step (execute) one Z80 instruction." << endl; cout << "'u [XXXX]' -> Unassemble 16 instruction from PC or XXXX." << endl; cout << "'d [XXXX]' -> Dump memory from PC or XXXX." << endl; cout << "'bp XXXX' -> Put breakpoint at XXXX." << endl; cout << "'cbp' -> Clear ALL breakpoints." << endl; cout << "'lbp' -> List all breakpoints." << endl; cout << "'irqbp' -> Toggle (ON/OFF) breakpoint on IRQ." << endl; cout << "'slbp [XX]' -> Breakpoint on scanline XX. Set negative value to remove breakpoint. use slbp witout value to show scanline breakpoint." << endl; cout << "'bpdi' -> Breakpoint when CPU exec DI opcode." << endl; cout << "'bpei' -> Breakpoint when CPU exec EI opcode." << endl; cout << "* All parameters are expected in hexadecimal values."<< endl; } /*--------------------------------------------------------------------*/ /* This method displays paging registers FFFC-FFFF. */ /*--------------------------------------------------------------------*/ void SmsDebugger::dpr() { unsigned char l_rsr; string state; l_rsr = mem->getRSR(); if (l_rsr & 0x8) { if (l_rsr & 0x4) { state = " [0x8000-0xBFFF is opt RAM bank 2]"; } else { state = " [0x8000-0xBFFF is opt RAM bank 1]"; } } else { state = " [0x8000-0xBFFF is ROM mapped as 0xFFFF]"; } cout << "FFFC (RSR) = 0x" << hex << setw(2) << setfill('0') << (int)l_rsr << state << endl; cout << "FFFD (PAGE0) 0x0000-0x3FFF = 0x" << hex << setw(2) << setfill('0') << (int)mem->getFFFD() << endl; cout << "FFFE (PAGE1) 0x4000-0x7FFF = 0x" << hex << setw(2) << setfill('0') << (int)mem->getFFFE() << endl; cout << "FFFF (PAGE2) 0x8000-0xBFFF = 0x" << hex << setw(2) << setfill('0') << (int)mem->getFFFF() << endl; } /*--------------------------------------------------------------------*/ /* This method displays VDP registers. */ /*--------------------------------------------------------------------*/ void SmsDebugger::dvdpr() { for (int i=0;iline << endl; } /*--------------------------------------------------------------------*/ /* This method displays human readable VDP info. */ /*--------------------------------------------------------------------*/ void SmsDebugger::vdpi() { cout << "* VDP Register 0:" << endl; if (v->REG0 & BIT7) { cout << "Reg0:b7 -> Disable vertical scrolling for columns 24-31." << endl; } else { cout << "Reg0:b7 -> Enable vertical scrolling for columns 24-31." << endl; } if (v->REG0 & BIT6) { cout << "Reg0:b6 -> Disable horizontal scrolling for rows 0-1." << endl; } else { cout << "Reg0:b6 -> Enable horizontal scrolling for rows 0-1." << endl; } if (v->REG0 & BIT5) { cout << "Reg0:b5 -> Mask column 0 with overscan color from register #7." << endl; } else { cout << "Reg0:b5 -> Do not mask column 0 with overscan color from register #7." << endl; } if (v->REG0 & BIT4) { cout << "Reg0:b4 -> Line interrupt is enabled." << endl; } else { cout << "Reg0:b4 -> Line interrupt is disabled." << endl; } if (v->REG0 & BIT3) { cout << "Reg0:b3 -> Shift sprites left by 8 pixels." << endl; } else { cout << "Reg0:b3 -> Do not shift sprites left by 8 pixels." << endl; } if (v->REG0 & BIT2) { cout << "Reg0:b2 -> 1 (Use Mode 4)" << endl; } else { cout << "Reg0:b2 -> 0 (Do not use mode 4, Use TMS9918 modes (selected with M1, M2, M3." << endl; } if (v->REG0 & BIT1) { cout << "Reg0:b1 -> 1 (Must be 1 for M1/M3 to change screen height in Mode 4)." << endl; } else { cout << "Reg0:b1 -> 0 (Must be 1 for M1/M3 to change screen height in Mode 4)." << endl; } if (v->REG0 & BIT0) { cout << "Reg0:b0 -> No sync, display is monochrome." << endl; } else { cout << "Reg0:b0 -> Sync, normal display." << endl; } cout << "* VDP Register 1:" << endl; if (v->REG1 & BIT7) { cout << "Reg1:b7 -> 1, Unused." << endl; } else { cout << "Reg1:b7 -> 0, Unused." << endl; } if (v->REG1 & BIT6) { cout << "Reg1:b6 -> Display enabled." << endl; } else { cout << "Reg1:b6 -> Display disabled." << endl; } if (v->REG1 & BIT5) { cout << "Reg1:b5 -> Frame interrupt enabled." << endl; } else { cout << "Reg1:b5 -> Frame interrupt disabled." << endl; } if (v->REG1 & BIT4) { cout << "Reg1:b4 -> 1, (if 1, Selects 224-line screen for Mode 4 if M2=1)." << endl; } else { cout << "Reg1:b4 -> 0, (if 1, Selects 224-line screen for Mode 4 if M2=1)." << endl; } if (v->REG1 & BIT3) { cout << "Reg1:b3 -> 1, (if 1, Selects 240-line screen for Mode 4 if M2=1)." << endl; } else { cout << "Reg1:b3 -> 0, (if 1, Selects 240-line screen for Mode 4 if M2=1)." << endl; } if (v->REG1 & BIT2) { cout << "Reg1:b2 -> 1, Unused." << endl; } else { cout << "Reg1:b2 -> 0, Unused." << endl; } if (v->REG1 & BIT1) { cout << "Reg1:b1 -> 1, Sprites are 16x16,(TMS9918), Sprites are 8x16, (Mode 4)." << endl; } else { cout << "Reg1:b1 -> 0 Sprites 8x8 (TMS9918), Sprites are 8x8 (Mode 4)." << endl; } if (v->REG1 & BIT0) { cout << "Reg1:b0 -> Sprite pixels are doubled in size." << endl; } else { cout << "Reg1:b0 -> Sprite pixels are NOT doubled in size.." << endl; } cout << "* VDP Status:" << endl; if (v->vdp_status & BIT7) { cout << "VDP Status:b7 -> 1, Frame interrupt pending." << endl; } else { cout << "VDP Status:b7 -> 0, No frame interrupt pending." << endl; } if (v->getIrqLinePending()) { cout << "VDP :Line IRQ pending." << endl; } else { cout << "VDP :No Line IRQ pending." << endl; } if (v->vdp_status & BIT6) { cout << "VDP Status:b6 -> 1, Sprite overflow flag is set." << endl; } else { cout << "VDP Status:b6 -> 0, Sprite overflow flag is not set." << endl; } if (v->vdp_status & BIT5) { cout << "VDP Status:b5 -> 1, Sprite collision flag is set." << endl; } else { cout << "VDP Status:b5 -> 0, Sprite collision flag is not set." << endl; } cout << "Line=" << dec << setw(3) << setfill('0') << (int)v->line ; cout << " / VRAM addr=" << hex << setw(4) << setfill('0') << (int)v->getVRAMAddr(); cout << " / Spr. table=" << hex << setw(4) << setfill('0') << (int)v->sit_addr ; cout << " / Tile table=" << hex << (int)v->map_addr << endl; cout << "i_counter (REG10) =" << dec << setw(3) << setfill('0') << (int)v->i_counter << endl; } /*--------------------------------------------------------------------*/ /* This method displays Z80 registers . */ /*--------------------------------------------------------------------*/ void SmsDebugger::dumpRegisters() { cout << "A=" << hex << setw(2) << setfill('0') << (int)cpu->A; cout << " B=" << hex << setw(2) << setfill('0') << (int)cpu->B; cout << " C=" << hex << setw(2) << setfill('0') << (int)cpu->C; cout << " D=" << hex << setw(2) << setfill('0') << (int)cpu->D; cout << " E=" << hex << setw(2) << setfill('0') << (int)cpu->E; cout << " H=" << hex << setw(2) << setfill('0') << (int)cpu->H; cout << " L=" << hex << setw(2) << setfill('0') << (int)cpu->L; cout << " Flag=" << hex << setw(2) << setfill('0') << (int)cpu->F; cout << endl; cout << "PC=" << hex << setw(4) << setfill('0') << (int)cpu->PC; cout << " SP=" << hex << setw(4) << setfill('0') << (int)cpu->SP; cout << " IX=" << hex << setw(4) << setfill('0') << (int)cpu->IX; cout << " IY=" << hex << setw(4) << setfill('0') << (int)cpu->IY; cout << " I=" << hex << setw(2) << setfill('0') << (int)cpu->I; cout << " R=" << hex << setw(2) << setfill('0') << (int)cpu->R; cout << endl; } /*--------------------------------------------------------------------*/ /* This method will remove ALL debugger breakpoints. */ /*--------------------------------------------------------------------*/ void SmsDebugger::clearBreakpoints() { /* Set break point to unused value */ for (int i=0;i MAX_BREAKPOINTS, the first breakpoint will be */ /* overwritten. This is a circular buffer. */ /*--------------------------------------------------------------------*/ void SmsDebugger::addBreakpoint(int ad) { if (ad >0xFFFF) { cout << "Breakpoint address is out of range."<< endl; return; } breakpoints[bp_index] = ad; any_breakpoint = true; bp_index++; if (bp_index>=MAX_BREAKPOINTS) { bp_index = 0; } cout << "Breakpoint added at address "<< hex << setw(4) << setfill('0') << ad <<"."<< endl; } /*--------------------------------------------------------------------*/ /* This method will list all debugger breakpoints. */ /*--------------------------------------------------------------------*/ void SmsDebugger::listBreakpoints() { int nb =0; if (any_breakpoint) { for (int i=0;idumpCRAM(); return; } if (strcmp(cmd,"s")==0 ) { /* Trace one instruction */ cpu_steping = true; end_session = true; return; } if (strcmp(cmd,"lbp")==0 ) { listBreakpoints(); return; } if (strcmp(cmd,"slbp")==0 ) { cout << "Scanline breakpoint on scanline : 0x" << hex << scanlineBreakpoint << "." << endl; return; } if (strcmp(cmd,"u")==0 ) { /* unassemble 16 instructions from PC. */ param1 = cpu->PC; for (int i=0;i<16;i++) { param1 = dasm->disasm(param1); } printf("\n"); return; } /* Dump 16 block of 16 bytes memory from PC. */ if (strcmp(cmd,"d")==0 ) { mem->dump_mem(cpu->PC, 16); return; } if (strcmp(cmd,"bpdi")==0 ) { breakpoint_on_disable_interrupt ^= 1; if (breakpoint_on_disable_interrupt) cout << "Breakpoints when CPU exec DI: ON" << endl; else cout << "Breakpoints when CPU exec DI: OFF" << endl; return; } if (strcmp(cmd,"bpei")==0 ) { breakpoint_on_enable_interrupt ^= 1; if (breakpoint_on_enable_interrupt) cout << "Breakpoints when CPU exec EI: ON" << endl; else cout << "Breakpoints when CPU exec EI: OFF" << endl; return; } unknownCommand(); } /*--------------------------------------------------------------------*/ /* This method exec a command with two parameters. */ /*--------------------------------------------------------------------*/ void SmsDebugger::exec_cmd(char *cmd, int param1, int param2) { if (strcmp(cmd,"u")==0 ) { /* unassemble 16 instructions */ for (int i=0;i<16;i++) { param1 = dasm->disasm(param1); } printf("\n"); return; } if (strcmp(cmd,"d")==0 ) { mem->dump_mem(param1, 16); return; } if (strcmp(cmd,"dsram")==0 ) { mem->dump_smem(param1, 16); return; } if (strcmp(cmd,"dvram")==0 ) { v->dumpVRAM(param1, 16); return; } if (strcmp(cmd,"bp")==0 ) { addBreakpoint(param1); return; } if (strcmp(cmd,"slbp")==0 ) { setScanlineBreakpoint(param1); return; } unknownCommand(); return; } void SmsDebugger::unknownCommand() { cout << "Unknown command." << endl; } void SmsDebugger::setScanlineBreakpoint(int scanline) { scanlineBreakpoint = scanline; cout << "Set Breakpoint on scanline " << dec << scanlineBreakpoint << endl; } /*--------------------------------------------------------------------*/ /* DebugEventListener interface implementation. */ /*--------------------------------------------------------------------*/ void SmsDebugger::sendDebugEvent(int event_type, char *source, char *message) { /* Display debugEvent message. */ switch (event_type) { case DbgEvtCpuStep: if (cpu_steping || !end_session) { cpu_steping = false; end_session = false; enter(); } else { if (any_breakpoint) { for (int i=0;iPC ) { end_session = false; cout <<"Reach Breakpoint at :" << hex << cpu->PC << endl; enter(); } } } } break; case DbgEvtUserTrigger: cout << "DBG EVT from " << source <<" : " << message << endl; end_session = false; enter(); break; case DbgEvtScanlineBreakpoint: /* Check scanline breakpoint.*/ if (v->line == scanlineBreakpoint) { cout << "DBG EVT from " << source <<" : " << message << endl; end_session = false; enter(); } break; case DbgEvtCpuIrqAsserted: if (breakpoint_on_irq) { cout << "DBG EVT from " << source <<" : " << message << endl; end_session = false; enter(); } break; case DbgEvtCpuDisableInterrupt: if (breakpoint_on_disable_interrupt) { cout << "DBG EVT from " << source <<" : " << message << endl; end_session = false; enter(); } break; case DbgEvtCpuEnableInterrupt: if (breakpoint_on_enable_interrupt) { cout << "DBG EVT from " << source <<" : " << message << endl; end_session = false; enter(); } break; case DbgEvtGeneric: cout << "DBG EVT from " << source <<" : " << message << endl; end_session = false; enter(); break; default: cout << "UNKNOWN DBG EVT from " << source <<" : " << message << endl; end_session = false; break; } } osmose-emulator-1.4/src/SmsDebugger.h000066400000000000000000000056671341430144300176730ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef SMS_DEBUGGER_H #define SMS_DEBUGGER_H #include "Definitions.h" #include "MemoryMapper.h" #include "IOMapper.h" #include "SmsEnvironment.h" #include "z80_disasm/Z80Dasm.h" #include "VDP.h" #include "DebugEventListener.h" using namespace std; #define MAX_BREAKPOINTS 16 class SmsDebugger : public DebugEventListener { public: SmsDebugger(); void setCPU(Z80 *c) { cpu = c; } void setMemoryMapper(MemoryMapper *mm) { mem = mm; } void setEnvironment(SmsEnvironment *se) { env = se; } void setVDP(VDP *vd) { v = vd; } void setIOMapper(IOMapper *im) { iom = im; } void setDasm(Z80Dasm *d) { dasm = d; } void enter(); /* DebugEventListener interface implementation. */ void sendDebugEvent(int event_type, char* src, char *message); protected: MemoryMapper *mem; SmsEnvironment *env; VDP *v; IOMapper *iom; Z80Dasm *dasm; Z80 *cpu; private: int scanlineBreakpoint; bool any_breakpoint; /* Flag to avoid bp search. */ bool end_session; /* Have we leaved the debugger ? */ bool breakpoint_on_irq; bool breakpoint_on_enable_interrupt; bool breakpoint_on_disable_interrupt; bool cpu_steping; int breakpoints[MAX_BREAKPOINTS]; /* INTeger chose to allow -1 value */ unsigned int bp_index; /* Index in circular buffer of bp. */ void help(); void dpr(); void dvdpr(); void vdpi(); void dvram(); void dumpRegisters(); void clearBreakpoints(); void addBreakpoint(int add); void listBreakpoints(); void setScanlineBreakpoint(int scanline); void exec_cmd(char *cmd, int param1); void exec_cmd(char *cmd, int param1, int param2); void unknownCommand(); }; #endif osmose-emulator-1.4/src/SmsEnvironment.cpp000066400000000000000000000050161341430144300207720ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include #include // for trace in hexa in rw port #include "Z80.h" #include "SmsEnvironment.h" using namespace std; /** Constructor. */ SmsEnvironment::SmsEnvironment() { // dasm = new Z80Dasm(*this); } /** Destructor. */ SmsEnvironment::~SmsEnvironment() { } void SmsEnvironment::disasm(u16 IP) { // This is done to avoid multiple disassembly of LDIR OTIR... instructions. static unsigned int last_pc = 0x10000; // impossible value in IP. //if (last_pc != IP) { //dasm->disasm(IP); last_pc = IP; } } /** Called immediately after a RETI is executed. */ void SmsEnvironment::onReturnFromInterrupt() { } void SmsEnvironment::onInterruptsEnabled() { if (v->irqAsserted()) { cpu->interrupt(0xff); } } void SmsEnvironment::setMemoryMapper(MemoryMapper *m) { mmapper = m; } void SmsEnvironment::setIOMapper(IOMapper *m) { iomapper = m; } void SmsEnvironment::setVDP(VDP *vdp) { v = vdp; } void SmsEnvironment::setCPU(Z80 *c) { cpu = c; } /* 8 bits read operation. */ u8 SmsEnvironment::rd8( u16 addr ) { //printf("r%.4x\n", addr); return mmapper->rd8(addr & 0xFFFF); } /* 8 bits write operation. */ void SmsEnvironment::wr8( u16 addr, u8 value ) { //printf("w%.4x, %.2x\n", addr, value); mmapper->wr8(addr & 0xFFFF, value); } /* 8 bits read IO operation. */ u8 SmsEnvironment::in( u16 port ) { //printf("i%.4x\n", port & 0xff); return iomapper->in8(port & 0xff); } /* 8 bits write IO operation. */ void SmsEnvironment::out( u16 port, u8 value ) { //printf("o%.2x, %.2x\n", port & 0xff, value); iomapper->out8(port & 0xff,value); } osmose-emulator-1.4/src/SmsEnvironment.h000066400000000000000000000045511341430144300204420ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef SMS_ENVIRONMENT_H #define SMS_ENVIRONMENT_H #include "Definitions.h" #include #include "Z80.h" #include "MemoryMapper.h" #include "IOMapper.h" #include "IOMapper_GG.h" #include "VDP.h" using namespace std; class SmsEnvironment : public Z80Environment { public: /** Constructor. */ SmsEnvironment(); /** Destructor. */ virtual ~SmsEnvironment(); virtual void disasm(u16 IP); virtual void onReturnFromInterrupt(); virtual void onInterruptsEnabled(); virtual void setMemoryMapper(MemoryMapper *m); virtual void setIOMapper(IOMapper *m); virtual void setVDP(VDP *v); virtual void setCPU(Z80 *c); // New core wrappers virtual u8 rd8( u16 addr ); virtual void wr8( u16 addr, u8 value ); virtual u8 in( u16 port ); virtual void out( u16 port, u8 value ); // Old Core Wrapper: virtual unsigned char readByte( unsigned addr ) { return rd8(addr); }; virtual void writeByte( unsigned addr, unsigned char data ) { wr8(addr, data); }; virtual void writePort( unsigned port, unsigned char data ) { out(port, data); }; virtual unsigned char readPort( unsigned addr ) { return in(addr); }; protected: MemoryMapper *mmapper; IOMapper *iomapper; VDP *v; Z80 *cpu; }; #endif osmose-emulator-1.4/src/SoundThread.cpp000066400000000000000000000175621341430144300202340ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ // Interleaved mode is not supported by some cards. However, since Osmose // is only using 1 single chanel (MONO), this feature can be disabled. // Contributed by: Kevin Joly (Kev-J) #include "SoundThread.h" #include /** * Constructor. */ SoundThread::SoundThread(const char *devName, FIFOSoundBuffer *sb) { /* Make a deep copy of the device name */ memcpy(deviceName, devName, DEVICE_NAME_LENGTH); initAlsa(); state = Paused; mutex = PTHREAD_MUTEX_INITIALIZER; sndFIFO = sb; } /** * Destructor. */ SoundThread::~SoundThread() { // Set state to stopped and join ourself. state = Stopped; this->join(NULL); // THEN, close the audio device. snd_pcm_close (playback_handle); } /** * This is the main Sound thread loop. */ void* SoundThread::run(void *p) { (void)p; SoundThreadState local_state_copy; { MutexLocker lock(&mutex); local_state_copy = state; } while(local_state_copy != Stopped) { switch(local_state_copy) { case Playing: play(); break; case Paused: struct timespec rqtp; rqtp.tv_sec = 0; rqtp.tv_nsec = 1000000; // 1 millisecond. nanosleep(&rqtp, NULL); // NULL = don't care about remaining time if interrupted. break; default: // Stopped means that thread is terminating. break; } { // Locked section. MutexLocker lock(&mutex); local_state_copy = state; } } // We are Leaving the thread. return (void *)0xDEADBEEF; } void SoundThread::play() { int err; /* wait till the interface is ready for data, or 16 milli second has elapsed. */ if ((err = snd_pcm_wait(playback_handle, 16)) < 0) { fprintf(stderr, "poll failed (%s)\n", strerror (errno)); } /* find out how much space is available for playback data */ if ((frames_to_deliver = snd_pcm_avail_update (playback_handle)) < 0) { if (frames_to_deliver == -EPIPE) { fprintf (stderr, "an xrun occurred\n"); } else { fprintf (stderr, "unknown ALSA avail update return value (%d)\n", (int)frames_to_deliver); } } frames_to_deliver = frames_to_deliver > 4096 ? 4096 : frames_to_deliver; /* deliver the data */ if (playback_callback (frames_to_deliver) != frames_to_deliver) { fprintf (stderr, "playback callback failed\n"); } } int SoundThread::playback_callback (snd_pcm_sframes_t nframes) { int err; //printf ("playback callback called with %d frames\n", (int)nframes); //void *channelsbuffer[1]; //channelsbuffer[0] = &samplebuffer; sndFIFO->read(samplebuffer, nframes); //if ((err = snd_pcm_writen(playback_handle, (void **)channelsbuffer, nframes)) < 0) if ((err = snd_pcm_writei(playback_handle, samplebuffer, nframes)) < 0) { fprintf (stderr, "write failed (%s)\n", snd_strerror (err)); } return err; } /** * */ void SoundThread::stop() { MutexLocker lock(&mutex); state = Stopped; // Perform ALSA shutdown ! } /** * */ void SoundThread::pause() { MutexLocker lock(&mutex); state = Paused; // Perform ALSA Pause } /** * */ void SoundThread::resume() { MutexLocker lock(&mutex); state = Playing; // Perform ALSA start/continue ! } /** * This method prepares ALSA system for 22050hz signed 16bits Little Endian * playback. */ void SoundThread::initAlsa() { int err; ostringstream oss; /* Get a handle on the PCM device. */ if ((err = snd_pcm_open (&playback_handle, deviceName, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { oss << "cannot open audio device : " << deviceName << snd_strerror(err) << endl; throw oss.str(); } /* Allocate snd_pcm_hw_params_t structure. */ if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { oss << "cannot allocate hardware parameter structure : " << snd_strerror (err) << endl; throw oss.str(); } /* Retrieve current parameters. */ if ((err = snd_pcm_hw_params_any (playback_handle, hw_params)) < 0) { oss << "cannot initialize hardware parameter structure : " << snd_strerror (err) << endl; throw oss.str(); } /* Set Sample are NON Interleaved (mono !) */ //if ((err = snd_pcm_hw_params_set_access (playback_handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED)) < 0) //{ // oss << "cannot set access type : " << snd_strerror (err) << endl; // throw oss.str(); //} /* Set Sample format: Signed 16bit little endian. */ if ((err = snd_pcm_hw_params_set_format (playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) { oss << "cannot set sample format : " << snd_strerror (err) << endl; throw oss.str(); } /* Set the Sample rate. */ if ((err = snd_pcm_hw_params_set_rate (playback_handle, hw_params, 22050, 0)) < 0) { oss << "cannot set sample rate : " << snd_strerror (err) << endl; throw oss.str(); } /* Set Channel number (MONO). */ if ((err = snd_pcm_hw_params_set_channels (playback_handle, hw_params, 1)) < 0) { oss << "cannot set channel count : " << snd_strerror (err) << endl; throw oss.str(); } if ((err = snd_pcm_hw_params_set_buffer_size(playback_handle, hw_params, 2048)) < 0) { oss << "cannot set channel buffer size : " << snd_strerror (err) << endl; throw oss.str(); } /* Apply these parameters. */ if ((err = snd_pcm_hw_params (playback_handle, hw_params)) < 0) { oss << "cannot apply parameters : " << snd_strerror (err) << endl; throw oss.str(); } snd_pcm_uframes_t bufferSize; snd_pcm_hw_params_get_buffer_size( hw_params, &bufferSize ); //cout << "initAlsa: Buffer size = " << bufferSize << " frames." << endl; /* Free memoray allocated for snd_pcm_hw_params_t */ snd_pcm_hw_params_free (hw_params); /* tell ALSA to wake us up whenever 4096 or more frames of playback data can be delivered. Also, tell ALSA that we'll start the device ourselves. */ /* Allocate snd_pcm_sw_params_t structure. */ if ((err = snd_pcm_sw_params_malloc (&sw_params)) < 0) { oss << "cannot allocate software parameters structure : " << snd_strerror (err) << endl; throw oss.str(); } /* Get the current software configuration*/ if ((err = snd_pcm_sw_params_current (playback_handle, sw_params)) < 0) { oss << "cannot initialize software parameters structure : " << snd_strerror (err) << endl; throw oss.str(); } /* Set the wake up point to 2048 (92.9 ms). The minimum data available before asking*/ /* for new ones. */ if ((err = snd_pcm_sw_params_set_avail_min (playback_handle, sw_params, 2048U)) < 0) { oss << "cannot set minimum available count : " << snd_strerror (err) << endl; throw oss.str(); } /* Set when ALSA starts to play. */ if ((err = snd_pcm_sw_params_set_start_threshold (playback_handle, sw_params, 1024U)) < 0) { oss << "cannot set start mode : " << snd_strerror (err) << endl; throw oss.str(); } /* Apply parameters. */ if ((err = snd_pcm_sw_params (playback_handle, sw_params)) < 0) { oss << "cannot apply software parameters : " << snd_strerror (err) << endl; throw oss.str(); } /* the interface will interrupt the kernel every 4096 frames, and ALSA will wake up this program very soon after that. */ if ((err = snd_pcm_prepare (playback_handle)) < 0) { oss << "cannot prepare audio interface for use : " << snd_strerror (err) << endl; throw oss.str(); } } osmose-emulator-1.4/src/SoundThread.h000066400000000000000000000034061341430144300176710ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef SOUNDTHREAD_H #define SOUNDTHREAD_H #include #include #include #include #include "FIFOSoundBuffer.h" #include "Pthreadcpp.h" using namespace std; #define DEVICE_NAME_LENGTH 64 class SoundThread : public Thread { enum SoundThreadState { Playing, Paused, Stopped }; public: SoundThread(const char *devName, FIFOSoundBuffer *); void stop(); void pause(); void resume(); ~SoundThread(); protected: void* run(void *p); private: char deviceName[DEVICE_NAME_LENGTH]; snd_pcm_t *playback_handle; short samplebuffer[4096]; snd_pcm_hw_params_t *hw_params; snd_pcm_sw_params_t *sw_params; snd_pcm_sframes_t frames_to_deliver; void initAlsa(); void play(); int playback_callback (snd_pcm_sframes_t nframes); SoundThreadState state; pthread_mutex_t mutex; FIFOSoundBuffer *sndFIFO; }; #endif // SOUNDTHREAD_H osmose-emulator-1.4/src/TGAWriter.cpp000066400000000000000000000037061341430144300176170ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "TGAWriter.h" TGAWriter::TGAWriter(const char *filename, int width, int height) { /* Initialise TGA Header with the given informations.*/ header.identsize = 0; header.colourmaptype = 0; /* No palette. */ header.imagetype = 2; /* RGB picture. */ header.colourmapstart = 0; /* No colormap. */ header.colourmaplength =0; header.colourmapbits = 0; header.xstart = 0; header.ystart = 0; header.width = width; header.height = height; header.bits = 24; /* 24Bits RGB. */ header.descriptor = 0; tgaFile = new ofstream(filename, ios::binary | ios::out); isOk_ = tgaFile->is_open(); tgaFile->write((char *)&header, sizeof(TGAHeader)); cacheIndex = 0; } TGAWriter::~TGAWriter() { flushCache(); tgaFile->close(); } void TGAWriter::writePixel(unsigned char r, unsigned char g,unsigned char b) { if (cacheIndex > INTERNAL_CACHE_SIZE -3) { flushCache(); } cache[cacheIndex++] = b; cache[cacheIndex++] = g; cache[cacheIndex++] = r; } void TGAWriter::flushCache() { if (cacheIndex != 0) { tgaFile->write((char *)cache, cacheIndex); } cacheIndex = 0; } osmose-emulator-1.4/src/TGAWriter.h000066400000000000000000000044611341430144300172630ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef TGA_WRITER_H #define TGA_WRITER_H #include #include using namespace std; #define INTERNAL_CACHE_SIZE 4096 struct TGAHeader { unsigned char identsize; // size of ID field that follows 18 byte header (0 usually) unsigned char colourmaptype; // type of colour map 0=none, 1=has palette unsigned char imagetype; // type of image 0=none,1=indexed,2=rgb,3=grey,+8=rle packed short colourmapstart; // first colour map entry in palette short colourmaplength; // number of colours in palette char colourmapbits; // number of bits per palette entry 15,16,24,32 short xstart; // image x origin short ystart; // image y origin short width; // image width in pixels short height; // image height in pixels unsigned char bits; // image bits per pixel 8,16,24,32 unsigned char descriptor; // image descriptor bits (vh flip bits) } __attribute__((packed)); // Required to avoid gcc to align data. class TGAWriter { public: TGAWriter(const char *fn, int width, int height); ~TGAWriter(); bool isOk() {return isOk_;} void writePixel(unsigned char r, unsigned char g,unsigned char b); private: void flushCache(); unsigned int cacheIndex; bool isOk_; struct TGAHeader header; ofstream *tgaFile; unsigned char cache[INTERNAL_CACHE_SIZE]; }; #endif osmose-emulator-1.4/src/VDP.cpp000066400000000000000000000746151341430144300164470ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "VDP.h" extern Options opt; // Pre calculated Vertical count values, for 192 line NTSC video. unsigned char vcount_ntsc_192[262] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF }; // Pre calculated Vertical count values, for 192 line pal/secam video. unsigned char vcount_palsecam_192[313] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF }; /* Constructor */ VDP::VDP(Z80 *c, bool ntsc) { cpu = c; VRAM = new unsigned char[0x4000]; CRAM = new unsigned char[64]; colors = new unsigned int[64]; // Select appropriate vcount array, depending on ntsc/pal option. if (ntsc == true) { v_cnt = vcount_ntsc_192; } else { v_cnt = vcount_palsecam_192; } if ((VRAM !=NULL) && (CRAM !=NULL)) { for (int i=0; i < 64; i++) { CRAM[i] = 0x0; } for (int i=0; i < 0x4000; i++) { VRAM[i] = 0x0; } reset(); } else { cerr << RED("Unable to allocate memory for ROM banks !") << endl; cerr << RED("Exiting.") << endl; ::exit(-1); } } /*-------------------------------------------------------------*/ /* This method handles write operation on the VDP data port. */ /*-------------------------------------------------------------*/ void VDP::writeDataPort(unsigned char data) /* Port 0xBE written */ { cmd_flag = false; rd_data_port_buffer = data; // CMD docs says that write, load buffer with it's value. // destination is VRAM or CRAM ? if (cmd_type == 3) { CRAM[addr & 0x1F] = data; // data not anded with 1f. It's done with rgb rate. #ifdef VDP_VERBOSE cout << "CRAM written: at 0x" << hex << setw(4) << setfill('0')<< addr << " with value "<< setw(2) << setfill('0') << (int)data <> 2) &3]; b = b_col[(data >> 4) &3]; out = (unsigned int) (0xFF000000 | (b << 16) | (g << 8) | r); return out; } /*---------------------------------------------------------------*/ /* This method convert 12bit xxxxRRRRGGGGBBBB to 32 bits */ /* 11111111BBBBBBBGGGGGGGGRRRRRRRR colors . */ /*---------------------------------------------------------------*/ unsigned int VDP::colorGG12BitsToColor32Bits(unsigned short data) { unsigned char r, g, b; r = (data & 0xF) << 4; g = ((data >> 4) & 0xF)<<4; b = ((data >> 8) & 0xF)<<4; return (unsigned int)(b << 16) | (g <<8) | (r); } /*-------------------------------------------------------------*/ /* This method handles read operation on the VDP data port. */ /*-------------------------------------------------------------*/ unsigned char VDP::readDataPort() /* Port 0xBE read */ { unsigned char r; cmd_flag = false; r = rd_data_port_buffer; #ifdef VDP_VERBOSE cout << "VRAM read: at 0x" << hex << setw(4) << setfill('0')<< addr << " value = "<< setw(2) << setfill('0') <<(int)r <> 6; /* 2second byte MSB are cmd type */ addr = ( (data & 0x3F ) << 8) | latch; if (cmd_type == 0) { rd_data_port_buffer = VRAM[addr]; addr = (addr +1) & 0x3FFF; } if (cmd_type == 2) // Cmd: 10 VDP register write */ { writeRegs(data & 0xF, latch); } #ifdef VDP_VERBOSE switch (cmd_type) { case 0: cout << "VRAM read: VDP Addr set to 0x" << hex << setw(4) << setfill('0')<< addr << endl; break; case 1: cout << "VRAM write: VDP Addr set to 0x" << hex << setw(4) << setfill('0')<< addr << endl; break; case 2: cout << "REG write: VDP Regs " << (int)(data & 0xF) << " written with value "<< hex << setw(2) << setfill('0')<<(int)latch << endl; break; case 3: cout << "CRAM write: Addr in palete is " << hex << setw(4) << setfill('0')<<(int)addr << endl; break; } #endif } } /*------------------------------------------------------------*/ /* Call back when port BF/BD is read. */ /*------------------------------------------------------------*/ unsigned char VDP::readStatusFlag() { unsigned char tmp; cmd_flag = false; // this flag is cleared when Ctrl port is read. tmp = vdp_status; vdp_status &= 0x1f; // Clear bit 6 & 7 from vdp_status. irq_line_pending = false; vsynch_irq_pending = false; updateIRQAssertion(); return tmp; } /*------------------------------------------------------------*/ /* This method return VDP RAM internal pointer. */ /*------------------------------------------------------------*/ unsigned short VDP::getVRAMAddr() { return addr; } /*------------------------------------------------------------*/ /* This method will reset the VDP by setting latch / regs */ /* to Zero, supposing it's the thing to do ! */ /*------------------------------------------------------------*/ void VDP::reset() { addr = 0; latch = 0; cmd_flag = false; v_counter = 0; i_counter = 0xFF; vdp_status= 0x1f; // 00011111b line = 0; sms_irq = false; irq_line_pending = false; vsynch_irq_pending = false; cmd_type = 0; rd_data_port_buffer = 0; if (emu_opt.bright_palette == true) { /* r_col[0] = 0; r_col[1] = 10; r_col[2] = 21; r_col[3] = 31; g_col[0] = 0; g_col[1] = 21; g_col[2] = 42; g_col[3] = 63; b_col[0] = 0; b_col[1] = 10; b_col[2] = 21; b_col[3] = 31; */ r_col[0] = 0x00; r_col[1] = 0x55; r_col[2] = 0xAA; r_col[3] = 0xFF; g_col[0] = 0x00; g_col[1] = 0x55; g_col[2] = 0xAA; g_col[3] = 0xFF; b_col[0] = 0x00; b_col[1] = 0x55; b_col[2] = 0xAA; b_col[3] = 0xFF; } else { /* r_col[0] = 0; r_col[1] = 8; r_col[2] = 16; r_col[3] = 24; g_col[0] = 0; g_col[1] = 16; g_col[2] = 32; g_col[3] = 48; b_col[0] = 0; b_col[1] = 8; b_col[2] = 16; b_col[3] = 24; */ r_col[0] = 0x00; r_col[1] = 0x55; r_col[2] = 0xAA; r_col[3] = 0xFF; g_col[0] = 0x00; g_col[1] = 0x55; g_col[2] = 0xAA; g_col[3] = 0xFF; b_col[0] = 0x00; b_col[1] = 0x55; b_col[2] = 0xAA; b_col[3] = 0xFF; } for (int i=0; i map default to 0x3800 in VRAM */ map_addr = 0x3800; /* REG2 converted into VRAM address. */ REG5 = 0x7E; /* x111111x -> sit default to 0x3F00 in VRAM */ sit_addr = 0x3F00; /* REG5 converted into VRAM address. */ REG10 = 0xFF; /* No Line Interrupt */ #ifdef BUILT_IN_DEBUGGER irq_accepted = false; #endif } /*------------------------------------------------------------*/ /* This is a debugging purpose function. */ /* Note that this method will dump VDP VRAM. */ /*------------------------------------------------------------*/ void VDP::dumpVRAM(unsigned int sa, int nb_lines) { cout << "Dumping VDP RAM:"<> 1) & 0x3F) << 8 ); break; } #ifdef VDP_VERBOSE if (r == 2 || r==5) { cout << "VDP REGISTER: tile map address set to 0x" << hex << setw(4) << setfill('0') << map_addr << endl; cout << "VDP REGISTER: sprite information table set to 0x" << hex << setw(4) << setfill('0') << sit_addr << endl; } #endif } /*------------------------------------------------------------*/ /* This method is called when a scanline has been drawn. */ /* It draws one line in screen. Set sms_irq if VDP triggers */ /* an interrupt. */ /* If drawline is true, line render is done else it's skipped */ /* This is for frame skip, to handle interrupt system, but to */ /* avoid drawing line if frame is not displayed. */ /*------------------------------------------------------------*/ void VDP::update(unsigned int *s, bool drawline) { if (line < 0xC0) { if (drawline == true) { traceBackGroundLine(s); } } /* V-Blank interrupt. */ if (line == 0xC1) { vdp_status |= BIT7; vsynch_irq_pending = true; } /* Line interrupt. */ if (line < 193) { i_counter--; /* Line counter overflow. */ if (i_counter == 0xFF) { i_counter = REG10; irq_line_pending = true; } } else i_counter = REG10; updateIRQAssertion(); v_counter = v_cnt[line]; #ifdef BUILT_IN_DEBUGGER /* This event is thrown on every scanline. The dedbugger will react depending on the scanline break point. */ throwDebugEvent(DbgEvtScanlineBreakpoint,"VDP", "End of current Scanline."); #endif } /*------------------------------------------------------------*/ /* This method update sms_irq value depending on VDP registers*/ /* and interrupt pending. */ /*------------------------------------------------------------*/ void VDP::updateIRQAssertion() { sms_irq = false; if (irq_line_pending && (REG0 & BIT4)) { sms_irq = true; //cout << "IRQ from Line IRQ " << dec <step(); cpu->interrupt( 0xFF ); } } /*--------------------------------------------------------------*/ /* This method draws a scanline. */ /* */ /* Drawing is done in two pass: */ /* - Render tile background */ /* (sprite are rendered, then) */ /* - Render tile that cover sprites */ /*--------------------------------------------------------------*/ void VDP::traceBackGroundLine(unsigned int *s) { unsigned int c,pos; unsigned int *dst; unsigned int *scr; unsigned short currentTile; unsigned char i, o, x, y, col_index, attrib; int current_line; unsigned int p; /* scr ptr in our SDL_Surface points line to be drawn. */ scr = (unsigned int*) s + (256 * line); /* Draw a blank line directly in screen if display is disabled. */ if (!(REG1 & BIT6)) { memset(scr,0x0, 0x400); // 0x200 means 256 32bits pixels. return; } /* Our destination is one 256 pixel line. */ dst = line_buffer; /* Clear our tileMask. */ memset(tile_mask,0x00, 0x100); /* Note that x is never tested for >255 since it automaticaly wraps due to it's unsigned char declaration. */ /* Now, for 32 tiles... */ for (o=0; o<32;o++) { /* x = X scroll register, y = Y scroll register. */ y = REG9; x = REG8; /* Top 2 rows of screen not affected by horizontal scrolling. */ if ((REG0 & BIT6) && (line<=15)) { x = 0; } x += o *8; /* current_line = current line + scroll register modulated to stay in screen. 192 could be OK. */ if ((o >= 24) && (REG0 & BIT7)) { /* Disable vertical scrolling for columns 24-31 */ current_line = ((line) % 224); } else { current_line = ((line+y) % 224); } /* Now get VRAM index of the Tile/attrib in VDP memory. 8x8 Tile at Coord x, y = (x*64) + (y /8) x * 64 because a line is 32 tiles, with 2 bytes for tile index and attribute. y /8 because a tile is made of 8 lines. */ pos = ((current_line>>3)<<6) + o * 2; /* get it's tile Index. */ currentTile = VRAM[ map_addr + pos++]; /* get it's attribute. */ attrib = VRAM[ map_addr + pos++]; if (attrib & BIT0) { currentTile |=0x100; // 9th tile index bit. } // line in tile converted to VRAM ind if (attrib & BIT2) { // Verticaly flipped tile. c = ((7 - (current_line & 7))<<2) + (currentTile<<5); } else { c = ((current_line & 7)<<2) + (currentTile<<5); } // Four bytes are read into one 32bits variable. This avoid 3 memory access. // Bits plan are like this in the variable (intel architecture): // P3P2P1P0 which is inverse order or ram content. This is due to intel // endianness unsigned int *cst = (unsigned int *) &VRAM[c]; p = *cst; // Patch for PowerPC indianess. //p = (p >> 24) | ((p & 0x00FF0000) >> 8) | ((p & 0x0000FF00)<< 8) | (( p &0xFF)<<24); c += 4; // Draw 8 horizontals pixels. switch ((attrib>>1) & 3) { case 0: // Tile not flipped for ( i = 0; i<8; i++) { col_index = ((p >>7)&1) | (((p >> 15)<<1)&2) | (((p >> 23)<<2)&4) | ((p >> 31)<<3); if (attrib & BIT3) col_index|=0x10; // Then use sprite palete dst[x] = colors[col_index]; if ((attrib & BIT4) && (col_index != 0x10) && (col_index !=0x0)) { tile_mask[x] = 1; } x++; p<<=1; } break; case 1: // Tile flipped on x for ( i = 0; i<8; i++) { col_index = (p&1) | ((p>>8) & 1)<<1 | ((p>>16) & 1 )<<2 | ((p >>24) &1)<<3; if (attrib & BIT3) col_index|=0x10; // Then use sprite palete dst[x] = colors[col_index]; if ((attrib & BIT4) && (col_index != 0x10) && (col_index !=0x0)) { tile_mask[x] = 1; } x++; p>>=1; } break; case 2: // Tile flipped on y for (int i=0; i<8;i++) { col_index = ((p>>7) &1)| ((p >> 15)&1)<<1 | ((p >> 23)&1)<<2 | ((p >> 31)&1)<<3; if (attrib & BIT3) col_index|=0x10; // Then use sprite palete dst[x] = colors[col_index]; if ((attrib & BIT4) && (col_index != 0x10) && (col_index !=0x0)) { tile_mask[x] = 1; } x++; p<<=1; } break; case 3: // Tile flipped on x and y for (int i=0; i<8;i++) { col_index = (p & 1) | ((p>>8) & 1)<<1 | ((p>>16) & 1)<<2 | ((p>>24) & 1)<<3; if (attrib & BIT3) col_index|=0x10; // Then use sprite palete dst[x] = colors[col_index]; if ((attrib & BIT4) && (col_index != 0x10) && (col_index !=0x0)) { tile_mask[x] = 1; } x++; p>>=1; } break; } // switch attrib flip x/y } #ifdef DISPLAY_SPRITES displaySpritesLine(); #endif if (REG0 & BIT5) // Do not display (clear) leftmost column of the screen { unsigned short c = colors[(REG7 & 0xF)+16]; for (int u=0; u < 8; u++) { dst[u] = c; } } // Copy buffer_line in screen line: memcpy(scr,dst, 1024); } /*-------------------------------------------------------------*/ /* This method selects VDP timings vcounts. */ /*-------------------------------------------------------------*/ void VDP::setNTSC(bool t) { // Select appropriate vcount array, depending on ntsc/pal option. if (t == true) { v_cnt = vcount_ntsc_192; } else { v_cnt = vcount_palsecam_192; } } /*-------------------------------------------------------------*/ /* This method will sprites on a given scanline on SDL_Surface */ /* The scanline is the line variable into VDP Class, which is */ /* the current line drawn. */ /*-------------------------------------------------------------*/ void VDP::displaySpritesLine() { unsigned char sprite_height = 8; unsigned char displayedSprites; unsigned short c; unsigned char col_index; int y; unsigned int *cst; unsigned int p; bool double_size = false; int x_spr[8]; int y_spr[8]; unsigned short ind_spr[8]; unsigned char line_spr[8]; unsigned char start_spr[8]; unsigned char width_spr[8]; if (REG1 & BIT1) // 8*16 sprites { sprite_height = 16; } displayedSprites = 0; /* Note that if Bit0 and Bit1 of reg1 are set, sprites are 16*32. */ /* Earthworm jim uses this.*/ if (REG1 & BIT0) { sprite_height *= 2; double_size = true; } // For all sprite information table for (int j=0; j<64; j++) { y = (int)VRAM[sit_addr+j]; // y=208 mean stop displaying sprites. if (y == 208) { break; } // Y position 0 means scanline 1. y++; if (y>240) { y-=256; } // Found one sprite to draw. if ( (line>=y) && (line<(y + sprite_height))) { if (displayedSprites == 8) { vdp_status |= BIT6; /* Sprite overflow bit */ break; } ind_spr[displayedSprites] = VRAM[(sit_addr+129)+(j<<1)]; if (REG6 & BIT2) // 9th bit sprite nbr { ind_spr[displayedSprites] |= 0x100; } if (REG1 & BIT1) { ind_spr[displayedSprites] &=0x01FE; } y_spr[displayedSprites] = y; line_spr[displayedSprites] = line - y; if (double_size) line_spr[displayedSprites] = (line - y)>>1; x_spr[displayedSprites] = VRAM[(sit_addr+128)+(j<<1)]; // Sprites moved 8 pixels left. start_spr[displayedSprites] = 0; // First pixel in sprite line to draw. if (REG0 & BIT3) { x_spr[displayedSprites]-=8; if (x_spr[displayedSprites]<0) { start_spr[displayedSprites] = -x_spr[displayedSprites]; } } width_spr[displayedSprites] = 8; // Nbr of pixels in sprite line to draw. if (x_spr[displayedSprites]>248) { width_spr[displayedSprites] = 256 - x_spr[displayedSprites]; } displayedSprites++; } } // Draw in reverse order. for (int i= 0; i < 256; i++) { spr_col[i] = 0; } for (int r = displayedSprites-1; r >= 0; r--) { c = (line_spr[r]<<2) + (ind_spr[r]<<5); cst = (unsigned int *) &VRAM[c]; p = *cst; c += 4; for (int i=start_spr[r]; i>7)&1) | (((p >> 15)<<1)&2) | (((p >> 23)<<2)&4) | ((p >> 31)<<3); col_index|=0x10; // Always use sprite palete if (col_index != 0x10) { if (double_size) { if (tile_mask[x_spr[r]+i*2] == 0) { unsigned short u = x_spr[r]+(i*2); line_buffer[u] = colors[col_index]; line_buffer[u+1] = colors[col_index]; if ((spr_col[u] == 1) || (spr_col[u+1] == 1)) { vdp_status |= BIT5; // Force collision to true } spr_col[u] = 1; spr_col[u+1] = 1; } } else { if (tile_mask[x_spr[r]+i] == 0) { unsigned short u = x_spr[r]+i; line_buffer[u] = colors[col_index]; if (spr_col[u] == 1) { vdp_status |= BIT5; // Force collision to true } spr_col[u] = 1; } } } p<<=1; } } } /* Implemetntation of ImplementsSaveState. */ bool VDP::saveState( ofstream &ofs) { VDPSaveState vss; /* Fill the structure. */ vss.map_addr = map_addr; vss.sit_addr = sit_addr; for (int i=0; i < VDP_REGISTER_NBR; i++) vss.regs[i] = regs[i]; vss.vdp_status = vdp_status; vss.v_counter = v_counter; vss.line = line; vss.i_counter = i_counter; vss.rd_data_port_buffer = rd_data_port_buffer; vss.irq_line_pending = irq_line_pending; vss.vsynch_irq_pending = vsynch_irq_pending; vss.sms_irq = sms_irq; vss.latch = latch; vss.addr = addr; vss.cmd_type = cmd_type; vss.cmd_flag = cmd_flag; /* Save VDP data. */ ofs.write((char *)&vss, sizeof(vss)); if (!ofs.good()) return false; /* Save 16 Ko VRAM. */ ofs.write((char *)&VRAM[0], 0x4000); if (!ofs.good()) return false; /* Save 64 bytes CRAM. */ ofs.write((char *)&CRAM[0], 64); if (!ofs.good()) return false; return true; } bool VDP::loadState( ifstream &ifs) { VDPSaveState vss; /* Load VDP data into structure */ ifs.read((char *)&vss, sizeof(vss)); if (!ifs.good()) return false; map_addr = vss.map_addr ; sit_addr = vss.sit_addr; for (int i=0; i < VDP_REGISTER_NBR; i++) regs[i] = vss.regs[i]; vdp_status = vss.vdp_status; v_counter = vss.v_counter; line = vss.line; i_counter = vss.i_counter; rd_data_port_buffer = vss.rd_data_port_buffer; irq_line_pending = vss.irq_line_pending; vsynch_irq_pending = vss.vsynch_irq_pending; sms_irq = vss.sms_irq; latch = vss.latch; addr = vss.addr; cmd_type = vss.cmd_type; cmd_flag = vss.cmd_flag; /* Load 16 Ko VRAM. */ ifs.read((char *)&VRAM[0], 0x4000); if (!ifs.good()) return false; /* Load 64 bytes CRAM. */ ifs.read((char *)&CRAM[0], 64); if (!ifs.good()) { if (ifs.eof()) cout << "EOF!" << endl; return false; } /* Now recompute colors that are usually computed on fly.*/ if (opt.MachineType == SMS) { for (int i=0; i < 0x1f; i++) colors[i] = colorSMS8BitsToColor32Bits(CRAM[i]); } if (opt.MachineType == GAMEGEAR) { unsigned short *CRAM16bits = (unsigned short *) CRAM; for (int i=0; i < 0x1f; i++) colors[i] = colorGG12BitsToColor32Bits(CRAM16bits[i]); } return true; } osmose-emulator-1.4/src/VDP.h000066400000000000000000000133171341430144300161040ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef VDP_H #define VDP_H #include "Definitions.h" #include #include #include #include #include #include "Bits.h" #include "Options.h" #include "Z80.h" #include "DebugEventThrower.h" #include "SaveState.h" #include "AnsiColorTerminal.h" using namespace std; extern EmulatorOptions emu_opt; /* Uncomment this to display sprites */ #define DISPLAY_SPRITES #define VDP_REGISTER_NBR 16 /* Destination component when data port is written */ #define D_VRAM 0 #define D_CRAM 1 #define REG0 regs [0] #define REG1 regs [1] #define REG2 regs [2] #define REG3 regs [3] #define REG4 regs [4] #define REG5 regs [5] #define REG6 regs [6] #define REG7 regs [7] #define REG8 regs [8] #define REG9 regs [9] #define REG10 regs [10] /*Uncomment this to have VDP access trace */ //#define VDP_VERBOSE typedef struct { unsigned short map_addr; unsigned short sit_addr; unsigned char regs[VDP_REGISTER_NBR]; unsigned char vdp_status; unsigned char v_counter; int line; unsigned char i_counter; unsigned char rd_data_port_buffer; bool irq_line_pending; bool vsynch_irq_pending; bool sms_irq; unsigned char latch; unsigned short addr; unsigned char cmd_type; bool cmd_flag; } VDPSaveState; class VDP : public DebugEventThrower, public ImplementsSaveState { public: VDP(Z80 *c,bool ntsc); virtual ~VDP() {}; virtual void writeDataPort(unsigned char data); // Port 0xBE written (overriden VDP_GG). unsigned char readDataPort(); // Port 0xBE read. void writeCtrlPort(unsigned char data); // Port 0xBF/0xBD written. unsigned char readStatusFlag(); // Port 0xBF/0xBD read. void reset(); // reset VDP. void dumpVRAM(unsigned int, int nb_lines); // Dump VDP VRAM. void dumpCRAM(); // Dump VDP CRAM. void update(unsigned int *s, bool drawline); // Update VDP. unsigned short getVRAMAddr(); // Get VDP pointer. bool getIrqLinePending() {return irq_line_pending;} unsigned int line_buffer [256]; // Line buffer for tile/sprite priority. unsigned char tile_mask [256]; // Pixels above sprites are marked here. unsigned char spr_col [256]; // Use for sprite collision. unsigned int *colors; // For on fly color conversion. unsigned char *VRAM; // Video memory. unsigned char *CRAM; // Color RAM. unsigned short map_addr; // Where in vram is tilemap. unsigned short sit_addr; // for sprite info. table. unsigned char regs[VDP_REGISTER_NBR]; // VDP Registers. unsigned char vdp_status; // used with portBF read. unsigned char v_counter; // Vertical scanline ctr. unsigned char *v_cnt; // point ntsc/pal vcount values. int line; // Line actually drawn. unsigned char i_counter; // Interrupt Line counter. unsigned char rd_data_port_buffer; // Buffer used in read data port. bool irq_line_pending; bool vsynch_irq_pending; bool irqAsserted(){return sms_irq;} bool irq_accepted; /* Implemetntation of ImplementsSaveState. */ bool saveState( ofstream &ofs); bool loadState( ifstream &ifs); void setNTSC(bool); protected: unsigned char latch; // Latch for address. unsigned short addr; // VDP address pointer. unsigned char cmd_type; // VRAM Wr/Rd, VDP Wr Reg or CRAM Wr. bool cmd_flag; // Flag for 2 bytes cmd. unsigned char r_col[4]; // Precalc Red possible values. unsigned char g_col[4]; // Precalc Green possible values. unsigned char b_col[4]; // Precalc Blue possible values. void updateIRQAssertion(); void writeRegs(unsigned char r,unsigned char v); // Called on write regs. virtual void traceBackGroundLine(unsigned int *s); // Draw one line. void displaySpritesLine(); // Used in traceBackGroundLine. unsigned int colorSMS8BitsToColor32Bits(unsigned char c); // Color convertor Helper. unsigned int colorGG12BitsToColor32Bits(unsigned short data); private: bool sms_irq; // Set when VDP gen. an irq. Z80 *cpu; }; #endif osmose-emulator-1.4/src/VDP_GG.cpp000066400000000000000000000210611341430144300170070ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "VDP_GG.h" static unsigned color_latch = 0; /*----------------------------------------------------------------------*/ /* VDP_GG Constructor. */ /*----------------------------------------------------------------------*/ VDP_GG::VDP_GG(Z80 *c, bool ntsc) : VDP( c, ntsc ) { } /*----------------------------------------------------------------------*/ /* This method handles write operation on the GAMEGEAR VDP data port. */ /*----------------------------------------------------------------------*/ void VDP_GG::writeDataPort(unsigned char data) /* Port 0xBE written */ { cmd_flag = false; rd_data_port_buffer = data; // CMD docs says that write, load buffer with it's value. // destination is VRAM or CRAM ? if (cmd_type == 3) { if (!(addr & 0x1)) { color_latch = data; } else { //CRAM[addr & 0x3F] = data; // data not anded with 1f. It's done with rgb rate. unsigned short col = ((data & 0xF) <<8) | color_latch; unsigned short *cram_w = (unsigned short*) &CRAM[addr & 0x3e]; *cram_w = col; colors[(addr>>1) & 0x1f] = colorGG12BitsToColor32Bits( col ); } addr++; addr &=0x3FFF; } else // Destination is VRAM { VRAM[addr] = data; #ifdef VDP_VERBOSE cout << "VRAM written: at 0x" << hex << setw(4) << setfill('0')<< addr << " with value "<< setw(2) << setfill('0') <<(int)data <167)) { memset(scr, 0x0, 0x400); return; } dst = line_buffer; /* Clear our tileMask. */ memset(tile_mask,0x00, 0x100); /* Note that x is never tested for >255 since it automaticaly wraps due to it's unsigned char declaration. */ /* Now, for 32 tiles... */ for (o=0; o<32;o++) { /* Draw a blank line directly in screen if display is disabled. */ if (!(REG1 & BIT6)) { memset(scr,0x00, 0x400); // 0x400 means 256 32bits pixels. return; } /* x = X scroll register, y = Y scroll register. */ y = REG9; x = REG8; /* Top 2 rows of screen not affected by horizontal scrolling. */ if ((REG0 & BIT6) && (line<=15)) { x = 0; } x += o *8; /* current_line = current line + scroll register modulated to stay in screen. 192 could be OK. */ if ((o >= 24) && (REG0 & BIT7)) { /* Disable vertical scrolling for columns 24-31 */ current_line = ((line) % 224); } else { current_line = ((line+y) % 224); } /* Now get VRAM index of the Tile/attrib in VDP memory. 8x8 Tile at Coord x, y = (x*64) + (y /8) x * 64 because a line is 32 tiles, with 2 bytes for tile index and attribute. y /8 because a tile is made of 8 lines. */ pos = ((current_line>>3)<<6) + o * 2; /* get it's tile Index. */ currentTile = VRAM[ map_addr + pos++]; /* get it's attribute. */ attrib = VRAM[ map_addr + pos++]; if (attrib & BIT0) { currentTile |=0x100; // 9th tile index bit. } // line in tile converted to VRAM ind if (attrib & BIT2) { // Verticaly flipped tile. c = ((7 - (current_line & 7))<<2) + (currentTile<<5); } else { c = ((current_line & 7)<<2) + (currentTile<<5); } // Four bytes are read into one 32bits variable. This avoid 3 memory access. // Bits plan are like this in the variable (intel architecture): // P3P2P1P0 which is inverse order or ram content. This is due to intel // endianness unsigned int *cst = (unsigned int *) &VRAM[c]; p = *cst; c += 4; // Draw 8 horizontals pixels. switch ((attrib>>1) & 3) { case 0: // Tile not flipped for ( i = 0; i<8; i++) { col_index = ((p >>7)&1) | (((p >> 15)<<1)&2) | (((p >> 23)<<2)&4) | ((p >> 31)<<3); if (attrib & BIT3) col_index|=0x10; // Then use sprite palete dst[x] = colors[col_index]; if ((attrib & BIT4) && (col_index != 0x10) && (col_index !=0x0)) { tile_mask[x] = 1; } x++; p<<=1; } break; case 1: // Tile flipped on x for ( i = 0; i<8; i++) { col_index = (p&1) | ((p>>8) & 1)<<1 | ((p>>16) & 1 )<<2 | ((p >>24) &1)<<3; if (attrib & BIT3) col_index|=0x10; // Then use sprite palete dst[x] = colors[col_index]; if ((attrib & BIT4) && (col_index != 0x10) && (col_index !=0x0)) { tile_mask[x] = 1; } x++; p>>=1; } break; case 2: // Tile flipped on y for (int i=0; i<8;i++) { col_index = ((p>>7) &1)| ((p >> 15)&1)<<1 | ((p >> 23)&1)<<2 | ((p >> 31)&1)<<3; if (attrib & BIT3) col_index|=0x10; // Then use sprite palete dst[x] = colors[col_index]; if ((attrib & BIT4) && (col_index != 0x10) && (col_index !=0x0)) { tile_mask[x] = 1; } x++; p<<=1; } break; case 3: // Tile flipped on x and y for (int i=0; i<8;i++) { col_index = (p & 1) | ((p>>8) & 1)<<1 | ((p>>16) & 1)<<2 | ((p>>24) & 1)<<3; if (attrib & BIT3) col_index|=0x10; // Then use sprite palete dst[x] = colors[col_index]; if ((attrib & BIT4) && (col_index != 0x10) && (col_index !=0x0)) { tile_mask[x] = 1; } x++; p>>=1; } break; } // switch attrib flip x/y } #ifdef DISPLAY_SPRITES displaySpritesLine(); #endif if (REG0 & BIT5) // Do not display (clear) leftmost column of the screen { unsigned short c = colors[(REG7 & 0xF)+16]; for (int u=0; u < 8; u++) { dst[u] = c; } } // Copy Partial buffer_line in screen line: memcpy(scr+48,dst+48, 640); } osmose-emulator-1.4/src/VDP_GG.h000066400000000000000000000021641341430144300164570ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef VDP_GG_H #define VDP_GG_H #include "VDP.h" class VDP_GG : public VDP { public: VDP_GG(Z80 *c, bool ntsc); void writeDataPort(unsigned char data); void traceBackGroundLine(unsigned int *s); }; #endif osmose-emulator-1.4/src/Version.h000066400000000000000000000020571341430144300170770ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef VERSION_H #define VERSION_H // These four definitions should be coherent! #define __OSMOSE_VERSION__ "Osmose Emulator" #define MAJOR 1 #define MIDDLE 4 #endif osmose-emulator-1.4/src/WaveWriter.cpp000066400000000000000000000106441341430144300201050ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "WaveWriter.h" #include /*----------------------------------------------------------------------*/ /* Constructor: Initialise structures ChunkFormat, Data Format, and */ /* allocate buffer of WAVE_BUFFER_SIZE for file writing. When done */ /* it open a file for writing and let it open, then write headers. */ /*----------------------------------------------------------------------*/ WaveWriter::WaveWriter(const char *filename) { // Index in our sample buffer, and sample count. index = 0; length = 0; // Initialise our FormatChunk structure. format.chunkID[0] = 'f'; format.chunkID[1] = 'm'; format.chunkID[2] = 't'; format.chunkID[3] = ' '; format.chunkSize = 16; // 16s bytes without chnkID/chnkSize. format.wFormatTag = 1; // No compression. format.wChannels = 1; // Monophonic sound. format.dwSamplesPerSec = 22050; // Sample rate. format.dwAvgBytesPerSec= 44100; // dwSamplesPerSec * wBlockAlign. format.wBlockAlign = 2; // wChannels*(wBitPerSample/8). format.wBitsPerSample = 16; // Initialise our FormatChunk structure. data.chunkID[0] = 'd'; data.chunkID[1] = 'a'; data.chunkID[2] = 't'; data.chunkID[3] = 'a'; data.chunkSize = 0; data.waveformData = (short *) NULL; // Allocate buffer for file writing data.waveformData = new short[WAVE_BUFFER_SIZE]; if (data.waveformData == NULL) { cerr << RED("Unable to allocate memory for waveformData.")<< endl; cerr << RED("Exiting.") << endl; exit (-1); } // Open our destination file. waveFile.open(filename, ios::out | ios::binary); if (waveFile.is_open() == true) { skip_save = false; } else { cerr << RED("Unable to open file for writing waveform data.")<< endl; cerr << RED("Wave file won't be saved.")<< endl; skip_save = true; } // Write headers. waveFile.write("RIFF7 WAVE", 12); waveFile.write((char *)&format, sizeof(FormatChunk) ); waveFile.write((char *)&data, sizeof(DataChunk) ); } /*----------------------------------------------------------------------*/ /* Destructor. */ /*----------------------------------------------------------------------*/ WaveWriter::~WaveWriter() { if (data.waveformData != NULL) { delete[] data.waveformData; } } /*----------------------------------------------------------------------*/ /* This method will add data into wave sound buffer. If buffer is full */ /* it's written to the file. */ /*----------------------------------------------------------------------*/ void WaveWriter::writeData(short d) { if (skip_save == true) { return; } data.waveformData[index++] = d; if (index >= WAVE_BUFFER_SIZE) { index = 0; waveFile.write((char *)data.waveformData, WAVE_BUFFER_SIZE *2); } length+=2; } /*----------------------------------------------------------------------*/ /* This method write end of buffer (if any) and close the wave file. */ /* Then it updates file headers to correct chunkSize value. */ /*----------------------------------------------------------------------*/ void WaveWriter::close() { if (skip_save == true) { return; } // still something to save. if (index > 0) { waveFile.write((char *)data.waveformData, index *2); } // Update wave header. data.chunkSize = (int)length; waveFile.seekp(36); waveFile.write((char *)&data, sizeof(DataChunk) ); waveFile.close(); } osmose-emulator-1.4/src/WaveWriter.h000066400000000000000000000036311341430144300175500ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef WAVE_WRITER_H #define WAVE_WRITER_H #include #include #include #include "AnsiColorTerminal.h" #define WAVE_BUFFER_SIZE 5*22050 // 5 second buffer. using namespace std; typedef struct { char chunkID[4]; int chunkSize; short wFormatTag; unsigned short wChannels; unsigned int dwSamplesPerSec; unsigned int dwAvgBytesPerSec; unsigned short wBlockAlign; unsigned short wBitsPerSample; } FormatChunk; typedef struct { char chunkID[4]; int chunkSize; short *waveformData; } DataChunk; class WaveWriter { public: WaveWriter(const char *filename); // Constructor. ~WaveWriter(); // Destructor. void writeData(short d); void close(); bool isOk() {return !skip_save;} private: unsigned int index; FormatChunk format; DataChunk data; unsigned int length; ofstream waveFile; bool skip_save; }; #endif osmose-emulator-1.4/src/WhiteNoiseEmulationThread.cpp000066400000000000000000000031221341430144300230630ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "WhiteNoiseEmulationThread.h" /** * Constructor. */ WhiteNoiseEmulationThread::WhiteNoiseEmulationThread(QGLImage *qglimage) : EmulationThread(qglimage) { setRefreshFrequency(25.0f); } /** * Destructor. */ WhiteNoiseEmulationThread::~WhiteNoiseEmulationThread() { } /** * This method perform one frame emulation stuff. The videoBuffer must * be updated inside this method. */ void WhiteNoiseEmulationThread::emulateOneFrame() { unsigned int col = 0; for (unsigned int i = 0; i < 256 * 192; i++) { int hzd = rand() & 0xFF; if (hzd > 0xF0) { col = rand() & 0xFF; col = col | (col << 8) | (col << 16) | 0xFF000000; } else { col = 0xFF000000; } videoBuffer[i] = col; } } osmose-emulator-1.4/src/WhiteNoiseEmulationThread.h000066400000000000000000000023431341430144300225340ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef WHITE_NOISE_EMULATION_THREAD_H #define WHITE_NOISE_EMULATION_THREAD_H #include "EmulationThread.h" class WhiteNoiseEmulationThread : public EmulationThread { public: WhiteNoiseEmulationThread(QGLImage *qglimage); ~WhiteNoiseEmulationThread(); void emulateOneFrame(); protected: private: }; #endif // WHITE_NOISE_EMULATION_THREAD_H osmose-emulator-1.4/src/Z80.cpp000066400000000000000000000535431341430144300163740ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include "Z80.h" #include #include #include // Precomputed parity, sign and zero flags table. u8 Z80::PF_SF_ZF_[256] = { ZF|PF, 0, 0, PF, 0, PF, PF, 0, 0, PF, PF, 0, PF, 0, 0, PF, 0, PF, PF, 0, PF, 0, 0, PF, PF, 0, 0, PF, 0, PF, PF, 0, 0, PF, PF, 0, PF, 0, 0, PF, PF, 0, 0, PF, 0, PF, PF, 0, PF, 0, 0, PF, 0, PF, PF, 0, 0, PF, PF, 0, PF, 0, 0, PF, 0, PF, PF, 0, PF, 0, 0, PF, PF, 0, 0, PF, 0, PF, PF, 0, PF, 0, 0, PF, 0, PF, PF, 0, 0, PF, PF, 0, PF, 0, 0, PF, PF, 0, 0, PF, 0, PF, PF, 0, 0, PF, PF, 0, PF, 0, 0, PF, 0, PF, PF, 0, PF, 0, 0, PF, PF, 0, 0, PF, 0, PF, PF, 0, SF, SF|PF, SF|PF, SF, SF|PF, SF, SF, SF|PF, SF|PF, SF, SF, SF|PF, SF, SF|PF, SF|PF, SF, SF|PF, SF, SF, SF|PF, SF, SF|PF, SF|PF, SF, SF, SF|PF, SF|PF, SF, SF|PF, SF, SF, SF|PF, SF|PF, SF, SF, SF|PF, SF, SF|PF, SF|PF, SF, SF, SF|PF, SF|PF, SF, SF|PF, SF, SF, SF|PF, SF, SF|PF, SF|PF, SF, SF|PF, SF, SF, SF|PF, SF|PF, SF, SF, SF|PF, SF, SF|PF, SF|PF, SF, SF|PF, SF, SF, SF|PF, SF, SF|PF, SF|PF, SF, SF, SF|PF, SF|PF, SF, SF|PF, SF, SF, SF|PF, SF, SF|PF, SF|PF, SF, SF|PF, SF, SF, SF|PF, SF|PF, SF, SF, SF|PF, SF, SF|PF, SF|PF, SF, SF, SF|PF, SF|PF, SF, SF|PF, SF, SF, SF|PF, SF|PF, SF, SF, SF|PF, SF, SF|PF, SF|PF, SF, SF|PF, SF, SF, SF|PF, SF, SF|PF, SF|PF, SF, SF, SF|PF, SF|PF, SF, SF|PF, SF, SF, SF|PF }; // Precomputed parity table. u8 Z80::PF_[256] = { PF, 0, 0, PF, 0, PF, PF, 0, 0, PF, PF, 0, PF, 0, 0, PF, 0, PF, PF, 0, PF, 0, 0, PF, PF, 0, 0, PF, 0, PF, PF, 0, 0, PF, PF, 0, PF, 0, 0, PF, PF, 0, 0, PF, 0, PF, PF, 0, PF, 0, 0, PF, 0, PF, PF, 0, 0, PF, PF, 0, PF, 0, 0, PF, 0, PF, PF, 0, PF, 0, 0, PF, PF, 0, 0, PF, 0, PF, PF, 0, PF, 0, 0, PF, 0, PF, PF, 0, 0, PF, PF, 0, PF, 0, 0, PF, PF, 0, 0, PF, 0, PF, PF, 0, 0, PF, PF, 0, PF, 0, 0, PF, 0, PF, PF, 0, PF, 0, 0, PF, PF, 0, 0, PF, 0, PF, PF, 0, 0, PF, PF, 0, PF, 0, 0, PF, PF, 0, 0, PF, 0, PF, PF, 0, PF, 0, 0, PF, 0, PF, PF, 0, 0, PF, PF, 0, PF, 0, 0, PF, PF, 0, 0, PF, 0, PF, PF, 0, 0, PF, PF, 0, PF, 0, 0, PF, 0, PF, PF, 0, PF, 0, 0, PF, PF, 0, 0, PF, 0, PF, PF, 0, PF, 0, 0, PF, 0, PF, PF, 0, 0, PF, PF, 0, PF, 0, 0, PF, 0, PF, PF, 0, PF, 0, 0, PF, PF, 0, 0, PF, 0, PF, PF, 0, 0, PF, PF, 0, PF, 0, 0, PF, PF, 0, 0, PF, 0, PF, PF, 0, PF, 0, 0, PF, 0, PF, PF, 0, 0, PF, PF, 0, PF, 0, 0, PF }; u8 Z80::bitval[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; /* Constructor, initialise env reference. */ Z80::Z80( Z80Environment &_env ): env( _env ) { #ifdef OPCODES_STATS NO_Prefix = new u32[256]; CB_Prefix = new u32[256]; DD_Prefix = new u32[256]; ED_Prefix = new u32[256]; FD_Prefix = new u32[256]; DDCB_Prefix = new u32[256]; FDCB_Prefix = new u32[256]; // Clear Statistics tables. for ( u16 i = 0; i < 256; i++ ) { NO_Prefix[i] = 0; CB_Prefix[i] = 0; DD_Prefix[i] = 0; ED_Prefix[i] = 0; FD_Prefix[i] = 0; DDCB_Prefix[i] = 0; FDCB_Prefix[i] = 0; } #endif reset(); } #ifdef OPCODES_STATS void Z80::opcodes_stats() { printf( "No prefixed instructions\n" ); for ( u16 i = 0; i < 256; i++ ) { printf( "0x%.2x used %d times.\n", i, NO_Prefix[i] ); } printf( "\nCB prefixed instructions\n" ); for ( u16 i = 0; i < 256; i++ ) { printf( "0xCB%.2x used %d times.\n", i, CB_Prefix[i] ); } printf( "\nDD prefixed instructions\n" ); for ( u16 i = 0; i < 256; i++ ) { printf( "0xDD%.2x used %d times.\n", i, DD_Prefix[i] ); } printf( "\nDDCB prefixed instructions\n" ); for ( u16 i = 0; i < 256; i++ ) { printf( "0xDDCB%.2x used %d times.\n", i, DDCB_Prefix[i] ); } printf( "\nED prefixed instructions\n" ); for ( u16 i = 0; i < 256; i++ ) { printf( "0xED%.2x used %d times.\n", i, ED_Prefix[i] ); } printf( "\nFD prefixed instructions\n" ); for ( u16 i = 0; i < 256; i++ ) { printf( "0xFD%.2x used %d times.\n", i, FD_Prefix[i] ); } printf( "\nFDCB prefixed instructions\n" ); for ( u16 i = 0; i < 256; i++ ) { printf( "0xFDCB%.2x used %d times.\n", i, FDCB_Prefix[i] ); } } #endif /* Destructor */ Z80::~Z80() {} void Z80::reset() { F = ZF; A = B = C = D = E = H = L = I = R = Rbit7 =0x0; A1 = B1 = C1 = D1 = E1 = H1 = L1 = 0x0; IX = IY = PC = 0x0000; SP = 0xF000; IFF1 = IFF2 = cpuHalted = false; /* IRQ/HALT opcode flags */ IM = 0; /* interrupt mode set to Zero. */ cycleCount = 0; /* Reset CPU cycles counter. */ } void Z80::dump( u16 addr ) { printf( "%.4x : ", addr ); for ( int i = 0; i < 8; i++ ) { printf( "%.2x ", env.rd8(( addr + i ) &0xFFFF )); } printf( "\n" ); } /** * Basic Arithmetic CPU Operations: */ u8 Z80::inc8( u8 v ) { v++; /* Inc value, wrap on 8 bits */ F &= CF; /* Clear all used flags */ F |= ( v &0x80 ); /* Save S flag (bit sign) */ if ( v == 0 ) F |= ZF; /* If v is zero Set Zero bit. */ if ( v == 0x80 ) F |= VF; /* Set Overflow flag */ if ( !( v &0xf )) F |= 0x10; /* Half flag if Carry from bit 3*/ // F |= ( v &( YF | XF )); /* undocumented flag bits 5+3 */ return ( v ); } u8 Z80::dec8( u8 v ) { v--; /* Dec value, wrap on 8 bit */ F = ( F &CF ) | NF; /* Clear all used flags set N */ F |= ( v &SF ); /* Save S flag (bit sign) */ if ( v == 0 ) F |= ZF; /* If v is zero Set Zero bit. */ if ( v == 0x7f ) F |= VF; /* Set overflow flag */ if (( v &0x0f ) == 0x0f ) F |= HF; /* Half carry */ // F |= ( v &( YF | XF )); /* undocumented flag bits 5+3 */ return ( v ); } /* Add -> Never overflow if sign a != sign b */ /* if sign a == sign b then (a^b)& 80 is 0 , so overflow possible */ /* ~(a^b)& 80 gives opposite result that we AND with second condition to overflow:*/ /* a & F sign != means overflow -> (a^F)&0x80 true mean overflow. */ /* Luckily sign is stored in bit 7 in F, so we xor can A and F */ u8 Z80::add8( u8 a, u8 b ) { u16 tmp1 = (( a + b )); F = ( tmp1 &0x80 ); /* Set sign */ F |= ( tmp1 >> 8 ); /* Set Carry */ tmp1 &= 0xff; /* 8bit wrap */ if (( tmp1 ^ a ^ b ) &0x10 ) F |= HF; /* Set Half flag */ if ( ~( a ^ b ) &( a ^ F ) &0x80 ) F |= VF; /* Set VF flag F already has sign.*/ if ( tmp1 == 0 ) F |= ZF; /* Set Zero Flag */ // F |= ( tmp1 &( YF | XF )); /* undocumented flag bits 5+3 */ return tmp1; } u8 Z80::adc8( u8 a, u8 b ) { u16 tmp1 = (( a + b ) + ( F &CF )); F = ( tmp1 &0x80 ); /* Save sign */ F |= (( tmp1 ) >> 8 ); /* Set Carry */ tmp1 &= 0xff; /* 8bit wrap */ if ( tmp1 == 0 ) F |= ZF; /* Set Zero Flag */ if ((( a ^ b ^ tmp1 ) &0x10 ) != 0 ) F |= HF; /* Set Half flag */ if ( ~( a ^ b ) &( a ^ F ) &0x80 ) F |= VF; /* Set VF flag F already has sign.*/ // F |= ( tmp1 &( YF | XF )); /* undocumented flag bits 5+3 */ return tmp1; } u8 Z80::sbc8( u8 a, u8 b ) { u16 tmp1 = a - b - ( F &CF ); F = ( tmp1 &0x80 ) | NF; /* save sign, set NF */ F |= (( tmp1 &0x100 ) >> 8 ); /* save carry */ if ((( a ^ b ^ tmp1 ) &0x10 ) != 0 ) F |= HF; if ((( b ^ a ) &( a ^ tmp1 ) &0x80 ) != 0 ) F |= VF; tmp1 &= 0xff; if ( tmp1 == 0 ) F |= ZF; // F |= ( tmp1 &( YF | XF )); /* undocumented flag bits 5+3 */ return tmp1; } u8 Z80::sub8( u8 a, u8 b ) { u16 tmp1 = ( a - b ); F = ( tmp1 &0x80 ) | NF; /* Save sign, set N flag */ if ( tmp1 == 0 ) F |= ZF; /* Set Zero Flag */ F |= ( tmp1 &0x100 ) >> 8; /* Set Carry */ if ((( b ^ a ) &( a ^ tmp1 ) &0x80 ) != 0 ) F |= VF; /* Set overflow */ if ((( a ^ b ^ tmp1 ) &0x10 ) != 0 ) F |= HF; /* Set Half flag */ tmp1 &= 0xff; // F |= ( tmp1 &( YF | XF )); /* undocumented flag bits 5+3 */ return tmp1; } u16 Z80::add16( u16 a, u16 b ) { u32 res = a + b; F &= SF | ZF | PF; if ( res > 0xFFFF ) F |= CF; if ((( a &0xFFF ) + ( b &0xFFF )) > 0xFFF ) F |= HF; return ( res &0xFFFF ); } void Z80::sbcHL( u16 value ) { u16 _HLD = getHL(); u32 result = _HLD - value - ( F &1 ); F = ((( _HLD ^ result ^ value ) >> 8 ) &0x10 ) | 0x02; F |= (( result >> 16 ) &1 ) | (( result >> 8 ) &0x80 ); F |= ((( result &0xffff ) != 0 ) ? 0 : 0x40 ); F |= ((( value ^ _HLD ) &( _HLD ^ result ) &0x8000 ) >> 13 ); H = ( result >> 8 ) &0xff; L = result &0xff; cycleCount += 15; } void Z80::adcHL( u16 value ) { u16 tmp1 = getHL(); u32 result = tmp1 + value + ( F &1 ); F = ((( tmp1 ^ result ^ value ) >> 8 ) &0x10 ); F |= (( result >> 16 ) &1 ) | (( result >> 8 ) &0x80 ); F |= ((( result &0xffff ) != 0 ) ? 0 : 0x40 ); F |= ((( value ^ tmp1 ^ 0x8000 ) &( value ^ result ) &0x8000 ) >> 13 ); H = ( result >> 8 ) &0xff; L = result &0xff; cycleCount += 15; } /* Acts like sub, but do not affect operands.*/ void Z80::cp8( u8 a, u8 b ) { sub8( a, b ); } /** * Basic Logical CPU Operations: */ u8 Z80::and8( u8 a, u8 b ) { u8 tmp1 = ( a & b ); F = HF; /* Set H, clear SZ H P/V N and C */ F |= PF_SF_ZF_[tmp1]; // F |= ( tmp1 &( YF | XF )); /* undocumented flag bits 5+3 */ return ( tmp1 ); } u8 Z80::xor8( u8 a, u8 b ) { u8 tmp1 = ( a ^ b ); F = PF_SF_ZF_[tmp1]; // F |= ( tmp1 &( YF | XF )); /* undocumented flag bits 5+3 */ return tmp1; } u8 Z80::or8( u8 a, u8 b ) { u8 tmp1 = ( a | b ); F = PF_SF_ZF_[tmp1]; // F |= ( tmp1 &( YF | XF )); /* undocumented flag bits 5+3 */ return tmp1; } /** * Basic Shift CPU Operations: */ u8 Z80::rlc8( u8 v ) { u8 tmp1 = ( v << 1 ); F = ( v >> 7 ); /* All flags to zero, C = bit7 */ tmp1 |= ( F &1 ); F |= PF_SF_ZF_[tmp1]; // F |= ( tmp1 &( YF | XF )); /* undocumented flag bits 5+3 */ return tmp1; } u8 Z80::rrc8( u8 v ) { u8 tmp1 = v >> 1; F = ( v &1 ); /* Set Carry from bit0*/ tmp1 |= ( F << 7 ); /* Set outgoing bit0 in bit7 */ F |= PF_SF_ZF_[tmp1]; // F |= ( tmp1 &( YF | XF )); /* undocumented flag bits 5+3 */ return tmp1; } u8 Z80::rl8( u8 v ) { u8 tmp1 = (( v << 1 ) | ( F &1 )); F = v >> 7; /* F = bit7 */ F |= PF_SF_ZF_[tmp1]; // F |= ( tmp1 &( YF | XF )); /* undocumented flag bits 5+3 */ return tmp1; } u8 Z80::rr8( u8 v ) { u8 c = ( F & 1 ); F = v & 1; /* bit0 -> Carry */ u8 tmp1 = ( v >> 1 ) | ( c << 7 ); /* Old Carry -> bit7 */ F |= PF_SF_ZF_[tmp1]; // F |= ( tmp1 &( YF | XF )); /* undocumented flag bits 5+3 */ return tmp1; } u8 Z80::sla8( u8 v ) { F = ( v >> 7 ); u8 tmp1 = ( v << 1 ); F |= PF_SF_ZF_[tmp1]; // F |= ( tmp1 &( YF | XF )); /* undocumented flag bits 5+3 */ return tmp1; } /* Undocumented 0xCB30 opcode. Support Undocumented flags. Tested. */ u8 Z80::sll8( u8 v ) { F = ( v >> 7 ); u8 tmp1 = ( v << 1 ); tmp1 |= 1; /* The only difference with sla8 */ F |= PF_SF_ZF_[tmp1]; // F |= ( tmp1 &( YF | XF )); /* undocumented flag bits 5+3 */ return tmp1; } u8 Z80::sra8( u8 v ) { F = ( v &1 ); /* Bit0 -> Carry */ u8 tmp1 = ( v >> 1 ); tmp1 |= ( v &0x80 ); /* Bit7 is keep unchanged */ F |= PF_SF_ZF_[tmp1]; // F |= ( tmp1 &( YF | XF )); /* undocumented flag bits 5+3 */ return tmp1; } u8 Z80::srl8( u8 v ) { F = v & 1; /* Bit0 -> Carry*/ v >>= 1; /* Compute Value */ F |= PF_SF_ZF_[v]; // F |= ( v &( YF | XF )); /* undocumented flag bits 5+3 */ return v; } void Z80::rrd() { u8 tmp1 = env.rd8( getHL()); u8 tmp2 = tmp1; tmp1 = ( tmp1 >> 4 ) | ( A << 4 ); A = ( A &0xf0 ) | ( tmp2 &0xf ); env.wr8( getHL(), tmp1 &0xff ); F = F &1; F |= PF_SF_ZF_[A]; // F |= ( A &( YF | XF )); /* undocumented flag bits 5+3 */ cycleCount += 18; } void Z80::rld() { u8 tmp1 = env.rd8( getHL()); u8 tmp2 = tmp1; tmp1 = ( tmp1 << 4 ) | ( A &0xf ); A = ( A &0xf0 ) | ( tmp2 >> 4 ); env.wr8( getHL(), tmp1 &0xff ); F = F &1; F |= PF_SF_ZF_[A]; // F |= ( A &( YF | XF )); /* undocumented flag bits 5+3 */ cycleCount += 18; } /** * Basic Bit CPU Operations: */ void Z80::bit( u8 bit, u8 v ) { // Based on Sean Young documentation, "Z80-documented". F = ( F & CF ) | HF; // Clear all bits except CF, HF (always set) from F. if ( !( v &( 1 << bit ))) F |= ( ZF | PF ); // ZF is set if tested bit is reset.PF is like ZF. if (( bit == 7 ) && !( F &ZF )) F |= SF; // if tested bit is 7 is set, set SF // if(( bit == 5 ) && !( F &ZF )) F |= YF; // if tested bit is 5 is set, set YF UNDOC Flag // if(( bit == 3 ) && !( F &ZF )) F |= XF; // if tested bit is 3 is set, set XF UNDOC Flag } u8 Z80::set( u8 bit, u8 v ) { return ( v |= bitval[bit] ); } u8 Z80::res( u8 bit, u8 v ) { return ( v &= ~bitval[bit] ); } /** * Basic Stack CPU Operations: */ u16 Z80::pop() { u16 tmp1 = env.rd16( SP ); SP += 2; return ( tmp1 ); } void Z80::push( u16 val ) { SP -= 2; env.wr16( SP, val ); } void Z80::rst( u16 ea ) { cycleCount += 11; push( PC ); PC = ea; } void Z80::setFlagAfterInput( u8 readed ) { F = ( F & CF ); /* Save the Carry Flag */ F |= PF_SF_ZF_[readed]; } void Z80::invalid_opcode() { PC--; step(); // Execute opcode from standard opcode table. cycleCount += 4; // Timing penality. printf ("Inv Opc\n"); } void Z80::invalid_prefixed_opcode() { PC--; step(); // Execute opcode from standard opcode table. cycleCount += 8; // Timing penality. printf ("Inv Opc\n"); } void Z80::nop() { cycleCount += 4; } /* This method generates a Non Maskable interrupt */ void Z80::nmi() { cpuHalted = false; /* UnHalt the cpu. */ IFF1 = false; /* Disable interrupt. */ push( PC ); /* Make call 0x66 */ PC = 0x0066; cycleCount += 11; } /* This method generates a Non Maskable interrupt. If cpu accept interrupt the method returns true, else, interrupt are disabled and the method returns false. */ bool Z80::interrupt( u8 data ) { if ( IFF1 ) { #ifdef BUILT_IN_DEBUGGER throwDebugEvent(DbgEvtCpuIrqAsserted, "CPU", "IRQ Asserted: CPU accepts it (DI)."); #endif /* Interrupts are enabled */ cpuHalted = false; // UnHalt the CPU. IFF1 = IFF2 = false; // Disable Maskable interrupt switch ( IM ) { case 0: (this->*(Opc_std[data]))(); // Exec opcode pushed on the bus (data). cycleCount += 13; break; case 1: push( PC ); PC = 0x38; cycleCount += 13; break; case 2: push( PC ); PC = env.rd16((I << 8) | (data & 0xFE)); cycleCount += 19; break; } return true; } else { #ifdef BUILT_IN_DEBUGGER throwDebugEvent(DbgEvtCpuIrqAsserted, "CPU", "IRQ Asserted: CPU refuse it (DI)."); #endif return false; } } /* Execute one single instruction. */ void Z80::step() { R++; if ( cpuHalted == true ) { cycleCount += 4; } else { //env.disasm(PC); u8 instruction = env.rd8( PC++ ); (this->*(Opc_std[instruction]))(); #ifdef OPCODES_STATS NO_Prefix[ instruction ]++; #endif } } u32 Z80::run( u32 wanted_cycles ) { u8 instruction; // Current Opcode u32 tc = cycleCount + wanted_cycles; while ( cycleCount < tc ) { #ifdef BUILT_IN_DEBUGGER throwDebugEvent(DbgEvtCpuStep, "CPU", "CPU step."); #endif R++; if ( cpuHalted ) { /* Instead of looping doing NOP, compute How many nop to do */ /* and adjust cycleCount and R accordingly. NOP is 4 cycles.*/ /* cycleCount += 4; */ u32 n = ((tc +3 - cycleCount) / 4); R += n; cycleCount += n * 4; } else { instruction = env.rd8( PC++ ); (this->*(Opc_std[instruction]))(); #ifdef OPCODES_STATS NO_Prefix[ instruction ]++; #endif } } return cycleCount - tc; // overcycles ! } void Z80::dumpSaveStateStructure(Z80SaveState &css) { cout << "Save state structure dump:" << endl << endl; cout << hex << "css.A = " << (unsigned short) css.A << endl; cout << "css.F = " << (unsigned short)css.F << endl; cout << "css.B = " << (unsigned short)css.B << endl; cout << "css.C = " << (unsigned short)css.C << endl; cout << "css.D = " << (unsigned short) css.D << endl; cout << "css.E = " << (unsigned short)css.E << endl; cout << "css.H = " << (unsigned short)css.H << endl; cout << "css.L = " << (unsigned short)css.L << endl; cout << "css.I = " << (unsigned short)css.I << endl; cout << "css.R = " << (unsigned short)css.R << endl; cout << "css.A1 = " << (unsigned short)css.A1 << endl; cout << "css.F1 = " << (unsigned short)css.F1 << endl; cout << "css.B1 = " << (unsigned short)css.B1 << endl; cout << "css.C1 = " << (unsigned short)css.C1 << endl; cout << "css.D1 = " << (unsigned short)css.D1 << endl; cout << "css.E1 = " << (unsigned short)css.E1 << endl; cout << "css.H1 = " << (unsigned short)css.H1 << endl; cout << "css.L1 = " << (unsigned short)css.L1 << endl; cout << "css.Rbit7 = " << (unsigned short)css.Rbit7 << endl; cout << "css.IM = " << (unsigned short)css.IM << endl; cout << "css.PC = " << (unsigned short)css.PC << endl; cout << "css.IX = " << (unsigned short)css.IX << endl; cout << "css.IY = " << (unsigned short)css.IY << endl; cout << "css.SP = " << (unsigned short)css.SP << endl; cout << "css.IFF1 = " << css.IFF1 << endl; cout << "css.IFF2 = " << css.IFF2 << dec << endl; cout << "css.cpuHalted = " << (unsigned int) css.cpuHalted << endl; cout << "css.cycleCount = " << (unsigned int) css.cycleCount << endl << endl; } void Z80::dumpValues() { cout << "CPU register dump:" << endl << endl; cout << hex << "A = " << (unsigned short) A << endl; cout << "F = " << (unsigned short)F << endl; cout << "B = " << (unsigned short)B << endl; cout << "C = " << (unsigned short)C << endl; cout << "D = " << (unsigned short)D << endl; cout << "E = " << (unsigned short)E << endl; cout << "H = " << (unsigned short)H << endl; cout << "L = " << (unsigned short)L << endl; cout << "I = " << (unsigned short)I << endl; cout << "R = " << (unsigned short)R << endl; cout << "A1 = " << (unsigned short)A1 << endl; cout << "F1 = " << (unsigned short)F1 << endl; cout << "B1 = " << (unsigned short)B1 << endl; cout << "C1 = " << (unsigned short)C1 << endl; cout << "D1 = " << (unsigned short)D1 << endl; cout << "E1 = " << (unsigned short)E1 << endl; cout << "H1 = " << (unsigned short)H1 << endl; cout << "L1 = " << (unsigned short)L1 << endl; cout << "Rbit7 = " << (unsigned short)Rbit7 << endl; cout << "IM = " << (unsigned short)IM << endl; cout << "PC = " << (unsigned short)PC << endl; cout << "IX = " << (unsigned short)IX << endl; cout << "IY = " << (unsigned short)IY << endl; cout << "SP = " << (unsigned short)SP << endl; cout << "IFF1 = " << (unsigned short)IFF1 << endl; cout << "IFF2 = " << (unsigned short)IFF2 << dec << endl; cout << "cpuHalted = " << (unsigned int)cpuHalted << endl; cout << "cycleCount = " << (unsigned int)cycleCount << endl << endl; } bool Z80::saveState( ofstream &ofs ) { Z80SaveState css; css.A = A; css.F = F; css.B = B; css.C = C; css.D = D; css.E = E; css.H = H; css.L = L; css.I = I; css.R = R; css.A1 = A1; css.F1 = F1; css.B1 = B1; css.C1 = C1; css.D1 = D1; css.E1 = E1; css.H1 = H1; css.L1 = L1; css.Rbit7 = Rbit7; css.IM = IM; css.PC = PC; css.IX = IX; css.IY = IY; css.SP = SP; css.IFF1 = IFF1; css.IFF2 = IFF2; css.cpuHalted = cpuHalted; css.cycleCount = cycleCount; ofs.write((char *)&css, sizeof(css)); //dumpValues(); //dumpSaveStateStructure(css); return ofs.good(); } bool Z80::loadState( ifstream &ifs ) { Z80SaveState css; bool ret = false; ifs.read((char *)&css, sizeof(css)); ret = ifs.good(); //dumpSaveStateStructure(css); /* Don't restore the values if read fails ! */ if (!ret) return false; A = css.A; F = css.F; B = css.B; C = css.C; D = css.D; E = css.E; H = css.H; L = css.L; I = css.I; R = css.R; A1 = css.A1; F1 = css.F1; B1 = css.B1; C1 = css.C1; D1 = css.D1; E1 = css.E1; H1 = css.H1; L1 = css.L1; Rbit7 =css.Rbit7; IM = css.IM; PC = css.PC; IX = css.IX; IY = css.IY; SP = css.SP; IFF1 = css.IFF1; IFF2 = css.IFF2; cpuHalted = css.cpuHalted; cycleCount = css.cycleCount; //dumpValues(); return true; } osmose-emulator-1.4/src/Z80.h000066400000000000000000001343301341430144300160330ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #ifndef Z80_H_ #define Z80_H_ #include "BasicTypes.h" #include "DebugEventThrower.h" #include "Definitions.h" #include "SaveState.h" // Enable opcode 'hit statistics.' //#define OPCODES_STATS /* Flag related constants */ #define SF 0x80 /* Sign */ #define ZF 0x40 /* Zero */ #define YF 0x20 /* Undoc flag */ #define HF 0x10 /* Half carry */ #define XF 0x08 /* Undoc flag */ #define VF 0x04 /* Overflow */ #define PF 0x04 /* Parity */ #define NF 0x02 /* Add subtract*/ #define CF 0x01 /* Carry */ /* Save state data structure. */ typedef struct { u8 A,F,B,C,D,E,H,L,I,R; /* Generals registers. */ u8 A1,F1,B1,C1,D1,E1,H1,L1; /* Alternat ' registers. */ u8 Rbit7; /* Use to store bit 7 of R */ u8 IM; /* Interrupt mode */ u16 PC,IX,IY,SP; /* PC,Stack, indexes registers. */ bool IFF1,IFF2; /* NMI/IRQ interrupt flip flop. */ bool cpuHalted; /* CPU state vs Halt instruction.*/ u32 cycleCount; /* Increase when running CPU. */ } Z80SaveState; /* This class, from Alessandro Scotti (Tickle emulator) Z80environment, must be derived, with implementation for each virtual methods. It will be used by Z80 CPU core to access RAM/ROM, IO etc... */ class Z80Environment { public: /* Constructor. */ Z80Environment() { } /* Destructor. */ virtual ~Z80Environment() { } /* 8 bits read operation. */ virtual u8 rd8( u16 ) { return 0xFF; } /* 8 bits write operation address, value. */ virtual void wr8( u16 , u8 ) { } /* 16 bits read operation. */ u16 rd16( u16 addr ) { u8 a,b; a = rd8(addr); b = rd8((addr+1)& 0xFFFF); return ((b<<8) | a); } /* 16 bits write operation. */ void wr16( u16 addr, u16 value ) { wr8((addr+1)& 0xFFFF, value >> 8); wr8(addr, value & 0xFF); } /* 8 bits read IO operation. */ virtual u8 in( u16 ) { return 0xFF; } /* 8 bits write IO operation address, value. */ virtual void out( u16 , u8 ) { } /* Called immediately after a RETI is executed. */ virtual void onReturnFromInterrupt() { } /* Called after EI or RETN if interrupts are enabled. This function allows the environment to supply a pending interrupt if needed. */ virtual void onInterruptsEnabled() { } }; class Z80 : public DebugEventThrower, public ImplementsSaveState { public: Z80Environment& env; /* Z80Environment reference. */ u8 A,F,B,C,D,E,H,L,I,R; /* Generals registers. */ u8 A1,F1,B1,C1,D1,E1,H1,L1; /* Alternat ' registers. */ u8 Rbit7; /* Use to store bit 7 of R */ u8 IM; /* Interrupt mode */ u16 PC,IX,IY,SP; /* PC,Stack, indexes registers. */ u16 IXd, IYd; /* Used for XY+d addressing mode. */ bool IFF1,IFF2; /* NMI/IRQ interrupt flip flop. */ bool cpuHalted; /* CPU state vs Halt instruction.*/ u32 cycleCount; /* Increase when running CPU. */ Z80 ( Z80Environment & ); /* Constructor with Z80Environment reference*/ ~Z80(); /* Destructor. */ void reset(); /* Reset Z80.*/ void nmi(); /* Generate CPU NMI.*/ bool interrupt(u8 data); /* Generate CPU interrupt.*/ u32 run(u32 cycles); /* Execute n cycles. */ void step(); /* Execute one instruction */ void setCycles(u32 c) { cycleCount = c; } u32 getCycles() { return cycleCount; } u8 getInterruptMode() { return IM; } /* Implemetntation of ImplementsSaveState. */ bool saveState( ofstream &ofs); bool loadState( ifstream &ifs); /* * Internal Register Manipulation Functions. * Get 16 reg from its 8 bits composant registers. */ u16 getAF() { return ( (A << 8) | F); } u16 getBC() { return ( (B << 8) | C); } u16 getDE() { return ( (D << 8) | E); } u16 getHL() { return ( (H << 8) | L); } u16 getIX() { return ( IX ); } u16 getIY() { return ( IY ); } u16 getPC() { return ( PC ); } u16 getSP() { return ( SP ); } u8 getI() { return ( I ); } u8 getR() { return ( R ); } #ifdef OPCODES_STATS u32 *NO_Prefix; u32 *CB_Prefix; u32 *DD_Prefix; u32 *ED_Prefix; u32 *FD_Prefix; u32 *DDCB_Prefix; u32 *FDCB_Prefix; void opcodes_stats(); #endif private: void dumpSaveStateStructure(Z80SaveState &); /* For debug purpose.*/ void dumpValues(); /* Dump CPU regs etc.*/ void exec_cb(); /* Execute opcode prefixed 0xCB. */ void exec_dd(); /* Execute opcode prefixed 0xDD. */ void exec_ddcb(); /* Execute opcode prefixed 0xDDCB. */ void exec_ed(); /* Execute opcode prefixed 0xED. */ void exec_fd(); /* Execute opcode prefixed 0xFD. */ void exec_fdcb(); /* Execute opcode prefixed 0xFDCB. */ bool checkInterrupt(); void dump(u16 addr); /* * Internal Register Manipulation Functions. * Set 8 bits composant registers from 16 bit value. */ void setAF (u16 v) { A = v>>8; F = v & 0xFF; } void setBC (u16 v) { B = v>>8; C = v & 0xFF; } void setDE (u16 v) { D = v>>8; E = v & 0xFF; } void setHL (u16 v) { H = v>>8; L = v & 0xFF; } /* * Internal indirect 8 bits regs Addressing. * Set/Get Indirect 8 bits values. */ u8 getBCi() { return env.rd8(getBC()); /* read u8 in (BC) */ } void setBCi(u8 val) { env.wr8(getBC(),val); /* write u8 in (BC) */ } u8 getDEi() { return env.rd8(getDE()); /* read u8 in (DE) */ } void setDEi(u8 val) { env.wr8(getDE(),val); /* write u8 in (DE) */ } u8 getHLi() { return env.rd8(getHL()); /* read u8 in (HL) */ } void setHLi(u8 val) { env.wr8(getHL(),val); /* write u8 in (HL) */ } /* 8 bit read/write thought (IX+d) and (IY+d). Warning: PC is not incremented ! */ u8 getIXdi() { return env.rd8((u16)(IX + (s8)env.rd8(PC))); } void setIXdi(u8 val) { env.wr8((u16)(IX + (s8)env.rd8(PC)),val); } u8 getIYdi() { return env.rd8((u16)(IY + (s8)env.rd8(PC))); } void setIYdi(u8 val) { env.wr8((u16)(IY + (s8)env.rd8(PC)),val); } void setNNi16(u16 val16b) { env.wr16(env.rd16(PC),val16b); } u16 getNNi16() { return env.rd16(env.rd16(PC)); } void setNNi8(u8 val8b) { env.wr8(env.rd16(PC),val8b); } u8 getNNi8() { return env.rd8(env.rd16(PC)); } /** * Basic Arithmetic CPU Operations: */ u8 inc8(u8 v); /* increment 8bits value. */ u8 dec8(u8 v); /* decrement 8bits value. */ u8 add8(u8 a,u8 b); /* add 8 bits values. */ u8 adc8(u8 a,u8 b); /* add with carry 8 bits values. */ u8 sbc8(u8 a,u8 b); /* sub with carry 8 bits values. */ u8 sub8(u8 a,u8 b); /* sub 8 bits values. */ u16 add16(u16 a,u16 b); /* add 16 bits values. */ void sbcHL(u16 v); /* SBC HL, REG */ void adcHL(u16 v); /* ADC HL, REG */ void rrd(); /* RRD */ void rld(); /* RLD */ void cp8(u8 a, u8 b); /* Compare 8bits values. */ /** * Basic Logical CPU Operations: */ u8 and8(u8 a,u8 b); /* and 8 bits values. */ u8 or8(u8 a,u8 b); /* or 8 bits values. */ u8 xor8(u8 a,u8 b); /* xor 8 bits values. */ /** * Basic Shift CPU Operations: */ u8 rlc8(u8 v); /* (<<1) 8 bits value. */ u8 rrc8(u8 v); /* (>>1) 8 bits value.*/ u8 rl8(u8 v); /* (<<1) 8 bits value.*/ u8 rr8(u8 v); /* (>>1) 8 bits value.*/ u8 sla8(u8 v); /* .*/ u8 sra8(u8 v); /* .*/ u8 sll8(u8 v); /* .*/ u8 srl8(u8 v); /* .*/ /** * Basic Bit CPU Operations: */ void bit(u8 bit,u8 v); /* test bit in 8 bits value.*/ u8 set(u8 bit,u8 v); /* set bit in 8 bits value.*/ u8 res(u8 bit,u8 v); /* reset bit in 8 bits value.*/ /** * Basic Stack CPU Operations: */ u16 pop(); /* Pop 16 bits value.*/ void push(u16 v); /* Push 16 bits value*/ void rst(u16 ea); /* rst operation.*/ void setFlagAfterInput(u8 r); void invalid_opcode(); void invalid_prefixed_opcode(); void nop() ; /** * CPU opcode callbacks: */ void Opc_std_00(); void Opc_std_01(); void Opc_std_02(); void Opc_std_03(); void Opc_std_04(); void Opc_std_05(); void Opc_std_06(); void Opc_std_07(); void Opc_std_08(); void Opc_std_09(); void Opc_std_0a(); void Opc_std_0b(); void Opc_std_0c(); void Opc_std_0d(); void Opc_std_0e(); void Opc_std_0f(); void Opc_std_10(); void Opc_std_11(); void Opc_std_12(); void Opc_std_13(); void Opc_std_14(); void Opc_std_15(); void Opc_std_16(); void Opc_std_17(); void Opc_std_18(); void Opc_std_19(); void Opc_std_1a(); void Opc_std_1b(); void Opc_std_1c(); void Opc_std_1d(); void Opc_std_1e(); void Opc_std_1f(); void Opc_std_20(); void Opc_std_21(); void Opc_std_22(); void Opc_std_23(); void Opc_std_24(); void Opc_std_25(); void Opc_std_26(); void Opc_std_27(); void Opc_std_28(); void Opc_std_29(); void Opc_std_2a(); void Opc_std_2b(); void Opc_std_2c(); void Opc_std_2d(); void Opc_std_2e(); void Opc_std_2f(); void Opc_std_30(); void Opc_std_31(); void Opc_std_32(); void Opc_std_33(); void Opc_std_34(); void Opc_std_35(); void Opc_std_36(); void Opc_std_37(); void Opc_std_38(); void Opc_std_39(); void Opc_std_3a(); void Opc_std_3b(); void Opc_std_3c(); void Opc_std_3d(); void Opc_std_3e(); void Opc_std_3f(); void Opc_std_40(); void Opc_std_41(); void Opc_std_42(); void Opc_std_43(); void Opc_std_44(); void Opc_std_45(); void Opc_std_46(); void Opc_std_47(); void Opc_std_48(); void Opc_std_49(); void Opc_std_4a(); void Opc_std_4b(); void Opc_std_4c(); void Opc_std_4d(); void Opc_std_4e(); void Opc_std_4f(); void Opc_std_50(); void Opc_std_51(); void Opc_std_52(); void Opc_std_53(); void Opc_std_54(); void Opc_std_55(); void Opc_std_56(); void Opc_std_57(); void Opc_std_58(); void Opc_std_59(); void Opc_std_5a(); void Opc_std_5b(); void Opc_std_5c(); void Opc_std_5d(); void Opc_std_5e(); void Opc_std_5f(); void Opc_std_60(); void Opc_std_61(); void Opc_std_62(); void Opc_std_63(); void Opc_std_64(); void Opc_std_65(); void Opc_std_66(); void Opc_std_67(); void Opc_std_68(); void Opc_std_69(); void Opc_std_6a(); void Opc_std_6b(); void Opc_std_6c(); void Opc_std_6d(); void Opc_std_6e(); void Opc_std_6f(); void Opc_std_70(); void Opc_std_71(); void Opc_std_72(); void Opc_std_73(); void Opc_std_74(); void Opc_std_75(); void Opc_std_76(); void Opc_std_77(); void Opc_std_78(); void Opc_std_79(); void Opc_std_7a(); void Opc_std_7b(); void Opc_std_7c(); void Opc_std_7d(); void Opc_std_7e(); void Opc_std_7f(); void Opc_std_80(); void Opc_std_81(); void Opc_std_82(); void Opc_std_83(); void Opc_std_84(); void Opc_std_85(); void Opc_std_86(); void Opc_std_87(); void Opc_std_88(); void Opc_std_89(); void Opc_std_8a(); void Opc_std_8b(); void Opc_std_8c(); void Opc_std_8d(); void Opc_std_8e(); void Opc_std_8f(); void Opc_std_90(); void Opc_std_91(); void Opc_std_92(); void Opc_std_93(); void Opc_std_94(); void Opc_std_95(); void Opc_std_96(); void Opc_std_97(); void Opc_std_98(); void Opc_std_99(); void Opc_std_9a(); void Opc_std_9b(); void Opc_std_9c(); void Opc_std_9d(); void Opc_std_9e(); void Opc_std_9f(); void Opc_std_a0(); void Opc_std_a1(); void Opc_std_a2(); void Opc_std_a3(); void Opc_std_a4(); void Opc_std_a5(); void Opc_std_a6(); void Opc_std_a7(); void Opc_std_a8(); void Opc_std_a9(); void Opc_std_aa(); void Opc_std_ab(); void Opc_std_ac(); void Opc_std_ad(); void Opc_std_ae(); void Opc_std_af(); void Opc_std_b0(); void Opc_std_b1(); void Opc_std_b2(); void Opc_std_b3(); void Opc_std_b4(); void Opc_std_b5(); void Opc_std_b6(); void Opc_std_b7(); void Opc_std_b8(); void Opc_std_b9(); void Opc_std_ba(); void Opc_std_bb(); void Opc_std_bc(); void Opc_std_bd(); void Opc_std_be(); void Opc_std_bf(); void Opc_std_c0(); void Opc_std_c1(); void Opc_std_c2(); void Opc_std_c3(); void Opc_std_c4(); void Opc_std_c5(); void Opc_std_c6(); void Opc_std_c7(); void Opc_std_c8(); void Opc_std_c9(); void Opc_std_ca(); void Opc_std_cb(); void Opc_std_cc(); void Opc_std_cd(); void Opc_std_ce(); void Opc_std_cf(); void Opc_std_d0(); void Opc_std_d1(); void Opc_std_d2(); void Opc_std_d3(); void Opc_std_d4(); void Opc_std_d5(); void Opc_std_d6(); void Opc_std_d7(); void Opc_std_d8(); void Opc_std_d9(); void Opc_std_da(); void Opc_std_db(); void Opc_std_dc(); void Opc_std_dd(); void Opc_std_de(); void Opc_std_df(); void Opc_std_e0(); void Opc_std_e1(); void Opc_std_e2(); void Opc_std_e3(); void Opc_std_e4(); void Opc_std_e5(); void Opc_std_e6(); void Opc_std_e7(); void Opc_std_e8(); void Opc_std_e9(); void Opc_std_ea(); void Opc_std_eb(); void Opc_std_ec(); void Opc_std_ed(); void Opc_std_ee(); void Opc_std_ef(); void Opc_std_f0(); void Opc_std_f1(); void Opc_std_f2(); void Opc_std_f3(); void Opc_std_f4(); void Opc_std_f5(); void Opc_std_f6(); void Opc_std_f7(); void Opc_std_f8(); void Opc_std_f9(); void Opc_std_fa(); void Opc_std_fb(); void Opc_std_fc(); void Opc_std_fd(); void Opc_std_fe(); void Opc_std_ff(); // Opcodes CBXX prototypes. void Opc_cbxx_00(); void Opc_cbxx_01(); void Opc_cbxx_02(); void Opc_cbxx_03(); void Opc_cbxx_04(); void Opc_cbxx_05(); void Opc_cbxx_06(); void Opc_cbxx_07(); void Opc_cbxx_08(); void Opc_cbxx_09(); void Opc_cbxx_0a(); void Opc_cbxx_0b(); void Opc_cbxx_0c(); void Opc_cbxx_0d(); void Opc_cbxx_0e(); void Opc_cbxx_0f(); void Opc_cbxx_10(); void Opc_cbxx_11(); void Opc_cbxx_12(); void Opc_cbxx_13(); void Opc_cbxx_14(); void Opc_cbxx_15(); void Opc_cbxx_16(); void Opc_cbxx_17(); void Opc_cbxx_18(); void Opc_cbxx_19(); void Opc_cbxx_1a(); void Opc_cbxx_1b(); void Opc_cbxx_1c(); void Opc_cbxx_1d(); void Opc_cbxx_1e(); void Opc_cbxx_1f(); void Opc_cbxx_20(); void Opc_cbxx_21(); void Opc_cbxx_22(); void Opc_cbxx_23(); void Opc_cbxx_24(); void Opc_cbxx_25(); void Opc_cbxx_26(); void Opc_cbxx_27(); void Opc_cbxx_28(); void Opc_cbxx_29(); void Opc_cbxx_2a(); void Opc_cbxx_2b(); void Opc_cbxx_2c(); void Opc_cbxx_2d(); void Opc_cbxx_2e(); void Opc_cbxx_2f(); void Opc_cbxx_30(); void Opc_cbxx_31(); void Opc_cbxx_32(); void Opc_cbxx_33(); void Opc_cbxx_34(); void Opc_cbxx_35(); void Opc_cbxx_36(); void Opc_cbxx_37(); void Opc_cbxx_38(); void Opc_cbxx_39(); void Opc_cbxx_3a(); void Opc_cbxx_3b(); void Opc_cbxx_3c(); void Opc_cbxx_3d(); void Opc_cbxx_3e(); void Opc_cbxx_3f(); void Opc_cbxx_40(); void Opc_cbxx_41(); void Opc_cbxx_42(); void Opc_cbxx_43(); void Opc_cbxx_44(); void Opc_cbxx_45(); void Opc_cbxx_46(); void Opc_cbxx_47(); void Opc_cbxx_48(); void Opc_cbxx_49(); void Opc_cbxx_4a(); void Opc_cbxx_4b(); void Opc_cbxx_4c(); void Opc_cbxx_4d(); void Opc_cbxx_4e(); void Opc_cbxx_4f(); void Opc_cbxx_50(); void Opc_cbxx_51(); void Opc_cbxx_52(); void Opc_cbxx_53(); void Opc_cbxx_54(); void Opc_cbxx_55(); void Opc_cbxx_56(); void Opc_cbxx_57(); void Opc_cbxx_58(); void Opc_cbxx_59(); void Opc_cbxx_5a(); void Opc_cbxx_5b(); void Opc_cbxx_5c(); void Opc_cbxx_5d(); void Opc_cbxx_5e(); void Opc_cbxx_5f(); void Opc_cbxx_60(); void Opc_cbxx_61(); void Opc_cbxx_62(); void Opc_cbxx_63(); void Opc_cbxx_64(); void Opc_cbxx_65(); void Opc_cbxx_66(); void Opc_cbxx_67(); void Opc_cbxx_68(); void Opc_cbxx_69(); void Opc_cbxx_6a(); void Opc_cbxx_6b(); void Opc_cbxx_6c(); void Opc_cbxx_6d(); void Opc_cbxx_6e(); void Opc_cbxx_6f(); void Opc_cbxx_70(); void Opc_cbxx_71(); void Opc_cbxx_72(); void Opc_cbxx_73(); void Opc_cbxx_74(); void Opc_cbxx_75(); void Opc_cbxx_76(); void Opc_cbxx_77(); void Opc_cbxx_78(); void Opc_cbxx_79(); void Opc_cbxx_7a(); void Opc_cbxx_7b(); void Opc_cbxx_7c(); void Opc_cbxx_7d(); void Opc_cbxx_7e(); void Opc_cbxx_7f(); void Opc_cbxx_80(); void Opc_cbxx_81(); void Opc_cbxx_82(); void Opc_cbxx_83(); void Opc_cbxx_84(); void Opc_cbxx_85(); void Opc_cbxx_86(); void Opc_cbxx_87(); void Opc_cbxx_88(); void Opc_cbxx_89(); void Opc_cbxx_8a(); void Opc_cbxx_8b(); void Opc_cbxx_8c(); void Opc_cbxx_8d(); void Opc_cbxx_8e(); void Opc_cbxx_8f(); void Opc_cbxx_90(); void Opc_cbxx_91(); void Opc_cbxx_92(); void Opc_cbxx_93(); void Opc_cbxx_94(); void Opc_cbxx_95(); void Opc_cbxx_96(); void Opc_cbxx_97(); void Opc_cbxx_98(); void Opc_cbxx_99(); void Opc_cbxx_9a(); void Opc_cbxx_9b(); void Opc_cbxx_9c(); void Opc_cbxx_9d(); void Opc_cbxx_9e(); void Opc_cbxx_9f(); void Opc_cbxx_a0(); void Opc_cbxx_a1(); void Opc_cbxx_a2(); void Opc_cbxx_a3(); void Opc_cbxx_a4(); void Opc_cbxx_a5(); void Opc_cbxx_a6(); void Opc_cbxx_a7(); void Opc_cbxx_a8(); void Opc_cbxx_a9(); void Opc_cbxx_aa(); void Opc_cbxx_ab(); void Opc_cbxx_ac(); void Opc_cbxx_ad(); void Opc_cbxx_ae(); void Opc_cbxx_af(); void Opc_cbxx_b0(); void Opc_cbxx_b1(); void Opc_cbxx_b2(); void Opc_cbxx_b3(); void Opc_cbxx_b4(); void Opc_cbxx_b5(); void Opc_cbxx_b6(); void Opc_cbxx_b7(); void Opc_cbxx_b8(); void Opc_cbxx_b9(); void Opc_cbxx_ba(); void Opc_cbxx_bb(); void Opc_cbxx_bc(); void Opc_cbxx_bd(); void Opc_cbxx_be(); void Opc_cbxx_bf(); void Opc_cbxx_c0(); void Opc_cbxx_c1(); void Opc_cbxx_c2(); void Opc_cbxx_c3(); void Opc_cbxx_c4(); void Opc_cbxx_c5(); void Opc_cbxx_c6(); void Opc_cbxx_c7(); void Opc_cbxx_c8(); void Opc_cbxx_c9(); void Opc_cbxx_ca(); void Opc_cbxx_cb(); void Opc_cbxx_cc(); void Opc_cbxx_cd(); void Opc_cbxx_ce(); void Opc_cbxx_cf(); void Opc_cbxx_d0(); void Opc_cbxx_d1(); void Opc_cbxx_d2(); void Opc_cbxx_d3(); void Opc_cbxx_d4(); void Opc_cbxx_d5(); void Opc_cbxx_d6(); void Opc_cbxx_d7(); void Opc_cbxx_d8(); void Opc_cbxx_d9(); void Opc_cbxx_da(); void Opc_cbxx_db(); void Opc_cbxx_dc(); void Opc_cbxx_dd(); void Opc_cbxx_de(); void Opc_cbxx_df(); void Opc_cbxx_e0(); void Opc_cbxx_e1(); void Opc_cbxx_e2(); void Opc_cbxx_e3(); void Opc_cbxx_e4(); void Opc_cbxx_e5(); void Opc_cbxx_e6(); void Opc_cbxx_e7(); void Opc_cbxx_e8(); void Opc_cbxx_e9(); void Opc_cbxx_ea(); void Opc_cbxx_eb(); void Opc_cbxx_ec(); void Opc_cbxx_ed(); void Opc_cbxx_ee(); void Opc_cbxx_ef(); void Opc_cbxx_f0(); void Opc_cbxx_f1(); void Opc_cbxx_f2(); void Opc_cbxx_f3(); void Opc_cbxx_f4(); void Opc_cbxx_f5(); void Opc_cbxx_f6(); void Opc_cbxx_f7(); void Opc_cbxx_f8(); void Opc_cbxx_f9(); void Opc_cbxx_fa(); void Opc_cbxx_fb(); void Opc_cbxx_fc(); void Opc_cbxx_fd(); void Opc_cbxx_fe(); void Opc_cbxx_ff(); // Opcodes DDXX prototypes. void Opc_ddxx_09(); void Opc_ddxx_19(); void Opc_ddxx_21(); void Opc_ddxx_22(); void Opc_ddxx_23(); void Opc_ddxx_24(); void Opc_ddxx_25(); void Opc_ddxx_26(); void Opc_ddxx_29(); void Opc_ddxx_2a(); void Opc_ddxx_2b(); void Opc_ddxx_2c(); void Opc_ddxx_2d(); void Opc_ddxx_2e(); void Opc_ddxx_34(); void Opc_ddxx_35(); void Opc_ddxx_36(); void Opc_ddxx_39(); void Opc_ddxx_44(); void Opc_ddxx_45(); void Opc_ddxx_46(); void Opc_ddxx_4c(); void Opc_ddxx_4d(); void Opc_ddxx_4e(); void Opc_ddxx_54(); void Opc_ddxx_55(); void Opc_ddxx_56(); void Opc_ddxx_5c(); void Opc_ddxx_5d(); void Opc_ddxx_5e(); void Opc_ddxx_60(); void Opc_ddxx_61(); void Opc_ddxx_62(); void Opc_ddxx_63(); void Opc_ddxx_64(); void Opc_ddxx_65(); void Opc_ddxx_66(); void Opc_ddxx_67(); void Opc_ddxx_68(); void Opc_ddxx_69(); void Opc_ddxx_6a(); void Opc_ddxx_6b(); void Opc_ddxx_6c(); void Opc_ddxx_6d(); void Opc_ddxx_6e(); void Opc_ddxx_6f(); void Opc_ddxx_70(); void Opc_ddxx_71(); void Opc_ddxx_72(); void Opc_ddxx_73(); void Opc_ddxx_74(); void Opc_ddxx_75(); void Opc_ddxx_77(); void Opc_ddxx_7c(); void Opc_ddxx_7d(); void Opc_ddxx_7e(); void Opc_ddxx_84(); void Opc_ddxx_85(); void Opc_ddxx_86(); void Opc_ddxx_8c(); void Opc_ddxx_8d(); void Opc_ddxx_8e(); void Opc_ddxx_94(); void Opc_ddxx_95(); void Opc_ddxx_96(); void Opc_ddxx_9c(); void Opc_ddxx_9d(); void Opc_ddxx_9e(); void Opc_ddxx_a4(); void Opc_ddxx_a5(); void Opc_ddxx_a6(); void Opc_ddxx_ac(); void Opc_ddxx_ad(); void Opc_ddxx_ae(); void Opc_ddxx_b4(); void Opc_ddxx_b5(); void Opc_ddxx_b6(); void Opc_ddxx_bc(); void Opc_ddxx_bd(); void Opc_ddxx_be(); void Opc_ddxx_e1(); void Opc_ddxx_e3(); void Opc_ddxx_e5(); void Opc_ddxx_e9(); void Opc_ddxx_f9(); // Opcodes DDCB prototypes. void Opc_ddcb_00(); void Opc_ddcb_01(); void Opc_ddcb_02(); void Opc_ddcb_03(); void Opc_ddcb_04(); void Opc_ddcb_05(); void Opc_ddcb_06(); void Opc_ddcb_07(); void Opc_ddcb_08(); void Opc_ddcb_09(); void Opc_ddcb_0a(); void Opc_ddcb_0b(); void Opc_ddcb_0c(); void Opc_ddcb_0d(); void Opc_ddcb_0e(); void Opc_ddcb_0f(); void Opc_ddcb_10(); void Opc_ddcb_11(); void Opc_ddcb_12(); void Opc_ddcb_13(); void Opc_ddcb_14(); void Opc_ddcb_15(); void Opc_ddcb_16(); void Opc_ddcb_17(); void Opc_ddcb_18(); void Opc_ddcb_19(); void Opc_ddcb_1a(); void Opc_ddcb_1b(); void Opc_ddcb_1c(); void Opc_ddcb_1d(); void Opc_ddcb_1e(); void Opc_ddcb_1f(); void Opc_ddcb_20(); void Opc_ddcb_21(); void Opc_ddcb_22(); void Opc_ddcb_23(); void Opc_ddcb_24(); void Opc_ddcb_25(); void Opc_ddcb_26(); void Opc_ddcb_27(); void Opc_ddcb_28(); void Opc_ddcb_29(); void Opc_ddcb_2a(); void Opc_ddcb_2b(); void Opc_ddcb_2c(); void Opc_ddcb_2d(); void Opc_ddcb_2e(); void Opc_ddcb_2f(); void Opc_ddcb_30(); void Opc_ddcb_31(); void Opc_ddcb_32(); void Opc_ddcb_33(); void Opc_ddcb_34(); void Opc_ddcb_35(); void Opc_ddcb_36(); void Opc_ddcb_37(); void Opc_ddcb_38(); void Opc_ddcb_39(); void Opc_ddcb_3a(); void Opc_ddcb_3b(); void Opc_ddcb_3c(); void Opc_ddcb_3d(); void Opc_ddcb_3e(); void Opc_ddcb_3f(); void Opc_ddcb_40(); void Opc_ddcb_41(); void Opc_ddcb_42(); void Opc_ddcb_43(); void Opc_ddcb_44(); void Opc_ddcb_45(); void Opc_ddcb_46(); void Opc_ddcb_47(); void Opc_ddcb_48(); void Opc_ddcb_49(); void Opc_ddcb_4a(); void Opc_ddcb_4b(); void Opc_ddcb_4c(); void Opc_ddcb_4d(); void Opc_ddcb_4e(); void Opc_ddcb_4f(); void Opc_ddcb_50(); void Opc_ddcb_51(); void Opc_ddcb_52(); void Opc_ddcb_53(); void Opc_ddcb_54(); void Opc_ddcb_55(); void Opc_ddcb_56(); void Opc_ddcb_57(); void Opc_ddcb_58(); void Opc_ddcb_59(); void Opc_ddcb_5a(); void Opc_ddcb_5b(); void Opc_ddcb_5c(); void Opc_ddcb_5d(); void Opc_ddcb_5e(); void Opc_ddcb_5f(); void Opc_ddcb_60(); void Opc_ddcb_61(); void Opc_ddcb_62(); void Opc_ddcb_63(); void Opc_ddcb_64(); void Opc_ddcb_65(); void Opc_ddcb_66(); void Opc_ddcb_67(); void Opc_ddcb_68(); void Opc_ddcb_69(); void Opc_ddcb_6a(); void Opc_ddcb_6b(); void Opc_ddcb_6c(); void Opc_ddcb_6d(); void Opc_ddcb_6e(); void Opc_ddcb_6f(); void Opc_ddcb_70(); void Opc_ddcb_71(); void Opc_ddcb_72(); void Opc_ddcb_73(); void Opc_ddcb_74(); void Opc_ddcb_75(); void Opc_ddcb_76(); void Opc_ddcb_77(); void Opc_ddcb_78(); void Opc_ddcb_79(); void Opc_ddcb_7a(); void Opc_ddcb_7b(); void Opc_ddcb_7c(); void Opc_ddcb_7d(); void Opc_ddcb_7e(); void Opc_ddcb_7f(); void Opc_ddcb_80(); void Opc_ddcb_81(); void Opc_ddcb_82(); void Opc_ddcb_83(); void Opc_ddcb_84(); void Opc_ddcb_85(); void Opc_ddcb_86(); void Opc_ddcb_87(); void Opc_ddcb_88(); void Opc_ddcb_89(); void Opc_ddcb_8a(); void Opc_ddcb_8b(); void Opc_ddcb_8c(); void Opc_ddcb_8d(); void Opc_ddcb_8e(); void Opc_ddcb_8f(); void Opc_ddcb_90(); void Opc_ddcb_91(); void Opc_ddcb_92(); void Opc_ddcb_93(); void Opc_ddcb_94(); void Opc_ddcb_95(); void Opc_ddcb_96(); void Opc_ddcb_97(); void Opc_ddcb_98(); void Opc_ddcb_99(); void Opc_ddcb_9a(); void Opc_ddcb_9b(); void Opc_ddcb_9c(); void Opc_ddcb_9d(); void Opc_ddcb_9e(); void Opc_ddcb_9f(); void Opc_ddcb_a0(); void Opc_ddcb_a1(); void Opc_ddcb_a2(); void Opc_ddcb_a3(); void Opc_ddcb_a4(); void Opc_ddcb_a5(); void Opc_ddcb_a6(); void Opc_ddcb_a7(); void Opc_ddcb_a8(); void Opc_ddcb_a9(); void Opc_ddcb_aa(); void Opc_ddcb_ab(); void Opc_ddcb_ac(); void Opc_ddcb_ad(); void Opc_ddcb_ae(); void Opc_ddcb_af(); void Opc_ddcb_b0(); void Opc_ddcb_b1(); void Opc_ddcb_b2(); void Opc_ddcb_b3(); void Opc_ddcb_b4(); void Opc_ddcb_b5(); void Opc_ddcb_b6(); void Opc_ddcb_b7(); void Opc_ddcb_b8(); void Opc_ddcb_b9(); void Opc_ddcb_ba(); void Opc_ddcb_bb(); void Opc_ddcb_bc(); void Opc_ddcb_bd(); void Opc_ddcb_be(); void Opc_ddcb_bf(); void Opc_ddcb_c0(); void Opc_ddcb_c1(); void Opc_ddcb_c2(); void Opc_ddcb_c3(); void Opc_ddcb_c4(); void Opc_ddcb_c5(); void Opc_ddcb_c6(); void Opc_ddcb_c7(); void Opc_ddcb_c8(); void Opc_ddcb_c9(); void Opc_ddcb_ca(); void Opc_ddcb_cb(); void Opc_ddcb_cc(); void Opc_ddcb_cd(); void Opc_ddcb_ce(); void Opc_ddcb_cf(); void Opc_ddcb_d0(); void Opc_ddcb_d1(); void Opc_ddcb_d2(); void Opc_ddcb_d3(); void Opc_ddcb_d4(); void Opc_ddcb_d5(); void Opc_ddcb_d6(); void Opc_ddcb_d7(); void Opc_ddcb_d8(); void Opc_ddcb_d9(); void Opc_ddcb_da(); void Opc_ddcb_db(); void Opc_ddcb_dc(); void Opc_ddcb_dd(); void Opc_ddcb_de(); void Opc_ddcb_df(); void Opc_ddcb_e0(); void Opc_ddcb_e1(); void Opc_ddcb_e2(); void Opc_ddcb_e3(); void Opc_ddcb_e4(); void Opc_ddcb_e5(); void Opc_ddcb_e6(); void Opc_ddcb_e7(); void Opc_ddcb_e8(); void Opc_ddcb_e9(); void Opc_ddcb_ea(); void Opc_ddcb_eb(); void Opc_ddcb_ec(); void Opc_ddcb_ed(); void Opc_ddcb_ee(); void Opc_ddcb_ef(); void Opc_ddcb_f0(); void Opc_ddcb_f1(); void Opc_ddcb_f2(); void Opc_ddcb_f3(); void Opc_ddcb_f4(); void Opc_ddcb_f5(); void Opc_ddcb_f6(); void Opc_ddcb_f7(); void Opc_ddcb_f8(); void Opc_ddcb_f9(); void Opc_ddcb_fa(); void Opc_ddcb_fb(); void Opc_ddcb_fc(); void Opc_ddcb_fd(); void Opc_ddcb_fe(); void Opc_ddcb_ff(); // Opcodes EDxx prototypes. void Opc_edxx_40(); void Opc_edxx_41(); void Opc_edxx_42(); void Opc_edxx_43(); void Opc_edxx_44(); void Opc_edxx_45(); void Opc_edxx_46(); void Opc_edxx_47(); void Opc_edxx_48(); void Opc_edxx_49(); void Opc_edxx_4a(); void Opc_edxx_4b(); void Opc_edxx_4c(); void Opc_edxx_4d(); void Opc_edxx_4e(); void Opc_edxx_4f(); void Opc_edxx_50(); void Opc_edxx_51(); void Opc_edxx_52(); void Opc_edxx_53(); void Opc_edxx_54(); void Opc_edxx_55(); void Opc_edxx_56(); void Opc_edxx_57(); void Opc_edxx_58(); void Opc_edxx_59(); void Opc_edxx_5a(); void Opc_edxx_5b(); void Opc_edxx_5c(); void Opc_edxx_5d(); void Opc_edxx_5e(); void Opc_edxx_5f(); void Opc_edxx_60(); void Opc_edxx_61(); void Opc_edxx_62(); void Opc_edxx_63(); void Opc_edxx_64(); void Opc_edxx_65(); void Opc_edxx_66(); void Opc_edxx_67(); void Opc_edxx_68(); void Opc_edxx_69(); void Opc_edxx_6a(); void Opc_edxx_6b(); void Opc_edxx_6c(); void Opc_edxx_6d(); void Opc_edxx_6e(); void Opc_edxx_6f(); void Opc_edxx_70(); void Opc_edxx_71(); void Opc_edxx_72(); void Opc_edxx_73(); void Opc_edxx_74(); void Opc_edxx_75(); void Opc_edxx_76(); void Opc_edxx_78(); void Opc_edxx_79(); void Opc_edxx_7a(); void Opc_edxx_7b(); void Opc_edxx_7c(); void Opc_edxx_7d(); void Opc_edxx_7e(); void Opc_edxx_a0(); void Opc_edxx_a1(); void Opc_edxx_a2(); void Opc_edxx_a3(); void Opc_edxx_a8(); void Opc_edxx_a9(); void Opc_edxx_aa(); void Opc_edxx_ab(); void Opc_edxx_b0(); void Opc_edxx_b1(); void Opc_edxx_b2(); void Opc_edxx_b3(); void Opc_edxx_b8(); void Opc_edxx_b9(); void Opc_edxx_ba(); void Opc_edxx_bb(); // Opcodes FDXX prototypes. void Opc_fdxx_09(); void Opc_fdxx_19(); void Opc_fdxx_21(); void Opc_fdxx_22(); void Opc_fdxx_23(); void Opc_fdxx_24(); void Opc_fdxx_25(); void Opc_fdxx_26(); void Opc_fdxx_29(); void Opc_fdxx_2a(); void Opc_fdxx_2b(); void Opc_fdxx_2c(); void Opc_fdxx_2d(); void Opc_fdxx_2e(); void Opc_fdxx_34(); void Opc_fdxx_35(); void Opc_fdxx_36(); void Opc_fdxx_39(); void Opc_fdxx_44(); void Opc_fdxx_45(); void Opc_fdxx_46(); void Opc_fdxx_4c(); void Opc_fdxx_4d(); void Opc_fdxx_4e(); void Opc_fdxx_54(); void Opc_fdxx_55(); void Opc_fdxx_56(); void Opc_fdxx_5c(); void Opc_fdxx_5d(); void Opc_fdxx_5e(); void Opc_fdxx_60(); void Opc_fdxx_61(); void Opc_fdxx_62(); void Opc_fdxx_63(); void Opc_fdxx_64(); void Opc_fdxx_65(); void Opc_fdxx_66(); void Opc_fdxx_67(); void Opc_fdxx_68(); void Opc_fdxx_69(); void Opc_fdxx_6a(); void Opc_fdxx_6b(); void Opc_fdxx_6c(); void Opc_fdxx_6d(); void Opc_fdxx_6e(); void Opc_fdxx_6f(); void Opc_fdxx_70(); void Opc_fdxx_71(); void Opc_fdxx_72(); void Opc_fdxx_73(); void Opc_fdxx_74(); void Opc_fdxx_75(); void Opc_fdxx_77(); void Opc_fdxx_7c(); void Opc_fdxx_7d(); void Opc_fdxx_7e(); void Opc_fdxx_84(); void Opc_fdxx_85(); void Opc_fdxx_86(); void Opc_fdxx_8c(); void Opc_fdxx_8d(); void Opc_fdxx_8e(); void Opc_fdxx_94(); void Opc_fdxx_95(); void Opc_fdxx_96(); void Opc_fdxx_9c(); void Opc_fdxx_9d(); void Opc_fdxx_9e(); void Opc_fdxx_a4(); void Opc_fdxx_a5(); void Opc_fdxx_a6(); void Opc_fdxx_ac(); void Opc_fdxx_ad(); void Opc_fdxx_ae(); void Opc_fdxx_b4(); void Opc_fdxx_b5(); void Opc_fdxx_b6(); void Opc_fdxx_bc(); void Opc_fdxx_bd(); void Opc_fdxx_be(); void Opc_fdxx_e1(); void Opc_fdxx_e3(); void Opc_fdxx_e5(); void Opc_fdxx_e9(); void Opc_fdxx_f9(); // Opcodes FDCB prototypes. void Opc_fdcb_00(); void Opc_fdcb_01(); void Opc_fdcb_02(); void Opc_fdcb_03(); void Opc_fdcb_04(); void Opc_fdcb_05(); void Opc_fdcb_06(); void Opc_fdcb_07(); void Opc_fdcb_08(); void Opc_fdcb_09(); void Opc_fdcb_0a(); void Opc_fdcb_0b(); void Opc_fdcb_0c(); void Opc_fdcb_0d(); void Opc_fdcb_0e(); void Opc_fdcb_0f(); void Opc_fdcb_10(); void Opc_fdcb_11(); void Opc_fdcb_12(); void Opc_fdcb_13(); void Opc_fdcb_14(); void Opc_fdcb_15(); void Opc_fdcb_16(); void Opc_fdcb_17(); void Opc_fdcb_18(); void Opc_fdcb_19(); void Opc_fdcb_1a(); void Opc_fdcb_1b(); void Opc_fdcb_1c(); void Opc_fdcb_1d(); void Opc_fdcb_1e(); void Opc_fdcb_1f(); void Opc_fdcb_20(); void Opc_fdcb_21(); void Opc_fdcb_22(); void Opc_fdcb_23(); void Opc_fdcb_24(); void Opc_fdcb_25(); void Opc_fdcb_26(); void Opc_fdcb_27(); void Opc_fdcb_28(); void Opc_fdcb_29(); void Opc_fdcb_2a(); void Opc_fdcb_2b(); void Opc_fdcb_2c(); void Opc_fdcb_2d(); void Opc_fdcb_2e(); void Opc_fdcb_2f(); void Opc_fdcb_30(); void Opc_fdcb_31(); void Opc_fdcb_32(); void Opc_fdcb_33(); void Opc_fdcb_34(); void Opc_fdcb_35(); void Opc_fdcb_36(); void Opc_fdcb_37(); void Opc_fdcb_38(); void Opc_fdcb_39(); void Opc_fdcb_3a(); void Opc_fdcb_3b(); void Opc_fdcb_3c(); void Opc_fdcb_3d(); void Opc_fdcb_3e(); void Opc_fdcb_3f(); void Opc_fdcb_40(); void Opc_fdcb_41(); void Opc_fdcb_42(); void Opc_fdcb_43(); void Opc_fdcb_44(); void Opc_fdcb_45(); void Opc_fdcb_46(); void Opc_fdcb_47(); void Opc_fdcb_48(); void Opc_fdcb_49(); void Opc_fdcb_4a(); void Opc_fdcb_4b(); void Opc_fdcb_4c(); void Opc_fdcb_4d(); void Opc_fdcb_4e(); void Opc_fdcb_4f(); void Opc_fdcb_50(); void Opc_fdcb_51(); void Opc_fdcb_52(); void Opc_fdcb_53(); void Opc_fdcb_54(); void Opc_fdcb_55(); void Opc_fdcb_56(); void Opc_fdcb_57(); void Opc_fdcb_58(); void Opc_fdcb_59(); void Opc_fdcb_5a(); void Opc_fdcb_5b(); void Opc_fdcb_5c(); void Opc_fdcb_5d(); void Opc_fdcb_5e(); void Opc_fdcb_5f(); void Opc_fdcb_60(); void Opc_fdcb_61(); void Opc_fdcb_62(); void Opc_fdcb_63(); void Opc_fdcb_64(); void Opc_fdcb_65(); void Opc_fdcb_66(); void Opc_fdcb_67(); void Opc_fdcb_68(); void Opc_fdcb_69(); void Opc_fdcb_6a(); void Opc_fdcb_6b(); void Opc_fdcb_6c(); void Opc_fdcb_6d(); void Opc_fdcb_6e(); void Opc_fdcb_6f(); void Opc_fdcb_70(); void Opc_fdcb_71(); void Opc_fdcb_72(); void Opc_fdcb_73(); void Opc_fdcb_74(); void Opc_fdcb_75(); void Opc_fdcb_76(); void Opc_fdcb_77(); void Opc_fdcb_78(); void Opc_fdcb_79(); void Opc_fdcb_7a(); void Opc_fdcb_7b(); void Opc_fdcb_7c(); void Opc_fdcb_7d(); void Opc_fdcb_7e(); void Opc_fdcb_7f(); void Opc_fdcb_80(); void Opc_fdcb_81(); void Opc_fdcb_82(); void Opc_fdcb_83(); void Opc_fdcb_84(); void Opc_fdcb_85(); void Opc_fdcb_86(); void Opc_fdcb_87(); void Opc_fdcb_88(); void Opc_fdcb_89(); void Opc_fdcb_8a(); void Opc_fdcb_8b(); void Opc_fdcb_8c(); void Opc_fdcb_8d(); void Opc_fdcb_8e(); void Opc_fdcb_8f(); void Opc_fdcb_90(); void Opc_fdcb_91(); void Opc_fdcb_92(); void Opc_fdcb_93(); void Opc_fdcb_94(); void Opc_fdcb_95(); void Opc_fdcb_96(); void Opc_fdcb_97(); void Opc_fdcb_98(); void Opc_fdcb_99(); void Opc_fdcb_9a(); void Opc_fdcb_9b(); void Opc_fdcb_9c(); void Opc_fdcb_9d(); void Opc_fdcb_9e(); void Opc_fdcb_9f(); void Opc_fdcb_a0(); void Opc_fdcb_a1(); void Opc_fdcb_a2(); void Opc_fdcb_a3(); void Opc_fdcb_a4(); void Opc_fdcb_a5(); void Opc_fdcb_a6(); void Opc_fdcb_a7(); void Opc_fdcb_a8(); void Opc_fdcb_a9(); void Opc_fdcb_aa(); void Opc_fdcb_ab(); void Opc_fdcb_ac(); void Opc_fdcb_ad(); void Opc_fdcb_ae(); void Opc_fdcb_af(); void Opc_fdcb_b0(); void Opc_fdcb_b1(); void Opc_fdcb_b2(); void Opc_fdcb_b3(); void Opc_fdcb_b4(); void Opc_fdcb_b5(); void Opc_fdcb_b6(); void Opc_fdcb_b7(); void Opc_fdcb_b8(); void Opc_fdcb_b9(); void Opc_fdcb_ba(); void Opc_fdcb_bb(); void Opc_fdcb_bc(); void Opc_fdcb_bd(); void Opc_fdcb_be(); void Opc_fdcb_bf(); void Opc_fdcb_c0(); void Opc_fdcb_c1(); void Opc_fdcb_c2(); void Opc_fdcb_c3(); void Opc_fdcb_c4(); void Opc_fdcb_c5(); void Opc_fdcb_c6(); void Opc_fdcb_c7(); void Opc_fdcb_c8(); void Opc_fdcb_c9(); void Opc_fdcb_ca(); void Opc_fdcb_cb(); void Opc_fdcb_cc(); void Opc_fdcb_cd(); void Opc_fdcb_ce(); void Opc_fdcb_cf(); void Opc_fdcb_d0(); void Opc_fdcb_d1(); void Opc_fdcb_d2(); void Opc_fdcb_d3(); void Opc_fdcb_d4(); void Opc_fdcb_d5(); void Opc_fdcb_d6(); void Opc_fdcb_d7(); void Opc_fdcb_d8(); void Opc_fdcb_d9(); void Opc_fdcb_da(); void Opc_fdcb_db(); void Opc_fdcb_dc(); void Opc_fdcb_dd(); void Opc_fdcb_de(); void Opc_fdcb_df(); void Opc_fdcb_e0(); void Opc_fdcb_e1(); void Opc_fdcb_e2(); void Opc_fdcb_e3(); void Opc_fdcb_e4(); void Opc_fdcb_e5(); void Opc_fdcb_e6(); void Opc_fdcb_e7(); void Opc_fdcb_e8(); void Opc_fdcb_e9(); void Opc_fdcb_ea(); void Opc_fdcb_eb(); void Opc_fdcb_ec(); void Opc_fdcb_ed(); void Opc_fdcb_ee(); void Opc_fdcb_ef(); void Opc_fdcb_f0(); void Opc_fdcb_f1(); void Opc_fdcb_f2(); void Opc_fdcb_f3(); void Opc_fdcb_f4(); void Opc_fdcb_f5(); void Opc_fdcb_f6(); void Opc_fdcb_f7(); void Opc_fdcb_f8(); void Opc_fdcb_f9(); void Opc_fdcb_fa(); void Opc_fdcb_fb(); void Opc_fdcb_fc(); void Opc_fdcb_fd(); void Opc_fdcb_fe(); void Opc_fdcb_ff(); /* Pre computed variables. */ static u8 bitval[8]; static u8 PF_SF_ZF_[256]; static u8 PF_[256]; /* Jump tables. */ typedef void (Z80::* Opc_handler)(); static Opc_handler Opc_std[256]; static Opc_handler Opc_cbxx[256]; static Opc_handler Opc_ddxx[256]; static Opc_handler Opc_ddcb[256]; static Opc_handler Opc_edxx[256]; static Opc_handler Opc_fdxx[256]; static Opc_handler Opc_fdcb[256]; }; #endif osmose-emulator-1.4/src/main.cpp000066400000000000000000000037161341430144300167340ustar00rootroot00000000000000/* * Copyright holder 2001-2011 Vedder Bruno. * Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] * * This file is part of Osmose, a Sega Master System/Game Gear software * emulator. * * Osmose is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Osmose is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Osmose. If not, see . * * Many thanks to Vedder Bruno, the original author of Osmose Emulator. * */ #include #include #include "OsmoseGUI.h" // GNOME3 on Debian has XDG_SESSION_TYPE, which Qt warns about at startup: // // Warning: Ignoring XDG_SESSION_TYPE=wayland on Gnome. // Use QT_QPA_PLATFORM=wayland to run on Wayland anyway. // // In this case, the warning is muted. This hack will be retained here until a // future version of Qt provides Qt Wayland widgets that are usable // in the gnome shell. Cf. https://bugreports.qt.io/browse/QTBUG-68619 int main(int argc, char *argv[]) { if (qgetenv("XDG_SESSION_TYPE") == QByteArrayLiteral("wayland")) { qunsetenv("XDG_SESSION_TYPE"); qEnvironmentVariable("QT_QPA_PLATFORM", "wayland"); } QApplication app(argc, argv); OsmoseGUI window; window.resize(512, 384 + MENU_HEIGHT); window.show(); for (int i=1; i < argc; i++) { if(QString(argv[i]) == "-f" || QString(argv[i]) == "--fullscreen") { window.toggleFullscreen(); } else { QString rom_file = argv[i]; window.loadTheROM(rom_file); } } return app.exec(); } osmose-emulator-1.4/src/osmose-emulator.6000066400000000000000000000050611341430144300205210ustar00rootroot00000000000000.\" Copyright holder 2001-2011 Vedder Bruno. .\" Work continued by 2016-2018 Carlos Donizete Froes [a.k.a coringao] .\" .\" This file is part of Osmose, a Sega Master System/Game Gear software .\" emulator. .\" .\" Osmose is free software: you can redistribute it and/or modify .\" it under the terms of the GNU General Public License as published by .\" the Free Software Foundation, either version 3 of the License, or .\" any later version. .\" .\" Osmose is distributed in the hope that it will be useful, .\" but WITHOUT ANY WARRANTY; without even the implied warranty of .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the .\" GNU General Public License for more details. .\" .\" You should have received a copy of the GNU General Public License .\" along with Osmose. If not, see . .\" .\" Many thanks to Vedder Bruno, the original author of Osmose Emulator. .\" .TH osmose-emulator "6" "September 2018" "OSMOSE EMULATOR" "Sega Master System and Game Gear console emulator" .SH NAME osmose-emulator \- is for Master System and Game Gear consoles with excellent performance and compatibility in emulated games. .br .SH SYNOPSIS .B osmose-emulator .RI [ description ] .RI [ command ] .RI [ keyboard ] .RI [ author ] .br .PP .SH DESCRIPTION .br A multi-machine emulator for platforms of Sega consoles (Master System and Game Gear) and compatible for all games. .PP Simulates hardware extremely accurately which ensures that these classic games are represented exactly like they were on the real systems. .PP Osmose Emulator has a clean graphical user interface based on QT and a simplified setup process, and supports ROM archives in the SMS and GG formats. .br .PP .SH COMMAND .br Basic emulator command. .TP .B Ctrl+O - Find the directory where is located the roms. .TP .B Ctrl+R - Reset the game. .TP .B Ctrl+F - Leaves the full screen mode and to return in window mode, press again. .br .SH KEYBOARD Basic movement and action command. To enter configuration mode, button Ctrl + C. .PP .B Control P1: (Standard Mode) .PP .B KEY ACTION .br Pad1 UP up arrow .PP Pad1 DOWN down arrow .PP Pad1 LEFT left arrow .PP Pad1 RIGHT right arrow .PP Pad1 Button A press letter Z .PP Pad1 Button B press letter X .PP PAUSE/SELECT press letter P .PP START (GameGear) press letter S .PP .SH AUTHOR Many thanks to Vedder Bruno, the original author of Osmose Emulator and continued by Carlos Donizete Froes [a.k.a coringao]. .PP This manual page was written by Carlos Donizete Froes [a.k.a coringao], for the Debian project (but may be used by others). osmose-emulator-1.4/src/osmose-emulator.png000066400000000000000000001710651341430144300211500ustar00rootroot00000000000000‰PNG  IHDRôxÔúsBIT|dˆ pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<tEXtTitleOsmose Emulatorb"-ì-tEXtAuthorCarlos Donizete Froes [a.k.a coringao]¸~(Ì=tEXtDescriptionSega Master System and Game Gear console emulator+aÁ1tEXtCreation Time06-04-2017Íé1tEXtCopyrightFreeArt http://artlibre.org/licence/lal(zwÛ IDATxœì½y|Å™ÿÿ©îžC‡%[’eù¾d°m0c0sŸ!6rÂîB¾“„ÀnHv!!ûãØ$$lÈ! WÈE|@bÌiðøÄȇlÉ’uK3Ó]õüþèC3£¹¤™žIõ~½æ5RwO×ÓUÕõ<õÔSU ‰¤ !"@5€ÑªTîÞ±£âåW^µlÙ²‘ãÆ+PÆF(…@1ŠQ€€€@ `vÀ ˆƒ‚‚uJ7€Nuh¡MQÐ (-‡:¶îëšÏ<ó̦iÓ¦ÐÈùÉ!‰D24¯H†3DT`28&a" &ÆÆP ‚ªÁ ]‡æóAp.Á`8pô8Y7e±i0w / ¦A ô9cÞ$ê‹9'FDŒÁˆèª¦èˆê”ƒ €Šýêcíf•D"É1ÒH\†ˆÆ83ÀD-€é 6 S!¨ @”ÒŽSæÀHh>@EU†à€Â@¶>ŽþMnåwŒ"²Db1çEçÛú»DÕæÅ8L⢠„}`´À^²*vØÅkpç‰$ ‰$gÑx˜'b6ˆÍÃLª`éÀØÞ³U`¨Ø©L+¦×8haí” ð>4lgŒòP^‰dÈ ‰dÑpÌ$NRTv"s!¨N˜¹§äœ^ŒL.{<  ‹¶ sBÄE#¶h Hy*ÞeŒm÷ZX‰d°! ‰$ Ó×­^½pÖì9§Î7÷…±S@(#SÇ…;X¨á<€g{ ˆ‹.6ƒÑfm„ª¾ÍÛëµ I!# ‰$"Z 3Àèt€ÖÜÔ4ÎTõ$=÷…K –l Áô‚¼ýæÛõ{vïzë¼ /x£ººúuÆØk^ )‘Ò kˆH…³¡ˆ%`ì,C OcõƒGÀ•®B€ˆÂDôcìUÃ0ÖkšöOÆ÷ZJ‰Ä+¤ vÑ"œ Fç@ÐÙPà3Ö½–¬ëýCjìß-Dt.cì\EQ@\è$Ä?Aì(x™1ö¦×J$ùD’!MÇ…`â€çL½“ s¸ãá|€Î·âšZRÖ@ÅjÆØ¯”HÜD’!‰9Ž/.±‹ hA̼~¢@X3=s»!z¡½Üè÷3´`>2a~`”4?@ÀþŒþ ƒ6áïPð7? ŠH@2$ "ËÀÄ廂ƹ:O2ôaX`ÝM\ÔôWòg¨ø“\æX2€dÐBDEàø$˜¸‚–™ëßK/q…q[F+ ÐMœÿ ¤¼dŒõx-œD2¤ T‘WA¡OAÐ'Á I¥/É3ÅQC ñGö{¨xž1ñZ8‰$S¤ AW€‰«!è*0eŸ¤@Ð@XFË!"Ο)Ï2½àµ`I:¤ )Xˆh±âÓ Ø5UËž¾¤À ì:0ºŽ¸hè(Êïd¡¤PI+‘ä“mÛ¶M|üñÇïlllÜ`cìÕ^Ë%‘ô“j€ÝAˆ‹-ÄéN"šèµPI4ÒdW !þÈÛÏû€y^Ë$‘äˆy}„ýuûêþøøÏ¿Êk$@!¢Zâü^´ŸÀžp…×2I$îBW€Ñs»wîÚOœßKDµ^K$¾H@’wÈ O˜‘Ó´`w®QÉpc"ÀÝ$ÄÉ Ox-dø! I^ ¢2â´’¸øŒ^ÉÞ¾D \F/@œVQ™×"I†Ò¸ Í!ÎA=`–×2I$ Ã,€€ Fâô#"šãµH’¡4$®@:]@Bü‚¶ì¯e’H 0ÜAÛHˆß“Nx-dh" IN!ƒ®%C¼ …Vƒp¥×òH$ƒ•Ph5âU2èZ¯Å‘ -¤ É Äéfâb;ý gz-D2¤`8Œ~C\l'N7{-Ždh É€!"…8ÝN\| УNðZ&‰dˆs@§Û‰H¶á’#+¤ß‘8}‚ô €ÉÙÞ“) ˆ 00ƒ0/—ÿefÚ¤0èB)¦SR½B„~ïaŸT”‰‹úŽþäÆXÌßñÿ ! „¹;®båYÿƒå¢üÒäc\Ž|¤@pPÀÌB‹‘=ëtûƒ•®¾°Ë2./{“N›îd€„ CÄéDäË ’á„Ü @’1D¤Bˆ;ˆ‹Û‘ÃåyçP5ÍQ.DŸÏlÏ ]‡ªª¹J*!vÃKV£Û«@È9®(Š#‡­ÜÈù›PT  ¦(N^Ùùå&ñù\Õ4(Š"çDdtBôy’ÏþØ2iV½""ÇXQ⌶|å€>õÈ–+ jº·çAQ`Œñì$– ¤ É"º„;À”±9éÔE¡Z ²Ý8‹(¥¡ªjš^vîHÖ‹¨†:Z™ °”«Ø‡¢@pîøDƒ%_ùÓ瀥x£Ê+Z™2E1¨\W˜x¢òEýo{&y-˜íIA½YˆiÕ#Š—77T¸„ÿGD0ÆÊÝ­%CiHRÂ#üf¦àëÄÅT·Ò°{‹œs§'iFÌ97IÔ‹ŽW œóÃÄ4¬¿]–OÕîQ'Pn^äÓøa †a8²8ÞKÑåC>39ÓKolØ^ !DoÏÛ–R<[ޱëS|=r^ÆxPüÆð?LUËåÍ%C iHB] w‚ÈýMy¬^´ßïwܶޛ6{izœ!ųñù|½Š-îÚ|ôí¼`ŒAÕ4ç˜ýÉKþ¤8ç³ÊÍ–ËîùÛC®çc€í¥‰:¬ª*´¨ü²QžŠTÏ–#xÔ—]·£‡\*¿©%.þÄîgû­‰H7ÒÄ@¤_Rïœ/e"?cÌBG±uuuÅô’„{ ¤C¼K=úèºîÈ ªªšò…«òE+Të˜=Ö‡ÝOÉÇÉ£åÑu‘H$&Nä~œ„-³‚êH0‘H‘Hˆ:ý Xä‹6f Àaàœ;r¹Ì<€~# q#þ]æó­q;AÉàAQx„úŸ»`½VÜø©¨qã³¥¥¥½=J—£IõœEEEƒfƒÍ˜)—`yÉK8G¡ !à÷ûQ\\œ·‰øÀÈh‰àÜ‘Çîq½†‹ëòÙñQžX½í@ ŸÏ×;;ÁºVUÕüÇAÓ4ƒÁ^ÏDþê÷Rº”8=ÿÍÛž¯„%…‹4†9O>ùòq53ï9°¿þvÃ0L¼êwz˜ñÓnÁ9‡ªªhiiA(B}}=:;;áóùúŒ™ºI|T6c ­mÇÐÖÖ†cÇŽáСCŽÛùÉι£´ì€ÄcÇŽ¡££ÍÍÍ®§o“,N‚sŽ®®.ttt ©©ÉQ¸v,G´Qàvtt|D @kk+"‘êëëÑÕÕezp8wf˜@PŸòv;AÓ4´··£££GE0„ay1@¢f¸\àšýüPX׿3cÆŒv×—,N²–xÍS«VÝÒÞÑvc¬ª¤¤º®ƒ1=b*ãè^“›ÄhÙ%c ‘H$f Ü&_½6PTs Z‘†€¿È Vtnõ°#‘ˆÙã·z·mmm(--Í«”[Ù‡B!W»Øé6ÑõA×u”––¢££Ã4b5@º®CMÓÌ'ylþ„Ž1ÛÝݲ²2D"‘„ÓãŸÇ ,£©‰ÿΊ/ùW“,Ò†|´{÷…œÄw:;;mß¾“&M¸qãœéQÜ G!'k r‰íiB`ÿþýØ¿?æÍ›‡òòrç|<ù4Ú;ZñÁ`ìØ±˜0a|>Ÿ9†KyÀ‹Ãîí644`çΘ;w.***ò*C}ýõ«s–¨dP ‡†D4^pq¯¢â Ðpä¶nÝŠQ£FaÊ”)Ð|>k±™ÞñT£”ûÂzzz°wï^Lš4 •••ÖÊwîOÓJEKk3¶mÛ†Q£FaÆŒÎø7×­àE·åcÌ >Ô4'ÀÎ0 躎±cÇbüøñ@»wïFee%¦M›fºþ­úä:QÁ†Ññ---hnnƸqãPQQѼ äÕ°ë‹àزe *++Q[[Û»VB¾±‚%…hmm]tøðá¿·µ´ýªldÙ0Æå_ ‰È¥€‡ ÄùWAØ¥0ö»Á±]’¶ËH0žk.9€>Ó¤ìó1Ÿ<£ªªÀe7œ¦Xy’ŎňZÁ–©°óÆ0 G¦èúä6"¾Mäñ±,v™Å,Éë6Vغ®;Ó%åó]¯£ÊEUU躟Oû»ˆè«ùFâÒ0Ä!–€Ñw‰h±¹x]ï¸,c¬w¹¥Øìn¸œ¤äAÑØC†®;ãݶ2aæÖÃ$–#[ùÒ)r³q4%a/uK{}ù¼äQå 1Áon¦$´ËÊŽÛ°N:ÞŠ|,dËGÖR[Žøub—{f1+ó¹E´7ÍŽ%‰1D\ª×12Ä•a|žøýfà¯à¼XQÕ‡"¡ÐU¾@à.ÆØúœ !)8¤0D!"?„ø>@·™à4ȶ+Ùî!Y?ˆê)Å6N®GI[ëØ«¦ÒuÜ£)Â|DqÛãÆöz¶¬yFfM?Ô|>‡ÃÖá<,””MÓÌùÿq²†Ÿßï~@[Ô"DÎMÀ ˜ú®`/¿L°+XegÇo¨ªjzr¬ãÉêw®äJgHØ3#ì8EUÁ˜²„çÿ Eùc,’a$…‚AË!èC€ÝX‹éÄ-XÃâzF°¼ˆê™äkùh™4Më3$‘ò7yP~vÐXto2ßy“¨ì¢gO¸JœÛ<æï¨zâô¦­Þ¾¦šÆõ]b7ªwÝó^Ü*2:rY³7bdÈÃIÂ}¢ŽÅ¬4iÕ§Þ/ì6ú Z’¼# €!Uç¿£gL³'r7FïD£d‰bÖœÏË:銂H8ìxì1Ò|¥Ÿ;ZÚž>Æ£§þå+ÈÍJËNÛî±BþkŽR³wäËÛn€¬wñ*aº²YÎ5èUvÂ2ò¦]vötÛŒŒÈ<¸öt[ûo;.!ª˜FÏç¿"¢*×’ä i È ÏBÐûû|ü9Ç•Ý÷zµ}\ –AàDœçɽìóù@  ¨> 0€©WQÆ ‚A!€ ‚  Óœ)€©0CNgÚÚ=4‚ƒ© ˆ¡Ï'פRâv‰²ST5‡õ'ƒ|´ËÁªÓŠª‚À!È»´tfK\ç°ü¬w*f]„¸ôcäI÷’ yÌd˜c(ÅÄ$ˆØç!è}2è³î%É7ÒäÑhâüI0zæ– ‰DâÕ`ôqþ$öZIvH`C] AÛvײH$’Ể¶‘A×z-‰dàH`BDEÄùÿÑoŒñZ‰D2,F¿!ÎÿˆŠ¼FÒ¤0È .† -[áµ,‰D°´…tºØkI$ýCƒâü>(ô73¼–E"‘H¢˜…þFœßçµ ’Ì‘À €ˆf“¯ì.¯e‘H$’ä°»HˆWˆh¶×’HÒ# €‡ ú"½ÂR¯e‘H$’´–BÐ;dнE’i0Äùc`ô8€€×²H$I?€ÑãÄùc^ "IŽ4 ":™ ±`_öZ‰D"8ìËdˆDt²×’Hú" €ƒ º‚6‚aײH$IÖ0,€ dÐ^‹"‰EqþC0ú9d¹H$’¡…F?'Îèµ ’^¤¢)ˆhªå«×²H$‰{°[­YS½–D" Ï!ƒ.ƒ 7e”¿D"˜³Þ$ƒ.óZ”áŽ4<„8­£?Cnâ#‘H†Õ`ôgâ´ÒkA†3Òð"þS€ðZ‰D"ñz€8ÿ©×R W¤g~ûøããöíÝ·¤Ü.ÑÞînìï^pØ{ €A#dó ˆ1PÜ>í©÷»·"[ˆœ]é‰díyoÿï6‰Ò¢Œž?W 0I1?°?q§Ó¾_9*¿ ‰ÉË–k&í‰S§ƒ™×),Oí»‰„XGDãò‘š¤i䑺ººÅºªmè\¯e‘H$’‚p.q±ˆ{-ÊpBy‚ ã3Œð*ý*‘ÃÆÓVøLáÕ]»v}ÆkA† ÒÈÄéöo𙼏i%ù ?.w‰Ä3#<õóŸýì^ 2€Ë˜ _Ðý^Ë‘ ©PÑ#Â,IlD²ãÉàƒÝ_÷q\4Èe¤àD¤Ïäâ>y“ä–CMm’an%AÏ‘ÔS.!3Öˆ¨œ^a¹×²èUøD}”>¢È%Y’DáÛ³&dÏ?7 »Ù7ƒƒåàô Õx-ÈPD9†ˆæ@ÐË`Xâµ,ÑØÓÇììo‰D")d–@ÐËD4ÇkQ†ÒÈ!D´‚Ö˜wLQ ëz¯ÆÌ¿­ù·,É'r) cB€) À ÃçDÁyLO“¬ëòa$82Y€®ëŽì®cå¿ó‰†Š•Ñùh—›-¯›pÃ0åŠË !D^c8’ÕK¦(àœC±òŒ™õ'_²Yåa†#§ý-„#€¸pÊÐ.3EIÝüåÌ`תªöÖÆ‰Dr@&"$nK„N>Ä¿{,Oõ8çÎß”¸s2 ‚ÖQAu¬;š× È O@Ðs|ñçl妪ªù?cà†!|~ú›gÙ2KyØ/»Ý8ûý~”””@UU(ª X¨ªø™Y"¥Ø_Ò(qEQ`XŽªª`ŒAÓ´Þô{$;9ˆÁ`š¦ÁÐuhšfæ‘™o.£j¸a@Õ4œCUUGé¥ÄåòœCÓ4G¹Úy”ÏòbŠÍJOEU¡ª*ü~?Eªi3ëWôBJ@Žaå•e8ºn•„€?H““µ|‰"FÍ6Á6f}>ŸóÎpdÍÇZHª•6ˆœ6"á0ü½md5­%ƒ–3½è¾TCiä"ãz@¬J~ÙûPT€ÀAàP} <ý žõûoöøUíí™Y/~{{{¯q¯b?˜Õ+βF~Á94¿©H0xn¥KQù“§!‹x'èèjG(Ò¦šÿ3Æ H€!7^št(šYLTUÁ#…»¡ù@I—/Yæ[šÇSCèÐyªO±Ê’@$ ëztî Âò>LE«( €:º{:Á…!t(ª Á¹¥ô`y¸KãíOñ&¸Ö|çÌ|ñùUèF¦ (éÈ®üXÔ=³˜B` p¡#îvÞ9»÷mÚ¸ÜõúMQ@0L@7ÂdÀô!îù}½@d|–1íIWH K::Zoîèè|4Õ5 ¦[«§§@===èho‡ªªŽëpO½ ôð‰È´ê5UU‰DPTTèêìc Š¢@pÓú·Ý†”¥®ùàœ#@×u„B!ƒAtvv¢¸¸ØôD¹5Fn7Pa«"„@OOOŒÜ0 ×ÓB@Ó4GyEˇÑÕÙ™ðw¹ªOé†acN¹uww£££Ãù¦iY»¹Óå®Ý‹B8.vEQ`"‘º»»¡œè!œLž/S’ÝGUg¸¦§§Á`ЬKÝ݇ÃNÏ;þ™œûæ@®è圕¨¿m¹‚Á :::ÌvAסZ!DÖù“ÉÛíö7 ¥¥¥…BèêìL–þªŽŽÖÒ#F>–•pÃëš¿ÿýs·x0ÝuŠ¥X»»»qìØ1TUU9/Xô8›[#ÅQVªªBó™ñªªâðáÃ1bÊËË …àóù ,}k7Þ,K/·’FAÚ 6ç†a ­­ ΉˆkÜV¸ñîa!š››QZZ ¿ßï¸p£Ï» Yq¶±(¬¸–¦fTVVÂç3G„½MA‚ß»‰]¯šššPRR‚ÒÒR§A×4-³aŠdjØŠÎV GE8Fyy9ŠŠŠ¢z¶VŸé¾MëbN“~šódåaŽRTTä(¶D©Çô²l ã7¶‰7Âá°ÓX—””@ŸÞ¦›pÎá÷û‰D¬1YÓ›¤(ŠS—€ä€Û‘#[qq1FŽã-±å(™xll… áóù‰Dœ<²ËJQÓˆzsLL´›ÏçC8FSS|>@B$^ž\”g´À¢þ¦±c‚‚Á ½u.åg+¿ßï KÚòÇ”o\½ú¥à…^üݬ„¦H`ño¸§÷ÿô.RÁ98€×_3gÎÄ´iÓz_\†xo ¢àÜOp¬¹ííí8á„0{öìÞq8Áœˆwóò ¬G"øðÃÑÝÝ“O>555y $‹.¿DÊ ±±k×®Emm-N<ñĤ׹)c¬7ÒÀ¶mÛÐÑÚ†¹sçbâ”)–ð Æ>úè#tuuaÖ¬Y¨­­u±ÛÆQ2HlÞ¼{÷îÅ’%KPVVÖ[föŒ ·?ìäzgp:t‡6óiƌԀ.Éc< 7¢®®‹-BeU•3,`{·òQ†v+ˆ°gÏttt`öìÙ˜:ujúw±ûˆ¸Ÿ1õÛ® :Ä@?á\¿—ˆîîïïl ·³³@ªQîë3i áo³)* «÷¯( ¸¡CÕ40ÆÐÑÑP(ä({=ÏtŒ%ÊÝ=àô3¸Æž ÑÕÕ…ââb§¡v»GÝ;Jô¬Á`ÐôžX½5»A´Ç½Ýv±3Æœ!UUÒ#P|š¥Ìàt½XÝÁŽGƒ}ι]lcÕp6^Ãá0Âá°u#sz"E+8Î{ ÝÊ—NAÙSF-Î.Ë´Xù–+€S¶ñ5l …@––Ñõ÷?*ÿlƒ£»»EEEÎl›”˜çï!®kLõýGVÂ3¤Ðˆóïì›ý#…t̹÷B@Ó ž~¾4˶kÇh¤FIú|>Ç­LDðùý†©ømEÇÜ^‰“1ó7>-€HØ0g/X.KW±—eH”c0t>M ŒÇ£ô"å“|šâ3£Õ AÕ43ªÝRþ±{ä»×mæ‹Ê4p]@S|1kþ=ÒGÙg:@œÀ˜5eȬ;@ìtRÁR XÞ *X¶“ý£2?Y] APô‡ªøÀ 2åaé\NjÅÉf/ J T(L Æ4ð©þ˜k]…UñdNßäœÃçóõÆd^Ÿï&Φªw¹%êPC.”!ŽòFÈ•M˜ ' ¢±3ç*çD—祔¢žäf¨$»|ì#CÆkä®üä¦[ù‚}Ól«%™ € ÎïÍ•ò÷¤!È` WÒO À8*4-]0›§$ˆ®÷ja)‰Û°ošm¶$ÒHqþm€õ{Ì?Õ0Ú°$ Ú˜’‘Äõþ  |’ÅN…øÞ †|”°»Í¶[’ i¤€8ݰ{Ò_9H°{=…ØJ†…n¤ 5Ø=f.I†4’@œn2œçŸ!¹ÚÜG’_âwQôZ–¼·æBŒ ƒ½>ç#?{ jè>³-—$B N7”v…¿~‘h R" ƒÁí^(ò‘óMÞ‡LJò=h¶é’x¤t=@)×öÏ–A¡ü ¤ñ–¤¦P”¬DRØÐ£fÛ.‰FQAŸ£ä»úesï¨EJœHâVå*(<’«{¶ ‡nr¼‘LÊboÞä6”b¯ƒTçòI¢÷(ºlìÕíÌ‹(,²gXG¼Zq ŠÛ8(ŸD/ÉíJÚŒV‘AŸÈý/Ò° ¢%`ôœ×rH$‰Ä%=GDK¼£P"šAÏH¿.¯D" `•%IŽñAгD4ÇkA aoQ = ÚkY$‰Dâ:Õô Õx-ˆ× k€ˆpzÀ,¯e‘H$IÞ˜NOå}㌂bX?<ˆžƒ’H$’áÃ=íµ^2l âü‡ ,÷Z‰Dâ>‰6ü#–ø¸dAXNœÿÐk1¼b•Í27 IDATXÄé»Õk9$‰Dâ5ìVS' ?†@} û½–C"‘ä ,ÁP/#ó“”´H†t?}Æk)òͰ2ˆh1=鵉D"),ˆèI"ZìµùdØD4‚VÁ\L"‘H$’h­"¢q^ ’/†Â*S½C"‘H$ËT"w–ƒ/D†…@œ~ à\¯åH$IÁs.çü§^ ‘†¼ðÚ?ÿ¹ 7y-‡D"‘HŒ±›ˆh¥×r¸Í6~»jÕe=൉D"\ÑDt™×r¸É5Z[[§* ¿ðZ‰D"‘ Z~A==C6vlÈ*‰_PíìîåóÖî ÷•÷"J¿ïvÉë%Éò‰)ùy…íÑ.ò´Ÿ}ªg´ÏEïån°.ð®þdô®åA>"2Ó‰/»¸}ïcäÍa{F|=&"']ÆXL~ä«nÛùÀ EQbäò"ª&Ÿ:d;’CÒ Ãø!-¢*¼Ç•ÉV¶inžIû’åIÞèF¨^|±¡—2Ùe§, *¯¼Ä΃¸¼Hö®yýÊ2KBÖgA´týú—‡ärÁCÎ 2nèVóïܼèöšáýxê}ˆ&NŽø‡× £[ ¸ÜâÚ¢BlœòRfV {’^gõxãäQšÂ­C…X¶Dä¹ 6$pëSOÆSžðªqNÔ¤bMäV0Fœ‡$S`ÑùSåéµÁÖŸ´ó)gŠò+¯@¼¡Äû2‘/z-W.м [ˆh6?It®·R s,—@!ó› 3Ò‹ öÿ‰¿Y’ã'“«?Þ‰¦ß›QÉò/Mº¶ŒY¦Ÿîñ¢\Lcƒ†ˆ¥•߬,º ÷¼pŠ)ÉPNZYÎòÏ” „ !D¹õæ\,¿tS¶X®ž?úbÚ›‚~Ö±läÏÅT[7ÓwÄHáÈÇûÞwÉ6Þ„PTK†lÛá4ßN;ëý·¾c¼$Œ™5GQ~BDo2Æ>Èø! Ao47ý1@Ã0Ð|`Œ! ¡½½%EŇÃhnlDtF3F`LMzÞþL@¡ÄßL0& BMpN#ÝÒҿߦ¦&”––‚sUUû¾xq/Ž‘V¾ä߀!ÌJQ!àó« "´´´  "‰ ¾¾EEEBÀÐTU…š¦Ï*}ŽÔ ÝH뺎ŽÎ6øŽ4Ô›/%c`"so2R•_ô7ù hii¡µ£M PUœshš–DÇ¢2ȧùÇ9ü~?"‘cPUímm9¢ 8Öx‚Ùé$Ë÷ÊOUUmj˜@Kk3ššKt À_Õ²J_¤)^[Y¨ªêüÏ9G8†ßïGgG =ì¼kD…MÓÀ9‡’Ñ|÷är¥Ê_SÃ0à÷ûÑ|´>•¡½õZ›Â0 G.ÿRM‡B ÔÝ MîÿcÇŽ…Âi›„5/?›ôû:šEÌŒ1D"³­a mÇZ0rDÚŽµ ¬¤ÔZï"y:™´ß™~ Ë â1rG"¨ªŠÃõõ`Œ ]ÿ1€sfî ¡übgÕ¯y»ËVl Ái|>8ˆÑ£G;-c>Ü¥‰”ê ³³EEE8vìJKK˜J/s` ( ¦Æ44€ˆP\\Œööv0ÆPQQH$]×Ràóù‰D „€_³_!XúÖ.7"Bss3ÆŒÃ0L£E7Rþ6½0pÙª†¶¶6”••9ù¨i"‘HFÊC¡ìÒ×4?Âá04Í´×m%ÖÒÒ‚Q£FeP¯³K?]ùqÎQ\\Œ#GŽ ¢¢‡QTT Cw5ýèò×uD„ÒÒRttt # ¢¨¨¨w×àà(¸ $ÈF|™F›m8Úåfºž:Ë®Ý"êu±Û ìØuÈVöB””” §§~¿?JñÃR†EA:ÀÎ!„cè¶´´`üøñ…B}®Ï5ñ‹ «+S¡ë:zzz0nÜ8444 ¤¤š¦!÷†n¼ÛU]dÐzÞß²åbÁè.Žo÷€TUE(BwgF…ÉS§8¿ódÌTU‰DÐÓÓƒH$‚éÓ§£¬¬ Œ1gÕ«Y ˜=Gͬì===ضmjjj0~üx–·¦Å97‹¬€Ì{pD„ÖÖV¦NŠ`0höÚÒx²M?šD±===غu+FqãÌ­Âíüôù|i•H²žyd²= º®CÓ4´¶¶" aêÔ©(++Ë.4¤Ë?]×Í÷­»“&MBEE…£@8çÐ20³IßÎÿèž´ªª¨««ÃÑ£G1cÆ ”””ˆ­k¶Á©ºÜâÖ¢(èêêBχbÂäI(//ހͶþÄ+¸xàÀhkkÃqÇŸÏç´Gªª"‰Àçóe•¾ˆ7â†Eu]‡ßï`zeêëëÑaì„ñ¦¢Í²þ¤•/IöGçÃîÝ»ÑÜÜŒY³f¡¶¶Öñ¦ !îzË–WO8ñÄ—\Ò%¥@DE ㇎önuÌê%554à£={1jÔ(Ìš3§w,JÙ¶´´ §'”ÒÒçÝK4ޙ躄 UÓpèà!´··£¸¸U£G;n¶>ct}ÆÎ²0  (fãÈ Ã4¬ «« ~åååЬ8@ÖC)ŠjȆ ÚW{(½³³ííðù|½y”mÖ±.‹¾.®Œ{zBPU ••½åÀ°rê25ŽàСú¸ß3L«bþ-PZÛÚÐÚÖ†¢âbŒ´zÝ®‘6Äáàƒ…BÐ4 £**@¾C¿ž é n¾#ŠbÕma¾§1bFŒÑk 0æT8ä¾”\ØÃj¦‡kzm-*«ªÌ÷1Ý@¶ùG蛇váHCŽ=ŠSN9Å#FÀ‡¡YÊÜá¥6lyì÷*ÐÜl¹Ü5TmÖy7‰Šñ©®®îSœs=z]]]˜2e Á ` 3©šø!ÈëqWÐÜ3(‡¸Áÿ+ìŠÄ ‚®ëðùý-MMX»z ¦L™‚SÏXìTd"Â_þúW<þ‹_ ¡¡!e:EEÅŽR´ ‡Cˆ„Ãî<˜dØ£(*üþ’>ÇC¡v¤‘H†>Ÿ\p>n¾ùfg8Kpo¼ñ:„«¯¾Úéý€ªi !@`?WUíK^Ê>Üõ­¸]«(Ê ¦(°?†®ŒÅ¸ª4M!¬GÌVç£?ý)¾û½ï¥Uþ‰D"^躎¿þõo¸å–[pìØ1shÙRøº®CÕ40EªifïfTQØ "ºÖcñûÍ 2ˆh4qñ09S L÷vt/]p2 sœK5ƒÙìë׬Y‹'Ÿ|ÒÃ'H$I¡³ÿÜsÏ·!„pf¨ª Á9¸Ñ”¬G"æ)ˆ‹‡‰h´‡b÷›Ae@ˆ‡ccú¬`ee™sFU0kz–¨Å¡p?øá<~‰D"‘ Þ}÷]¼ôÒß €bd øüþh]4B<ì±ØýbÐdÐgv€ÞÝÚl˜ °¨ùôÖœwf–À_þúW;v,ßbK$‰dòÄOÀ°züš¦ÁÞ·€1fNè3…€]gêªÁÁ 0ˆ¨ ŒÈæ/¾øb®Ä‘H$É0`ÿþýؾ}{ÿ~Äè"ªrG¢Ü2( ñ€ê´×‘’pùɆ†FìÝ»×Á$‰D2”yýõ7c$Ñ3QT[:«à)x€ Z°ÏgswÞÙ,7M‘H$I¿Ùüλøû¼©» ›‚6ˆÈFß7—+ˆþ¤C±VŸ2?íûÈM1%‰D2DùøãA‚eÒó·°ôÃ÷‰Èï¶|ÙPЄø>€iÙÞfÿþ9F"‘H$Þž´µ h!®iø~®åÉ%kÑ€Ýs,>ú?CÚÛå*j‰D"=¡îþô6S—&k€Ówsu«îîžD"‘H†9áPË¿çP—åš‚Ü ˆ8} ÅQGñ»b:Þaí$Ä9üBµ…®pæqæÎ D"‘œÝÏMªª*ÑÕÕžžÞ=*ŠŠŠpë-·`óæMX÷ò+ÎñÒÒR|åÖ[°~ý«ØðÚk}î5¶¦§v:ˆ›6'L¯fL5N;mŽ9‚·Þ~;æœyÿ[±þÕõذ¡÷þåeeøÊWnÅßÿ¾ooÜØ¯çóù|X|Æ(//ÇßW¯¶¶틦i¨=õ‡'<¯( ÆŽ‹C‡õ+}7PU þ‚5”H††Ð­MÔKß$ˆST ‹‰ÓW™Ê n‘ ‚3ˆh<Ý›«ûõg+ØLèîîAÓÑÆÜÞ4Lœ07}éKxuì^³óO: =öö×Õá3×_ïì9þí{îÁù狳Î\Œ¿½ôÚÚÚ+oÿ*–ž}6N]°_ýwÇkÂÊoÄM_ú’³¿Âÿ»í6¼ºaƒ“6c 7ÜpþõË_vvÆ»ýŽ;ðÊ+½Æ×îX‰¥g/Á‚SNÆK/½ä%ÿùwã¬3ÏÄœ9spáEel¬Í™3ÿsÿý;v,`ö¬™¸ýŽ; ( ®ûÌg0aÂüè‘GÐÕÕ…Gücœzê©øÆwbíºu¸äâ‹qÆé§ãÇ>Š#GŽà›wÞ‰k®¾?zäü◿̲$²Ãç󣤤ùܧ«´´S¦LÁ˜1cPYY@ Mó!êAOOŽ=ŠÃ‡ ®®.f[i‰D’)t/=Ãó¾—EÁâ^€{-Æ`¢¸¸>ú(ƇK.¹[·mÃWo» ~Ÿµµµ8géR¬^³‹-Â'–-ÔNŸŽÍ#sÎ9]x! ¤¤“'OƇ~¿Ï‡oûÛ¸äâ‹´c¸âŠ+Àçóážo} —]ziŒLW,[æçœs.8ÿ|¦²™ïyçž‹ûî½{ËRK–,ÁÈ‘#ñ‰eËðÕÛÌÐ!ÞzûmœvÚi€¿øEœã»÷ݨ¨¬ÄC?ŒåW]øâ 7à×O<1,”c Ç,X€‰'¦Ý“"‘vìØ‰·ß~…gK$L±©Ûpƒ×‚DSPét!@_ðZŽÁÆ—V¬Àøq㪪âk+WbîܹÎùiÓ¦¡²²߹瞘†¾¸¸555ø»ï޹_qq1ü~?zðA,>ãŒ>é³zÝ~Ÿ<ð€£Ä£kÉ3vìØ>÷/))Á¤I“ð¯½Oºé¸üòËñ{î¢ÄºßTUÅìY³ð¯7ßì[zöÙ˜•S§NÅQiž¶p!ný÷wîURR‚Ñ£GãÈ‘#iåÌL˜0_|ª«Ó¯­ßïǼys1wî|øá‡X»v:;;]’R"j°/N¿e>¶ÚkIl Ê£ïx-Â`£¦¦Ÿ¹6vÊsÏ=7æUQðàôiðÛ;:ððƒ¢bÔ¨˜ãxø¡‡pÆé§'L³µµ~¿>ðÎ\¼8á5ímmƒx(Áý»{zð¿=„#FÄonnNþ –-[†oë[}”¿ÍW\`0èü_SSƒššçÍçØ1cœÿUUÅÙgŸsLzƒÆ–.=‹-Êê9c˜={6¦OŸŽ_|»wïÉ¡”ÉÆÔqcÌ,ât y-Ç`ãK+VÀŸ&jì̳Ήóæõ9~ÓŠ˜9sfÌ1"Â×V®Lªü`ç®]øÁÃ'Uþðþûïãþï~3?¾ÏýoûÊW0uêÔ˜ã†a¤4–_uUJåìØ1œgøÄ“Nå†1d{´š¦áê«—ãôÓOÏ™‘°|ùrœ~º|m%’Œ`XDœnñZ ›‚0ˆ¨  {¼–c°1aüxgL?ñJØæŒî}Æ,Xò~Ÿýìg±hQêFÿ³×_ß§wmßáÂ…}Žkš†çžy%%%}Î}êÊ+q÷]w%UþP>r$TUM)SªßÛ2¬úõ¯ÓTƒ UUqÕUŸBmmmÎïÍÃ9眃3ÎHn0J$’hèSçyOa qÀÅîIýÁ¯j(/*J«˜2¡'A[Oìz—_~¹uïœstwwǸëÕ8E*„@gg'ÊÊzë´2€gž2e .¹øb<÷üó1Ç¿|ÓM}®mmmÅÈ‘#“Ê4P&OžŒ…§ž3²ÈïGyÑÀãR»#at„BžíGqÉ%cúô鮦±téR´µµãý÷ßw5‰dPeê<¬ôZÏ "šA·{-G.)/*ÆÉ“¦`ÜÈQé/Î÷ëâ½±ò&LÈÙýÁ9Çwþû¿ñµ•Éë) {ï½_ùÊWr’fü3>± ^{ õõõ¸æê«s’f<ã¬F›ª’XrÜÌ$WgFX×ñþáƒØqäp^ ùóçc^‚á7¸ôÒKÐØØˆ£Gæ%=‰dðÂn'¢_2Æú¹×pnñ~@ˆÿôZ„\2¦¬0/§ÊH<~ÝÚÚÚ¯{D¬µâÑ'"üç·¾…­[·ö Ö‹¾æ™ÿ{ooÜÓ»(éýÍù‡Ã1K9¿ºaV®\‰™Ç—8½p´©)æEÉ~Ì<àóáäISqfíñPòhX^^ŽóÏ?/ãë;::°wï^lÛ¶ Û¶mÃÞ½{ÑÑÑ‘ñï}>.¿ü²!H)‘äŒÐ}žzH§ ºÆKrIi ˆ¥ÇÏ‚¦¨hîêÄŽÃõè ‡ rÐã 'P¢kÖ¬Ág®½6£÷ü#fÏžã£'øñ#àŠ+®Àĉc®øÁ‡ð·—^ÂìÙ³“Þóx¿ÿÃ0nÒÄ„ç Àƒ>ˆùô§11®gÿÿünZ±•••Î±ŽŽ¬Y»¶Ï}ž{þy|ñ†ð—¿þßù¯ÿ‚®ë(Ê`Êà@hkkÛoÆîÿÝÐÞ†¿mß2à{úTãFŽÂqcÆbRE%B“§aãÇ{³5-]t!|>_Êk8çØºu+6o~'éÜþ1cÆ`þüù8ñÄyi‡³ÆŽ‹SN9›’¬)‘HlØ5¤ÓÏ™­ñJo‡Tº+~ÕÄÁÌéÓj¡)*v6Ææº}®»z·lÝŠ]»wÇ(õDlÛº÷Þw~ñøãα–ÖV|ïþû±fÍ\xÑEÎñcÇŽážï|¬…~8€ˆ®Ã¥H6oÞŒG~ò¼÷Þ{€ƒ‡!‰ÄϽûî»xô§?ÅÆqÅ'?éonnÆÝ{/Ö¯_Ï}ö³ÎñÇã«·ßžpþò¼ø§?Å,´gï^̘1Ãù¿³³¥¥¥)ó!x衘¥“ ¤ë%ñždJC{ö55âÜ™'à¸158ØÒŒÃmýóàô‡‰'¤ úkllÄ‹/þ)í¢> x饗°qãF,[vyŸ!’x/^Œ­[·"É.Ï$’!JwðÌðl€ º„¥^¥ŸkÆ•DuY9¶4cÓÇåmœWO°/ACCƒówýáømåJ!°nÝ:À¡úz|þ _Àš5f½³×ÕÕáúÏ}ÎQþ€Ù+òÉ'»vïÆ×¾þu¬¸é&GùæfKO¬Zؽg¾qçøâŠØh­íoßÿã?ÆõŸûÖ¯_s|×îÝøÜ¾€»v%|F!DŸŸXµ èììį~ýk|ïû}w݌·D455Ŭú÷Ì3ÏàÏþsÊßdCkw7þ±ó"œ8a’kéæÊˆ©8xð žxbU¿VôknnÆ“O>…;v¦¼®¤¤óçÏÏø¾ɰ…°” º6ý…îà€Ñž¥í³ÇM€Á9ÞÚç¾k7šwÞ}sæÌqþê7¿Áï~÷;üÛ¿ýºººð“GEKK àɧžÂƒñÞ{ïÅÄ<þ‹_`÷ž=Ø´iSÂ1ß=ò~õë_§þñO~‚'V­JxÍÏ»vïÆÆcæÙÿè‘G°eëV¼ùæ›ýÞ±qÇŽ¸è’K‰D`ªªª ëºãò>vìn¸ñFœÞy8yþ|üí¥—ðõ¯}Ír…BøêÊ•˜8a.¾øb¼þúëxæÙgû%Ã@8ÖÕ…Gê1{ìxŒ)+GC{[ÎÓ¨ªªÂäÉ““žoooÇóÏÿ~@›Z†^xÀÕ}Örˆæä“OÆÛooôlæƒD2h0uáo½HÚ€8Ý P~B“ó@‘ßêeØq¤>kWqyò©§pÞyç¡fÌüæ·¿ÅÿþàBஸåw3ðîÿøGŸãœó˜{‘I0X²k’Ýß0 ¼üòËih£¡©© ¿üÕ¯pÓ—¾„ºº:¬üÚ×pøða¬zòI¬²<þ@ßþÖ·ÐÖÖ†o|󛨾};¶oߎ¿½ôÒ€eÔÂñcÆbre•+ÀÉ'ŸœôáùçŸGWW×€ïÏ9Ç /¼ˆ+nL:ì2jÔ(L™2ûö}<àt$’aÂ<ât3SÙcùNØ#}=ý5¹AÉCdÂÈ 0ư׃]=Š«–/‡ßïïWÄöPäÑÇÃïž~ííí 7ôùóŸÿŒ×6l@gWW™ ù"lè8Ôz GUbcއ‹c˜93ñÂO°mÛ6>œý^ÝÝÝX¿~=.Û*šY³fI@"Éú:€¼y N·Hî;ÌÆ@æ^ÍDUU!„p#©ªFŒ@G¨§ÏB=ù"{åoÓÒÒ’r7¿–ÖVO•¿ÍcÍú|(ÚÑ0L˜0!i¯œsŽW_ÝðÜ@زe+šš’/ß|ÜqÇÉ)’!¢(Ð4 œs0E1§03f~rÃTK7敼zˆHáŽ\íunç½àŠª:=)†Þyæùh€*ŠKÑ4D×—¸ƒ]_Ê‹ŠÑ å쾩VüÛ¹sÚÚr7ä@Dذa>ùÉ+ž/..FuuuÚ`Ìhü~?¦M›Š‰'¢ªª ¥¥¥ðù|ˆD"…B…Âhi9†C‡áàÁCíÝà÷ûû,J犢`Ú´i8®®Fqq1ººº­õö`ÇŽ‡Ã)Ó*//GmítLœ8 ee#PRRÃ0ÐÒÒŠàý÷ßÏé~Á`Ó¦MÃäÉ“PUU…ââb¨ªŠP(„¶¶6>|»wïÉùâLååå˜>}:ÆŽ­Aee%Š‹‹ÁC(F(Ôƒžž466âàÁC¨¯¯O¸æGÓ›9s&&Nœ€‘#GÂï÷#‰ ½½‡Á®]»úUÏú‹œsGÇ8+°ZÎqý€1–·ýÈó; p@csu;Ûqj/;ˬž?¬Þ?c,fÏx· b_“Ü]’9á ÁQ^TŒƒ-Çrvßøõ¢Ù¹3uôþ@ؽ{wŸ) ñòdÒ09§Ÿ¾óæ¥_kÀ†ˆ°wï^lÚ´}ôQÒ뮹æjLš;ëâ©§~ãÌ, ƒX¸p!N>y~Ÿ-©í®fÎ<çŸ>V¯^ƒmÛ¶Å\ÃÃŒµ8í´E˜81ñꜣGÆqÇÍÀÙg/Á«¯nÀ›o¾™ÕÐOqq/>'tbÒµjjjpüñÇcéÒ¥8pà þùÏbÿþýN0·?ãŒÓûäg"ì5DÂá0¶mÛ†·ßÞØïÅËÊÊʰtéRœpÂ섹êêjÔÖÖ⬳Îıvíšœ qÅCÂRüV^G"(L3 Ü á±;ôÒäy3ˆÈçÖ’¿Üêé+*ÀÆ ÃP¤sPƒª(èÑÝMG2ôè‰DàÏÁ>6ªªbܸÄöµ®ëØ»7÷Ûö꺎={ö$]0*ÝšpÊ)§àüóÏë÷žŒ1ÔÖÖ¢¶¶ûö}Œçž{.ãáSO=GŽÁÂ… qê© b¶‘NF À²e—£ªª¯¼òÀÔ©SpÁ¢ªª2ÕO4MÃ9ç,Eii©3 ·¿Ì˜1—_~ŠŠŠ2þÍĉpýõ×á½÷ÞÃêÕkúÝ#¸ì²Kûìšéo,X€ùóçcýúWñÆodô»ãŽ›eË–e܉›8q>ÿùÏcíÚµ9_ˆÊôö3pÀ¢(ð)¦÷9Gû˜ÐíDôc,/ã”yôˆÛ¡ :ýu  Äl„ªe…qÓãD„@ ãÂé‹O5³PO1î,‘$"Â9|9ÜÌ©¢¢"©­¯¯wmaž;w&5FN¾Çc —\r N:éĬe?~\¿”ÚŒµ¸å–‡ðôÓOGOOÆŽ‹Y³fõû÷pê© °oß>ìÙã_ À IDATÓ?£láÂ…8ï¼s<´yÒI'¡²² Ï<óLÚá ›ÒÒR\ýu¨¨¨Pš6ªªfl(Í›7—]Öÿe¥EÁ…^Æg’œÀü~¿©k`u:¡f¶éëWZ5@·#O^€¼D¤€ømYÜ ñaë›Y1ÌVödúhÊ ÕhæÍ›×¯½’1qâ,_~~÷»§Ó¦ÍÃòåWe­üm:”öšiÓ¦áÒK/Í*~ëüóÏCCCCÖC6‚ 躎î®.—”@Õ4p]ÀÐõ vdí·n¸ˆþ?Æúg9 „¼Ï>ûôm ªð ’xȪš¢"‰€)!‚>3èÇ>iwa®u6Ì7g,^Š‘£róRI¼‡sŽ];?À+/ÿÕ·TtVüë/mmm‡Ã ª¦iV0]ìºee#pÖYgåL†ƒÓ+–B£¬l¦OŸŽ]IVÀŒ¦ºº—\rqÎÒžø‡Nšîé§/ÊYzº®§5D—,9«O æ@©®®ÆÌ™3ñá‡f}/ŸæƒßïGII Š‹‹ADÐTfÓÌÖ‘ÿ †‚ …n£äë’fBc 3 ƒ Bgg'þò—¿`̘19«P¹ ¥¥Û¶¾ƒy'žâµ(’Ã9ÇkR¯¨è&¥¥%IÏõôänªa"ÚÚÚ’‰Þ¿tÁd†a`ÇŽ¨¯¯GkkTUEqq1FŒ(Åĉ1~üxÇ€ "Ô×çÆèîîFgg'üþFŽ,ï÷ïÍá .tww# ¢¬¬,åõS¦LI:Dbs '`̘1)ï …°uë69rºn ¢¢sçÎAUUêŒsÏ=O=õ›„çkjjP^ž:ÚÛÛñÁ¢©© ]]‹P\\„‘#GaêÔ)Î`Æ¡¤zÎŠŠ œxbò!¡P(„íÛ·cß¾ÑÝÝ…¢¢b̘Q‹O<1©ÇàŒ3Nω0jÔ(ƒA,^¼Š¢X³Í”Ì:r3&G"¡›ýþ «‹¹nh>ß-@–Ci fÕ)3+™®GûSh½í¾²ÇÏœ“—)Š’ü±yÓ›8ÖÜäYú@òHöH$³€¯’êþñÓÔJKKS*–#GŽàùçŸrÍ‚@ €“N: §¶ápÝÝ=I¯MGOOÞyçlÛ¶ÇŽõNɬ©©Á•W~£FJ{ÖÖV¼õÖÛØ¹sgÌ<ÿÉ“'ãÊ+?™´0jÔ¨˜tã9õÔ)ÓÞ·oþð‡?öYÛàÍ7ßÄ)§œ‚ .8?i8yòdTWW'ì™O˜0>eº›6mÂË/¿’2ö¥²²‹-ÂܹsÒÓœyæ™I½ xöÙçÐÞÞs|Ïž=øàƒðéO:áoÇŒƒQ£F9û¡ EQ ª*4MsÒ!ÁÒojÀ-pyu@W 2èZ0œõº?if@X‹1°¾ {’îî.¼þÚ?pι¥¿X2(èîîÂëöþ@Ó’»ˆÃaw§©†BÉ €xW*…‡ñôÓϤݫ ã­·ÞÂ{g©S§ôCÒXÞ~ûmlØðZÂ…Ž9‚ßýîiÜxã“®s …°~ýz¼óλ ÝÁuuuøýïÿ€ë®ûLR%\S3&©PUU…±c“/RWW‡gžy6a0aÓ¦MÐu—]–|ÉæyóæaíÚµ}Ž™¼œvïÞƒÕ«ÓOclnnÆ_þòlÚ´)eGÌçóáøãokÞÓÓ“PùÛÔÕíÇ«¯¾Š¥K—&<Üq3ðÖ[o§•5Ž¢g±Açi;˜×'×2¦¹¶Q«säüß@•°>öâ?ö7ˆœsùX x lÞø†§½EInYÿµO«r‹TcÄn¿©ž=Þ=›Êóµsç®~mT‡ÓnOœŠdÊߦ¥¥[·nKz~Ë–-Ø´isÊüÝ¿?8ôüˆɇ æÍK¾gZ$ÁŸþôç´‘ü[¶lÁŽ;’žŸ3ç„„u'L^Nï¼óNÊ4ãihhÀ‘#Ég‹üñI4zã7’*›M›6'õDÔÖÖf.hì•…NÓ-½óáôoY Ÿ× "º`gƒšÝ‡±´ KÌ#ªªªûÈÆ9Ç?^Yí‘D’\ÒØpÛ¶öm«FlÙ 7p{¸)UÔ6ç± s*e™J{E*åYV–YœÀîÝÉçû§ŠÝ¨­M¾´ó»ï¾›V1Ú¬_ÿjRWuqqqB/çù+§d1!BlÙ²5íï#‘êêOùƒ÷Ðn¾Y‚õÿÓꧬtŸz¦®ëdýIpÏ@øW¹\'99Ñ…e D^2wÞ|Ì7¿ÏñÝ»>ľv{ ‘$—¬[û×>JMQT|âŠkÈ`…¹\‘j,6HìÂÎÉ\äúôP£·qާ¶vzΣݳ%Uϵ¼‰D"Ió¶¸8yï=šTFOªµü“)˜ÆÆÆŒ{ÿ6»w'ïl$ZB:UæÂ… qÖYgåÄX+++Kª û³€Uª@¿d†TÆÄ××üê–+-šsÜñüÿì½w˜ÜÖyïÿ=À´í»\j)v±Š¤DŠ*ì&)Ñ’¬jË–k,Çr\;q’'É/¹¾¹s¯“8¾q¹²-[’%˲,Y²)‰–H‘ÅÞ;—\¶%·q{™ àüþÀ`v 03ƒÙÅçyæ!À¼ƒÁà}Ï{Þ"Ë_Žü¿PDYc&[¨©©ƒ«ÌeËW'ìëééÂÑ#–¬43§]Þd3:£EÛ·¾›°ÝétbÙŠjjr|ðd@²™REEy^Ïl½8~Mßëõ&}XO:O?ýeÜwßÇ0i’qEhrAOÛléUòô%i®§Dµfå*—.]Në¼Ñ\¾¬ÿ­4ÃÖÖVÝã !Xµj%¾ò•¯`ÅŠº-¨ÓaâDýǾ¾ô£÷“e¢¤JgL—h¢µ˜ÓöåÔGfŽáYŒ± 0|‰É²r å§c˜EéGãp(M;n½}N?Œ¾¾Ø¢,~ð>æÍ_§Ó<õ Œbêä‰ðŒxq­Û¸Žwfaÿ¾Lìn¶jÍ‘F-…\H²î£øýk±…7ü~ví܆;ïúX1DÌ+Õ•nÔTUŒ9`dă}{v&l¯ŸÐ€›nÍÛV¿B0<<¬»o„ü$Bt]¬@@3`ìÀƒXºtiZ.ä &`Æ»°~ý:œ:u{÷îEO92hŒ¨fH©ö5HÖ¡0›ÊŽŒ1 jöŒp8ì 9íŒ1ìß¿6¤ŽAã8³fͬY³àñxpàÀA>|8­Ì˜dËG ܘòý鮡fbì¾à?Ôð%&ã‹FYÊp\ìbÖìy˜>#1-åÈ¡èîNÝ7½”p»]UUæYÏ5Šmï¿«ér\·þx#Ëݦ¢·WßÈʧPYY¡¨§¨‡††°{÷îŒÎÃq-Zˆ§žú"6lضû½TIW‘]ʩ߯íA¡”jÞ«GŽI©…ÛíÆÚµÁÓO ¤^ºN¶|dZñW%ˆáºÕP ¹©éd×s±îÎ{¬~Y–ðþæwŠ$Q~¨­*ùw¬ÐÙÙŽÓ§Ž%lŸ=g>¦MÏ=ç8[z“Ô•¨­­I«¢]646êWŒëîÖ—i×®ÝY-KPJ±té-øüç?Ÿ·Ïd’UvLð™Œ`P¿ ”–Á!IÞ|óšË8©(++ÃÜûîKÞÇ Ùç4 A0O?˜˜'ŠâFh¨ ƒü™‘ãUêê&à¦Å‰½Z._Ä…óÙ51Uá)Õ0`ŒáýÍï$D±s‡5k7I*…ÁÁ¡‚¦n©Ìž­]Á @Òý²,ã7ÞHZh'uuuxòÉ' ð2²¬_à'ÛX§dõôÒHûúúðÒK¿ÎzÙeÑ¢…xàûueNö9-b¡”ªc 3ž}öÙð QãuV­¾S3èoËæwÒînvjªG]ÿÕ•ÙG ›‰Ó§Ž£õjKÂö[o_QЈ-cI»âÍ™c¼ÀqfΜ¡»?UýwI’ðÖ[oá÷¿#iÚ™åI•K)“¬ØN²º ÉÐ{c,é²B__~ùËç°gÏž¤õ&ô˜7on½õVÍ}Å® YJ0ÆdŒæf4ÎÀØç kàt:±|Åš„íý}8|po$2žÊŠQ¥_9 €P(„ÛëŸë¥xƒd%gqýõÆÖ%˜={¶îZõððpÚÁjMMMx晟âwÞIÙ26žÉ“'ãÆ 3Éc¶iwzu ‚Á`ʺ)¢(bÛ¶íx晟bïÞ}7`Z³fu$;&šd}*<r~+{$/Èâçʸ…Ÿ5l¬qÂ’¥·ãرCèéŽ}àíüp+æ/¸)i÷R`¬ÍÉöìþCC‰³Ô¬Õ.òT š›ÏcíÚµºû׬Y­Ûþ5S!X±byYš3*Æ%IŽ=†£G¡¡¡ .À‚ Òªâvûí·áäÉ“iŸ«HÖ`©®®6ie?-xž×­\˜‰‚ÂÖ­[ñÁ`æÌ™X´h!fÎL]ÁQ,^|3vïÞ³=Ð÷tlÚ´)iåq !ŸðOF eˆàêåË€`²c'(å°þÎÄ.]Á`;w¼_‰ŒeÏÁ8sî2Nœ¾€K-Å''††qpbÔzÃÄF,X˜Xæ¹Xôôô$m-;uêÔœºçE3wÙgÎè×ÐOŵk×°eËûøá„7ÞxW®h×yWihhÈ{±£B“lͽ¡A¿HuuuºK%É‚5õ$ çÎÃk¯½Žÿø'ضm{ÒTT@;^$Y±Ÿòò±õÄdÆÄGŒÈ€ò#ÆL›>3fÎJØ~ìè!tv¶A"ãèìêñSÍ8uöbVë†fbÛûJˆ¼&„`ý]÷˜nýùĉäAu÷Þ{oÒótp8X¿þNÝýýýý)•v:H’„3gšðÒK¿NÙùîúëÇÖ$YúÝŒÓ3¾ï’Åjttäö¬ñx<سgžyæ§I=1 é†×®é§?'«†8®a0Dçæ¼À›|µåŠü—ëï¼—/ý0¦zc [Þ{O~橜L(Dgg;†‡‡àõŽ”¼2N…Ëå‚ÓU†ÚÚ:ÔÔÔå<^[ëœm:•°}Þü…˜ŽãPQQã¥òx<ÖœíO›6=¡@‘àÁóçÏO¾á†ôƒ~ÒÀˆ€' c\SS[‡%KïHp1·µ^Á¹³§1gnæN¢©“ÇpúÔq´·]3™™R^^3gcÉÒÛQ_¯_s\ƶh¤ýñ¼€5kóÖ¥3'<N:E‹ê3}ú4<úè#øýïßÈ(§\<ôЃ˜1C6é÷ûqäÈÑ $NŸ––˺€V€Y)ÃCkk+fÎÔn |ûí·§mL:Uw6-IÚÛó6ʲŒ+W®j€v…ÃŽŽM ªªÓ¦MË8Þa<@$éIÿ;—1r_`ødÎcX`åʵšº[·lÊè-Ë2öíùÏüøûxwÓqõÊåq«ü`xxÇŽÄsÏþ¯¾òº»2›éœ8v‰©lw,[…ŠŠ*£Ä4œ]»v¥¬Ç>sæL<õÔ1uêÔ´ÆlllľðyÌš•¸d;}û ﯒lM8YŽ{©rêT¢çIå†nÀìÙÉ¿ @ þ»ë.ýåšóçÏ%Ÿé÷túôÝãïºë΂VÔ,Xκ7§_ cl€E¹ a¡4Y¹j]Âö¡¡AØ¿+­1:Ú[ñÂsÿlß ¯W¿1Ìxåò¥ xá¹g°cûæ´–A‚Á >ÔÆ,¯¨Äm·¯È‡ˆ†Ñßßǧ<®ººO>ù)|úÓO⦛¡¦¦&fÉ©ªª ‹-Ä'?ù>ÿùÏ¡®.ù’ÊÀÀöïOÝÝrΜ9§² ‚€Ûn»Mw²–»¥Êٳ璦Þ{ï½I1)¥¸÷Þ{’£3¢–^δåocc#f̘®»_«3â¹sçtƺº:|âg·RUU™—Ú&bÑKÏ?ŸÓƒ(7³J–Ÿ{Vw±¸iñR=r]q³Ô½»w`ÁÂŨ¨Ð_ã<~ô6¿—ùÉOfä'„d•%°ÿ~\¸p!åqÇ¡¦¦”RÌšufÍR ›ù|> Âï÷ÃçóÁápÀår¡¦¦&­RÒW®$Vh ìÚµ êÏÄív;î¹çn|ä#kÐÝÝPHDuu•î|4~¸SwÒP_¯x{\.n¹e n¹e ÅËãõzáóù!I"Ün7ª««SŒºÄž={“~N—Ë…õë×aýúuÁÈÈ|>l6ìv;*++Þ[[[ žçÇlà3{À׳}ÖÓw&²ä¯ÅX¦¼ÆS¦NǬىý”N<†ö¶Ä€ÏÛ7[Ê?K†‡‡ðÛ—ŸGŸF­[6%<•´¿{M—ö—Œ––+ضm{ÞÏséÒå´ÏS[[«i8NLœ8Ó¦Müyó0}út444¤¥ü{zzt=¥Îàà öìI]ÔétbÊ”)˜9sFZÊ¿½½Gêkê-÷TUU¡±±3gÎÀìÙ³1eÊ”„¥#=Ο×/êÓßßýû÷§P M˜0S§NÅu×]‡ššMÃã8Ô××§5¦éÑÖw:ÛÚ²ÎÂËÞOäDz~¯ERÖÝyOBЋVš];·aßÞÄžôéãõŽàÕW^ÀððPd[KËE47'±Y¸h1-¥[öíÛ‡={ö¤>0K®^½Š×_-eСJª8‚lعslÿvíÚ…¶6ã"õý~?6n|+iz]]±ŠÓï÷ãàÁCIÙ±ãÌۧb¬× @Öº8+€1fˆ!•ˆ,©ªªÆÒ[SÚÛ[qúÔq@ssvïÜ^`ÉÆ&CCƒxóõß@’$Ȳ¬Ù–Ùf³cÕýHj³³mÛv|ðÁ†çSŸ={¯¼ò[ƒégª¨®e£¸téRNUKI’ðúë¯c``À±ÞxãÍ”}&L0ÖØºu[ÊlI’ð»ß½–Uc(=&NÌ<ý·´`(:9s²óHx@þ›8c–­øÜîÄà­¶½‡îkxgãëVq éèhÃÖ-›pôÈtw%V&[¶|µæ÷QJìÚµ¯½öFFrÏQÃdZG0ÖÐÖÖ†×^¿ǃ—^z)ãfIѼúê«)óê9ŽCU•qi®;v|˜t¹!šááa¼øbnŸ3š±îà€$e5!Ï.²cìÿÞŠŠÍfê5wbÓÛoÄlÂï~÷RV-4Á‡£ v»ǃãÆNn-c2dYB0@ àƒÏ7’±R8rx¿f»Ôªªj,½M¿éM)ÑÜ|?ýéϰfÍjÜtÓMçW3ÆpîÜ9lÛ¶=iÏd\¾|“&Mʺ£ Ì÷î݇]»vÙ/-†††ñ ¿Âºuk±dÉ’ŒâQZZZðöÛï¤åE ”âäÉS¸ñÆù§ÆÊ;„÷Þ{çÎ5gü¾çŸkÖ¬ÆÒ¥K³–¡££#oE©LÅÇü&Ó·e¬cNÈì¡Lßg‘9 -Ʊ#ÐÞÞÙF'j½:œÎ2¸Ý•°ÛÇV¥´X(8އ ØQVVÆdxôõõ£§§'í€ÐtÄÖ­[±uëVTWW£¾¾n·v»¡PÁ`###èééÅÐÐиXÒ€—¤àCÈÐ ¹"'òƒc¯Ó»yiœ4sç-Ä™ÓÇ3r÷ÙíNÔÖN“åQ3ŠÊÊZØíNôö^cé?˜Ôº ã¿ß––âåчB!´··Z“~¼ÀCgg§áÑóZx<ÃÁLèïï×,d‘¡‘v`ŒQ€Ü¯œ(¯0<σq©JG)ÄK‘’(Fþöûýc¢AÈÚuÀ§‘ ­âvW¢®îºq¯ü£q8\˜0aRÚk‰„ÜtóRL˜0æˆ,,,R@Ão%IŠÑmŒ±‚é6`Ô;©þ-˲òL#”ÒûÁçÊè*H¸€+,Q䥸œ¼eyTQ…”D1æØ|¼ÄP` „páµZY–QYY™•ËÐl”WT¢2IàhÊÊÊQUUWRÅj … ØPW×JÓ3æÌɼ £……ÅØÄn·Gô‹ßçƒ )Æ@žõ (~„ B)¥# €)_$éþL>SFKím­÷ÆZ$€RQÊív£··—.^„ à8Œ1PJ!ÉÙ¯A)'Kn§PJA)EH €RŠ ÏÉ7Êi Ì ô÷õ¢¿?uĵËåFuõ©z•'#`"º»ÛS®;vS§ë·½µ°°x½^pÅÅ `³Ù”ꔌÂçó¥®TIr‹‡` e9RPf"$IB__£Dé>HwìŒ €w7¿—° ʃ ðù|8sæ Μ9A Ïç|R,<û—™ŽãÀ žçÑÝÝÊÊJŒqÍÊØRYñ¼€êê °â3Rc³9P]]¾¾äÑ×çΞÆðÐ ÊÓô¾XXXŒMz{{A)Á¡à«LÈ IDATC‡ÐÕÕAà°» ŠbjokŽúP’$‚Dô©$I‚!øý~ *‘²I’2 ZJÛh:yr#´1z›ª”úúúpîÜ9̘1‘T*Õ2’YŽyºi.kÊ Š"8øý~H’„ &Àér¡ß€ ZÅ à÷ãôÉãI¡”¢®î:ËíŸ.W9ü~¼^­Ô.Y–pôÈA¬Z³¾€’YXX˜ªª*”——cþüùX´h‘²îÎhz5(r4dF”óÈ <σ”óövu£££3fÌ@YY% „4655­˜;wnZÓ6æÌ›wÞì²­­ gΜÁäÉ“1cæLˆ¡P$€É2H®-ùÒñP:z¡0Ôß‹/FÒŠJ•Ó§#LÇP^^ žO?HÐB¡ºº€’¤ÿ#>qü0V¬ZkTZXŒcÊÜe°Ûí˜={¶Ò œ1È@9.²N¯K®pŽYbPÎEdIÂyBqåÊL›6 µµµ BXËô¤Ù"8ý§#¨§Dþ3Æ·„(Ž>,ãÍ$ê|qC0 {#J7/ôÌéI÷ ‚ å寕ì4ŠÈý~™l„PTU%/Këñ ãê•Ë…È”0YÑ'ª—U’¤‚M Ôåt ¬e”ã Bdù›„ƒ%QcÒGÓ;-cl2“ä¥LUè„å…Ñ8Q#Q’>¯N—š0« ÅûÀ`0¨”r••‹b³Ùr*cYl††ÑÖz%é1©X±ðù¼åØ*k‡Ótž §³ ‡ ~¿W÷˜3§O`ê4+ÐÂb¼Âñ(¥a×X…#óSë·ÜôŸÍf DŽӡxÖ¥gCÄ8•ØÎf[Ê›LIìGz&Œ„ DÉ3Çqà8åbpž"¥’$çùˆ`‡gp¹½Tc#T«L„Hî$¥4*ú¿4ׯ›NŸHzs9e¦,ï«Öå'™«½˜TT$ï~öì)Sz0,,, ƒV®j~´! §ŸF'ɹé?@‰ó"… —1Y–ÁˆÌ`lŠ–°!Ï•^ ‘ï*U%*—¦Ø€ Î%ÝŸJqY¤‡ÍfOêøýhk½‚ÉS¦V° „X1Å¢ä&D¾ À/R–f ±Â  L(D{›¾ÇnwB²jm¡AyyuÒe€K›‹hØíÙwγ°°È Ÿ/§ÃQl12 =rZÁ»€9šÇ0--“v*3cà_)c·;`³éÿÀ/]<_@i,,,,r¢.¬»“’Ú¯(c!âXdD²Èsžàp˜oí¿Ôq»õ[vuuFªKZXXX˜ž4twj€°µ†c‘íí­ºû\.7J5&ÃÌ8eº©=Œ1\ël+°DY’†îNj0Æ80¬1N"‹te×:;t÷»\å”fü@)…ÝîÒÝßÞ¦o”YXXX˜ †5Œ±¤yðÉ="Ö0Wâö8 »«¢¨ÝÀÈf³›.—~,¡xW´éì´zÕ[XX” BX‡ë’¢Íž¼ÚPq,Ò¢»ûšî>‡£¬€’Œ?—nO…®kú^ Ó‘B‡'7Ye¨0iÑ×Û£»Ï þË/„ÝâJÃÃCºž Ó‘B‡'¯À°ÂPa,Ò¢¿¿Os;¥‚PºJ»Ý©Y€1†þ¾>ÔOhÈÛ¹“ úayZX˜‡PÈœULS’B‡ëŒ±™¥mŠ€žÀnwZ- @²òÊ}}=y5DQÄÕ«—ò6¾……Eæô÷÷ aBm±ÅÈ;cl!D³; þ€ŒåyÉ")CCšÛ­Ùa°Ù캆ÖРöwcaaaaJ’èr}€°eyÆ")¢("hî³ÛK©ei£WfÙë)°$9D—ë ·çE‹¤x½Ý}°zëš›*—«Ø"•ê2wòý®Ò^½ÍžRT8­n©ºhèöD€aa*ƒPš¢Jc ”B–å¤Õ‡‘D¯€$ŠÊ9£¬?Y–“ºËJ‰RRFz²–ÒgJOÞñÀxtmG“ê–ï÷,É“§T–8Žƒ(ŠŠ^# $o:.æÜLVôªËÂçŽÑm„$|÷ zRC·Çüšc“Lˆ?ˆ1yÅíƒ$Iƒe‚ DîR4ï©’-#!Žç»(F[âv¿ß—‹3Me Ð4$•6ÉÖú¿EæÜ°èF<ôåÏ#è ÀQ¦__€<ùí¯ãºi“1Ô7€ºë&âü±“¨kœˆOýÍ×ÀqB Ü•ðyFðø7¾Œ7ö<‚þæ,¹ Ûßx “gÍÄ£_{ ’(P ›Ã¿×‡ÕÞƒåÛ€‘¡!”WUðÓëã*/ÇÝŸ~ ón]Œæ£'ñêÿ´Ø"¡á!ôôô ©© ###ÊráÓJ3ÏÕ „‹Ìð%I% 6› ½½½èííÅéÓ§Q]] ŸÏ§Ä€ W ŸŸÅ<7k÷îÝÛpÇw\¢ €K—.ÍÖ©?Ïóhoo¥4’/©¼`Ïæsž_ç«Y„)n™)3Ç+çgÀàà µ ÕPÓJ!‘$”šÃ-)I!ÍíV‰d‹lp•—ã¡/OžÁë?ywúq€Ó]–0‹_÷訛t^úÞ#àóãºi“át9ñÈ_<…¡¾~¼ü?Ââ5Ë!†B˜½dæÝºïýæ5TÖÖÀ]U »ÃGþâ‹h¿Ô‚ßþà§X÷؃C"f,œ5߇=›¶àýß¾ûŸú´® …bÂõøÔ_-²¤1ëæ„òñãŸWQ®çÏŸG(~1ãz×#¾fM.(~ŠB Ad†ŽÖ6 ôö!(òè$˜R 9Ñ>@¬°aÆYz'Me´¶¶âĉ˜7o®¿þz‚9ì&áyÁPnKé”RPN‰hç E__<ˆšš¸Ýnôõõå$ÃX†ã8MÀL‘õñÁ,*Öú¿E6Ì^¼ÃýCxõ¿ŠP@™¤4Lž„{?÷žû_ÿsìÍkVàõ?‹‹'Ï`ñšèîÅcõ4ªêkð“¿ÿW ÷÷£¦aÄ ˆ‡¾ô9  è⦕Ë0Ô×u=à7ÿùcø½>8\.”WW⑯üNî=€÷^~ v§²,cÁK1mÞ¼õܯ ~Mª'ÔãÓ÷ ØìlüÅK8±{?¾ðÿ}@8«+ìiÔÔT£¦¦Ë–-ƒÃáÇqÄ´–s5T]ª>yŽ  ¡íÊU477ã–[nAUU +’™Ô‘pP`³|DUUU7èVpKax½^x<8NÔÕ×G‚ðDQTÖáS¸ðS‘ÊEÅÀà¥@ƒ:+ôûý°ÛíÖq 8Nµj£0St½_’ cŽ% ‹Òb »¯ÿäY„ApwU9žøÖ_ »5±ÎþÖWßĹ#Çõ1ýƹ˜6w6Þ~îe ‡—<e.<þ/A–e´4‡ÏãÁ‚;–¢§£“gÍÀÛ¿|~¯’¶ZVáÆ'ÿú«ðxñÎ ¿Ô5^g™<õYì~ç½]…X>òñûÆð‹ÿñÐÝÞ§» ²$B°ÛðØ×ÿßÿ玜(Šlņr<"KÚ¡€ÁfK`ÐŒl¿~ætð6/|÷¿pë«1}þ ôô⺩SàDóq%hL›7>Ï~ñï!àS2ZÜ••˜{ËMhm¾€ßE1èëìÄÎ?nBw{`ÒŒiìÀgÿî/qý¬™ØùÇ?E.³ ê59œî®ê·T…îŒT,\}Wõ®ó<¯½s ‚=b<(÷™åþ·È€ÏþÍ?#H,üÞo^Ó<îçÿòo‘í3ÌCÈĹ#DZå•7p|çÞÈq’$á‡ßþ—„1®œ;gÿÇÿ.šò×B ‰ðz/¼^l6ÊÊܰÙlÅË4ø|>ø¼#$Ng\ee–÷Æ`Ôʨ€a¿ 7.#ÆÓû¡Ž×‡v©cÆ5wÆÆçjO6Š4×1 1¦™ I’páÂ9´\:Ë-18ПpŒÓáÂä©Ó0eêtÌ™s#œNW$-ƒƒh>{W®\ÂÕÖ„‚Á˜ý„ÔÕMÀ”©Ó1cÆlL™:ÝÒ9c؇ÿÍéšÊpñ 0ä®Õ›1Z_zé¡(ZfªÀœ^‰B`†ˆ}#Æ( à÷ãè‘8rd?<žá¤Çúü^œ;{çΞÆÛÞÃüù7aémËQ]=vK«t´·âÀÝ8ßÜ”t™1†îîkèC÷¢¦¶·,]† nÇq”ØBÀYl9,̆ù”?€p*àø{xdL—ë…ÓlA€ÎŸÅæÍoÃ3<”ñ{C¡Ž;ˆ'ãÖ[—cùʵcJÑü~ìÚµ GïÏÊïëíÁæw7âàþ]¸ë£÷cÊ”éyrl¢i‡¿ƒ'EN@έ£´„ „ŒúkͨM,’`Îïk¼z²Á LŸ`0ˆMo¿ææ39%Ë2öíÛ‰óçÏâ‡Gmmé÷Z»råÞÞø:FF<9Õß߇ßýöWXrËøÈÚ»@ˆ' õ¹‰Áa£ñ9><»‘BZ¥aOfן1ž§Ð ()ůRiYœ¹à„p tì*7‹ä öãÍ׃žž.CÇíííÆ¯_ü9>vß#˜yÃCÇ.$ÇŽÂû›ß64+ˆ1†C÷ §§ ÷?ð(Ë ÑÏxƒ ;Ï ¥ e¶@¢ÿUfø ¼@"ƒPÂ’Œ¸¿ 1 ˜¶•ÈÂbÐð)¥% L”`ãø1=s€P(ˆ@ÀŸÕ{9Ž× \2«1§'—$IðùF²“‚²27 Œ¬5œl곟1‹½ÐÓÓ…ß¾ò<|^o^ƃøÃ›¿ÅGïy7ÞxS^ΑO>ܱûöîÌÛø-—/à•_?‡Ç?ù9¸\ey;Q(“ŒQý§¶*Où¼$¹O„ðE¡Šnc2(¥à8Œ1Å8“e€çÆ@“e0–•éÖP±QBˆ þ¸õ^”RPJ5*v»„ˆ¡¢ü A(‰z_¾^¢(*1åA)xžG0Œf§ª2»lLõ¦Ìî½"´fÍf5ôe1ë÷F~@ârÚa· YŸ7ÌÀgÄf èÃk¯¾˜7å¯"Ë2ÞÝô45ÌëyŒfïžyUþ*=½]øÝoŸÏ—÷så!½æ÷û!‰bDç[¿I’¤èß(]ªÎþ9Žƒ Êdœ1„B!0YŽ+IR²±ŸÎ‡èÿ-I<B¡xAÐ<&ŸŒžSq…(?¼ÑDó*´Šò2,Y4'Ô`Çž#8–ñæýl…¢öÊŠÛ¡¢¼ '›.¡ùâÕ¼NJUé/Ùzª¿S#@¦çH§Ú`> g¯¾òBÊ(°ÛÊËæÇñÊìŠÉeÁPÁ€þ€7é÷/Ë26½ýœ¦N›aäGÉ ÇŽÄη¦<ŽR‡ » <σr(dY‚$‰ýð|“{(»»¯á×_ÆãO|<ŸZƇ#¬ps¾½Ìoº¤Üwœ ÌðC¡DQD( §n)_5®‚¨F tïMž—e9e¨jôÔš2ÆPQQ¡œ,<£R­À€ªr:xu ²r.Å*"aKÈí6o#Aàqãܘ=cräAè.3K±y ³Ô(s» /œ™Ó&áб&\ëî+ȹÓyàd3ûÎåølß“1’Á˜Œ·6¾†¡¡Á$2P”¹*àvW€ÒÄÇ£7Â縜nȲ ŸÏÏÈ`Ø«–ˆ$IxkãïðéÏü9*«ÌÛ€µ½½[·nJzŒ ØàvWÂéÐ~¾rŽãa³9àvWACö ÀïÑõ.¶·_ÅÖ÷7aÃGïÏù3äB)*** ÃJ–@–¤ô<ˆ9.Ȫ—!ª±êùu¹\‘¿)%á °"“~ŽS¢û<çø7¦\d‹7┡Pƒƒƒ8zô(Nœ8A".ŠHäb.¤ˆ€¬¸þe&‚;/Àï÷£££ÃÃÃÎ=zÕhî\}+*+b@&ÐkaÌ#I"†VÂÊ%CEyÖ®¼»÷Ç•¶kE”Ê"lߌ֫-ºûív*+êÀóé/ïPJQVV—Ë gž‘AÍgžÏçÃ[_ßú3S¦z½#Øøæ«ºËŠ„¸Ý•(wgfÀð¼€êªz„Ä ô  jwüØ!46^ g,{¾ééîFWW6oÞ ¿ßJ)˜LÀó| åY£¬ÿ3p¼âóyFÐÛÛ‹½{÷Ân·Ã €1»Í Y–!1Y1ô=”!ã§©j¨ÿª16›-RS E1÷@ž¶Ò%YY÷àˆ"KYY\.WÞ]4ÙÐt¾‹ÌÍfR——I1áW èìêCWï@^ÆÎfm=ëõùZóϤ¼p.\¾t‡îÕÝ_^^•±r‹†ŠòòjØlôti*†ŽŽ6ìÞ¹ «ÖÜ™õyòÅŸ6½‰av žPSÓ‘aÀÛQ_7 ƒC=Ñ^~yË;˜›à@MMƒa•uà8CC‰Kf¡PÚô<þÄçL5q«¬ª„ÛíÆwܧөüþÙèZ{^¡²,ƒ§œb0CB(ÂÅæóÀ’%KP__*„3Uô.QâôWž„ô}ªÑ?ž¨m·Û#3}Êqp8•¼NIÁå3¨#,‚Àñ!$Êq°Ùíp»Ýðù|˜8q¢©n¤hüÁ 9 —[1{æ´]ë)‚æ¼6zä' óÏ4_†Ðtþ2$)¿s]ÏÏfŒBY(À®Û5ëùBPUiœòWáyuµ×¡§·#Á`LÆ»ú#>óÙ?‡ álßú®æ>A°ªüUÜe• i\½z§NÅ‚æY „Âçó¡Ìí"ø6%í<ÏË9 Ê7 §÷€Ýá€Óé!‚ @°ÛCA’@© Æ“°Ç@ÿùÆ”VÆÖ+æ­£ÛdY‰N$áT0&Ëàx^8Ýñ3|ÅBˆ^WSS'J¾þ!ì=x~ ã÷æò1ÃÃ'SÒ™5f8bVïo¾p§Î^Ì»ò×¢ÁuÅ àˇÐß߇C÷h¨ƒÓ™ŸtŽãQ«£<»®uâÄñ#y9o¦ìÞµM3#‚çÔÖ\—·ç¨»¬åî*Í};¶oÑ(Œ1%ç?¬€9Ž“•|ü|é7õ¿ü¦ Š¢„Èd4,¢u£þØ2`¿³EV‚ |x_ÂÒ¥U•‰Ê8ß8ì.ÍXŒcÇÍ@*ô¥Ù,(HdyfRô.„E¦ˆ2ÙF×çóïb‘ G4Çñp—ižå›Í—3qf}ðÀî‚?§B¡ NžH B,+«Ç§6IEymB`²Ïë-šIŒWˆ¥Öo Z¹G‚ï•™  ²k%grÆëlÑ(̘!P*YF3V{d#gº„‚AœÐPpååÕE}6”—W%œ¿§§+iuÂ|pêä±Hm{Žãà.«(¨ñç/s%žÿðas,˜A§D¯÷Çü~tŒë2û)“·a²(f¸Ùã1£Lf¤Töò!§Jssþع Ï †çûg Çñp¹Ê¶Ÿ:u´ rœ<™h¹ÝUE7üÝ®u¢»«³H™°çAó÷£¨ƒ‚Á~˜ê Yt¥¾y#î<–ë?7Šý ˆG¹Æ§PªîúlfóFyΜ9‘°Íí®4…©Á‰æÜÙ3K èǵΎ˜m”rp9 “BC)‡2 ©ØË ²v]!õ Òà'ªNd‰‹1™r”<ñÇÃॠÆfE.þï½$1Ã2³ÉSH¬ ÀÌðù¼h¹|!a½îu…†ãx8âRÛ‚Á.]<_óŸ:u,a‚Tæª0Ío¬LcâôéãÖ¤Îh(¼€ùZåYJͨՖu¼i`>ÎaÄ{Òñ*Á¹sg‚ÿ̤à Ì•èhj*Ì,÷\Óé„mZËÅBË@BG{k‘$³x(ÓnËd1®QVr̳ `¦‡w¡±*fÆ%¦6Nèûbb·;:ë]¾|Œå·´ôððzzcW9.Óµ'ÖZޏxQ»Y‘E–06Lh÷´÷˜%ê>ŸÁb¥H6L×ÖðBÎx“qõ꥘m6›=§6¶ù"> 1à÷££½-¯çÔR¢ùê… ‡ ”Ä%—.f‰d1D [ s¢¸Ý‹¯xÍbˆŒwJÁkk½šÞf¶Ù¿ŠCCñ^¾tAãH㸧D !°ÛÌYj7Þ0éºÖ¯w¤HÒŒI)@Rg1^1CUÀñ¼þƵ^¬1ãÉu  ¥åbÂ6»Íœ}"Þ¦± ¿Y.c W®ÄzGv—i ìø8EþÄï×"[èØ$ÛÂ"L±•¯åþ7Æ•nÖsýݶ·_ù[íiVìöXãäÚµÍæ­÷¤ó7¥Ÿù̧ð¯ÿú/˜;wvZïIFoo죌煢ǰ¤ƒ Ä*¹Þ>ãçdŒ1ôõÅ:{ãÏkFlBb@_5g5ˆn€eNY¤D™=…)ÇYxƒÃ¼dêz¯®®Æw¾óO¸í¶¥1Û§OŸ†Ÿüäÿâž{ŒÙÞØx¾úÕ/Cx¼þú›Ø¼ùýȾ™3gà•W^Dy¹’JWYYÿù?¿s^—ˉü!Ìž=Ï=÷.]ºÙÿ‰O<Š»îZ .bË–m1çý»¿ûî¼sàî»7àþû?žúb$!QÁ™† 6Á/Fë±õåÁðŒ # Æl³›|yPî!Žãcú$ô÷[«ÖÑÅBd&É]&[ 3CÀó|A–PJKbæV(2é0{ö,üâÏ ¡AûçûÚÛ;@Áu×MÄóÏÿÓ§OÜwß=xôÑOââÅKxê©Ïãþûï¬^½+V,Ã>I’°råòˆòÃâ©§¾€ßÿþI?k2úcã™Íý ÏÇ*¿^ï\.ã ôô÷%*ÍR¹>‚`‹yîäÃ@‡tBdõ×eõZ´H‰¢˜ó3L¬Èÿ8Òu­¯\¹¯¼ò¢®òWY±byxfÅáûßÿ?寎õío ”RÜrË,[v{Ì{yžÇã? p»ËðÜs?‹(uÛ?üÃßâ®»ÖG”¿ÊìÙ³°aÃzÀ×¾öt‚\=ö!V)¥»ÀÃÀ@©‰rj)ì\è3Ž(åLUê;ñŠý}Vâšt€ò¤%è⢊“'¨Õ@ÊPx^€(†š­Çqã>ï?žt:÷Ýwß=øÞ÷¾³F¯Ç´iSAÁ§>õ ,^|sÂþ)S&cêÔ)xøáû5ß¿pု~õi̘1=aÿªU+°`Á|Í÷®_¿½½ýX²dqÂ>§ÓÉ“'áØ±c‘méÞ >Ÿ¡P¬wŠçJc @õxÉòhtûÐÐ &xŽ¡¡Øzo¥bgÄ‹, Š j$<ÏcÍšÕÒÿý&†‹•WœÁ1TÚ@üó£Ð¿}BI¸5º"c ˆ›8Œ\Ž(]ÕŒéáÔÍíQD~„ázÁ@@© P !`áüLU³,I˜­™4cÌTnU-eY.J>p¡Q:óçÏKyì®]{°{÷Þ|‹”wôšé’ð;/mg=·bI¸ |yÔ"M€{D9²,$Ø4p®A ÖP _…B!0IŠÈŸª˜@”®,îÛ·ï‚Þ=§ý½mpp„´´´ ··<σ1.,P¾ofu|»CPf³¢QáõzÑÑÑ_‰Ïˆò¾+ÝL!mYDQ‚ ”–»7SÔßZm­vq•;vâ«_ý+lÙòN!ÄÊ+µµJA t €øqé)ÐXy9ƒã4xžC(µÌWbvsü÷ɸY˜wD©4yüøqƒA%ø™Wº)æ{9‚xE¯Iá/Èe#CÃà8çÏŸG{{;B²‘KEH,l È±×Ž\Pÿ¹ËÎ77Ÿg:VsŒÛCc;¥~¿ýýýèïï‡,Ë$ <Ï#ä=èˆR I’@9Åâ@`³Ù  …ÆUÄx¦È²¬ëÆ2S%5Žã!ˉn?IêÇ5ÔßY__¿î1Û·ïÀ×¾öMÔÖÖ¤ìP x Ê(//?—­QXUU…‘‘ØívTFU“D± _”$Ã%@9TUUAETTT˜J‘™øu~Bìv‡éš…Bàr•!ðÆÈ¬¤ЦòVú€yóÍ?ⳟ}2fߟþ´¯¾úûÈ쮾¾¶àòM(ÂÖ­Ûd°ç.JpVÄËk´ÀÇyÉJíúÄÇúÄ|y?¿¬¬ÿO˜0 ²$€+HŒ {"ôp‡»áAȲ J).@¹hØ€jÄOì ΩÿHO¹ÆzŽnLùŠ" Ân·®…„÷Goºcæðb² Žç•@ˆP(Ò¸!¾C˜Å(Jú_´@àp8M§üU!¶ŠÝX¯ þŽNž<çŸ1²ýg?û%þò/ÿ:Æ ,¸|FóòË¿Eo¯Ò7]ÀétÅüÝY¯ˆ—×épé™»#éùÌL|š28]ÎÂÊuý=¬ü£ßåûñ¢Gã‡ë (}Yx@–ôr¤N@ì«—rM=†}ƒÜé\ÈÏ2ÜÉf³Fá‘QKSMc¢¬BY–a·ÛKÎÕUHdYŠÜ3”R8®’ð–ØíBñ,¼ `/¶Xy#Z þÛ¿ý;:;»pàÀœ8q*æÆ®^5¤­GJN:oÔnù› ×ðƒü0òwº€ËÛ¦”(¯ËàF7ñã•ÒõÑ’Õèë“ Ž*ëï`±ø$IÊÿ33¾ a8CKíH)UôadI#ZKð¬)zèÉ !Mj±ƒT¯hk„ã8x½^E JA( ¯9¥;^./^ ØlDL–A!2ó/½|×Â!†s9އÓYfè,Š"‚Á@äetí~›Í‡Ã BT€ñ†žoÆΞmŽQþÑ´¶¶¡¥E¿²÷áÃGr–aÇŽøÛ¿ýÇïš(ŠèééÍiÜ`0ˆý茌ŒÖ­Oß(‹ù[™ý”Ž›[Š+ÔÿyrE]·=_)±ß#!.§±×'%D¹Çý~Lš¹Z /Š·›1ð¼bˆ¢ ê]BHÄk@)Õ’Oßèé´/H”Å¡¦üÅ{òmEúG-9¨n5ÑBBA°Áétj(1Æà÷{c €@Àox]žçáp”åmý_–Íá=Šÿn´þŽÞöË_¾0F{{ž~úëø§úNÊó©Yxœ„5i6%c!–¡Ô>‚Y®y*%¨eìØ±+&`pÕªU”HæaÙ²Û5ÇÚ¹s7þë¿~ˆåË—ãøñãxâ‰Ç öí;€^x mmíºç=}º wß}—æ¸Á`?ùɳ8qâ>ñ‰Oãïÿþo°pá¸xñ2~ðƒbß¾p:³ì"„¢ªª}}£-MJEÉiÉY]cl6GuuìxjÜT),‘Jq€Ñ×f\ÁãdìŸQBÚ˜$w(ýJ"c ³(£ñ„Y®yüC:›¥µè÷¼øâËšÀ±cÇñõ¯SYS$Ï=÷+<÷ܯüÿì½yÇuçÿ}™UÕÝ3ƒ¹€Á}ÄAðo$©Ë–EQ¶EI¶hIöî*,[ñ³–"dÅo­]o¬e…¥X[¶¥Õa‰ ¯dëX‹’xŠoð>$H€ä˜ûìéîªÊüýQÇô]}TuuÏä'¢b¦««3_]ù^¾|ùؾ}{àŒš—^:Š£G_ñÓøzX–…OúÿA.ç¸_yåUÜvÛbÏž=˜˜˜ÀÈÈHÙó,–;ˆþB x ÜvŲ ãctý—[ª4%,Ë,™QÓŽ?wÊh˜"*§+}»ϵLEÍtRÔîR¡]bH‚\þÅûÊ.ùßßu×=¸ï¾ ŽôÑCøÈGnóðÊÕQ)Xþ÷ú§†ééßèè(~ï÷>Ž;ï¼;PîZ>Wc°H1˜fgd-ÎT:00zϼwE_ɸy'\gM’Bip`ULÒt8et{é@ ”ÏtmKR”ÀXùàe´žrR­>J{ÁAA€ÅŸËýæöÛÿ¾ýíÁÐО{îylÞ¼¥`Áz½}G޼Œw½ë}¸òÊ˱aÃ|íkÿ´¸€J™óÓ,T ¦eBJv_Ø´ q Ž1†þAŒúûrf]hïñôr«’zŠ‘ò™â]e ötIî@E˨¤`Úie¾åB9£+ Ò•öÕªXýë‡üÏ›6m<¾¸ŽJ2œ>}?üá¿ãàÁƒ¾ò¯å®Bß@LÒt8tzy€ã±H…QT$™¬œçº’RR„O%c+ eÝla¸ë‹Ë¬eöBÐ÷õž«nez¹é¶ v[H&š¦aÃÆ-‘Ö¹u{©±°0WæÈxÉå2%^Ϩ£%M^Ö ¢W —ûN-DTÑÍÜ Óv–¶mUr‰#y#îú € 2‹W‹APï@9ÂÈz¸mÛ%ûÒm¦ä,Ë,™ÿ¿iÓÖ’Y a³jÕj¬XQ¸ÎÀBf¾m²^z”»_åŒEM »:½„ÊoáÑÈÄQT¥8o·‡ò´†j×9Ž4¤QÓ5;lE`³y»÷ì+ø,¥Dza¶%uׂ™L¡w$•Jaóf5þßUtye@ÒÑÓbXû¼ó5SIɘfN¶€rÁGƒ+[Ÿ†´Ñ¬|QŽ£ŒZèííú¢Ù¶mµÍ”7!Šçgœ±§%õïÝ{vɾv2æÓ3%Ñÿ»ví‹% ×’ Š.¯l0jÜ0ŒXfÓˆR¬w<>Œ8ƒzål6@>å”ÜÜ\i¯;ÒeÜö»H¶&cášµë1X”6Ù²L,Txî[‰”Ò5F Ù³·5Þ‘%I]^Q;уԠs ¬ZUy1Æ……ø_Ò¥LÓ÷F4 IDAT5/ËÊ•C-–Æ!ìÞ{£ÇD!W¡Ñ¨°gÏY%=Æln!vZ¹2 îÌ}ç´TŽrõÍÎN"n/€Óû/ ØìííÇÆMÑG.a²®./Kõî1¡âѱvÝúŠ _6›nëÄ&Nµˆèb·r«¨ez]µ±ôFÝõAe6;=±x_X1êê*똙h¨¼°˜›Ÿ*«àvîÜÝR9Î=÷Â’´Ö–eb!Æ)“Bˆ²^šó/¸¸áç`٠ëR>Põ{E$¤R]èëë/û3oWy¢"®lÄ•…¬–žx5ÅÙÈ|ûZ €f]üµÌVh†ó/¼¤dŸiæb x³,étiÝŽ‚kíPeª« »wï+Ù?3;Ûº#ssÓ%Æ‘®ë8ëìóc‘gI Ã«?u‚ݪ0 #‹¶ DÑÖyTëmVSRŠÆÉå²US.¯[ß@#Š2Œaƒfëh„fÊX³z]IN˜™™Œ%/ÀôÌx‰÷N7 œ}N< î‚ /-ÙgÛff'[.‹iæ07?U²ß¾óJ¥Z.Ï’!@‡W74ü €JBå.L&­fD@¹à#Tª«$pªU4ë®o¤ÌZŽ{X¡¹‚¸ì²«Jö aczf¼©rëe>=S6þàüó.B2‚[³f¶o/Í™0??ÛÒ)ÇRJLM•ìgŒáÂK.o™KÓÕá©j‘ ª^@[AÂÙ–Õ²^I)Û&¢y© „]Õ³²eëŽØÆ!Û%0êÏåhöšoݶ³ìüñ……ùª_˜˜f33¥±ºnࢋ¯h‰ •Øõue®±ÄäÔl»5^’™™‰’¤HpιoS©›ð+"ªzƒž$Ýš@Šš\‰þþÊÿüüllcuK‘ ë¹}Gûd!«Wq6\•W!_Pðb-rÖBy%LÏLÀ4£è$¤ÉÉ‘²³.ºør¤ºº"­?ˆ¡¡5صûÌ’ý¶mcjjQÏ H/Ìb>]jˆiš†K/ÝiÝKžtw°ÀpOÅïÜ—ŠˆÀcÌYEMJcÎ÷­Ø˜H€ƒ°m@J!J#ÚNl)Z¸#!lÌÎvš =#„Àìléø£akŒyÈU @s¬[·¡lÀ 16~ ¹ˆŒ)ÆÇOòKGQ{{ûpÑÅíáÞÞõueSgs ˜œ¬ÞlvSSå‡b.¾äJô¥,ŽF º®Ã4MGÏ9^’¨õàÇŽx:­Ä ”pu.yz¸šîöÎ+è"zDJ9&¥„·Tê~Îf³B8ë¥A Ë4‰p³]£çcàœÃ¶íŽž2·{O©ežÏÜÜT[ž_¥ˆæv5ÈœëXÙS¶~æXÖðˆ¢·ÞHÕꬵŽVôøËqðÚw”k—R`bâ4,+Ü•6¥Ÿ8]ÑÃp𺛠ëF¨u6Jß.»âê²ß-dæ15¾Í.`bò4Êu Wá’6ëý )`Y–o(Ù¶ )¸¦E¯ã°Øv !ü¡¯ãí~pŽuõÑ#AçUS‹L$ï&&AL‚8œwÞ&aƒ˜×RZ°íˆšÁýÞyS[EÁœï¹¦-^€¼‹fÛvÛ*Zؼe;ºªdž ê¹Æc †‘€¦éþ¦ë8v¡“F°í`OÊÞ3Kç“·’b¥Xn1 zgЂBAr”«³ÞÅj1Âz»º{põÕ×—ýN£cÃÈ„4½Ö²MŒ¬H·gïY-Ÿ÷ÄE]Ž5kÖ—ý.žÃØøÉÐ:óéYŒOœª¸õÛßñžöKû+¶Â²œàkÝ0=ÎA4©ÿò‡Êˆœsë}ÈårÎwÞæ^SÎÙݵœVmo—wú!J,Î9t]÷…̶|ïA$›+“ÿ€ºLÓ47ÙE{ºžƒ`Œao@ ̹¹©ÈÇ1Á0H&Sþ–H$Qç®)¦§ÇªŽý3ƱgO9÷që¨eõ¿ ÏAÇ4bT´"(0LÀYçœ;ËçÛ—Rbrr33Í̓O§ç06vfBoo®½þ¦†Ë "†›Þù›Ž· ¹\ccÃM­§ „ÀäÔ¦§K#þ=.¾ôʪ3 â‚C*•ç–iúCÍD½~s•º”Òñ¾üÖað¶‹.ÃðÿOÕcfg§`I¤RÝ-’ª³™˜8h ®¬:£U„1–¤Hfè¤ À|†V¯ÅoþÖoãß~ð]L·¶mavn ³sSg: ! ¥¨ËhºrÿAœ{îÛB>z|Ò8üâsUËfWrÒ81ØÂª«ÓÕÕÕ÷ß|+ººÚ·íšžžÂää${ì1¤ÓN¬ˆ®%j‹3kÒ`Üqó{î;ÃÛÙôfffðè£Â0 †!L[ü¢Ö²k6’šq‡ ùÙâýžÐÓÓÃ0 ëº¯ü½qø¦©ÁÐ4Í¿1˜¦‰žžž‚Ø„Ne÷ž}¸û®Ÿ!`ÈLNŽ€±µH$TêÌJxc½µŒe^xÑemñìÔ;^_‹R­%0hX¡Þ À  Ü°BT=ÂÍ›·á=ï½?þÑ÷kLx#!„ÝP áK.¹—–ÉHØ®nzçoÂ2-=z¸¦ß8ãÓê½:©d>pËG*Ë´ Œshš"Bww·ãŽg:²ÙlK<Œ1$ ç}‘¶ÿÌ& ôöö:3ðtÝñ‚ú£Ö²kÖÎ7ÜtÓƒ™ôÂ0€õ@ac0<<Œ_üâ¸ðm»°cÇŽw|T*ÇõŒ@ÚîP\k̘Åwܵk×¢»»££ÑÍgÇ Ž B`|ü††6´Í£öBbrr´æµ’©ö«m6诖žvTeT£‘`Å0Ù¾ã |à–àG?ú>Òá/°ED¸ìò«qùׄ^vÔ1¼ç7nƽwÿO>Yy8 úúð¾ßúؖٮ‡žž$“I8£ kÞz†ƒÊðôœ7¬Î™ó›W_>ŠC‡ᬳÎÂÚµkaÛ6ˆhXOuÕ¼Šo]ÝóDÂø@·ù;ÜÓuÝwAîôYt*¸“¼ æA‘è x.»vèÅ5ÃsÏ<‰é©ÉšÎC‘‘718¸F ä!„ÀääHÍËJ)ñ«{‰3ÎØŽ« ÂPŠ­ˆÈï„€b6lÜŒßýÐmø÷ÞŽññð: †‘À;ßõ>ìh³é~õ@ÄpðºÑ?0ˆûîýE¨±T›7oûßûŽYè‡‘Ó ÷¦àð=Óਤ¿<‚~/òf¥x1^ß›éÆ4ÍéüûY §ãS_Ë&åÿ•€ox¯¦Âߤ” ¼© 5–[õëJh±mîéÏLhdŒ²Éårxàþš¦tú83N£·w==ýKâ:4ƒiæ01qºbÐW%¦§&ñø£VL’µÜÏzg4RFP™ôð㈠èïÄ­ù{ô×xô‘šÎ¿}Ç.\wý;ÑÛÛ’„ñrÁÛ.ÁæÍÛðË_ü¤j0r-FWì?€óÏ¿¸mþ‚ðŸI7áY³ >è÷Œ3¦3Pú[r Oïø¿µžP¯ÀùOIÈ4€Eßh¹4l\Á@ðöVª¥$saòà÷`nÎYCÜ;—Z®«”ÓÓH§çÐß¿jYÆH)033…Ù:—7Ífyøœ}ÎèY_&À¥XK=­BÓ4\~Å5صëL<üð¯pôåÃu÷x׭߈K.ÝßvI~Â`ÕÐj|ðw~Ï=÷=þ&'ê[MQ×uìÛw.¹|?Vô´OŠßZqRÞ”Ñ'e¦à–ýqj"ÈÏ@¿³íu¼]ÓдŸžLuD$¤mÿ [Ê)þüœ-’æ©W‰ç ÜûšœÀ‡J³9±š“•˜f££Ã0ŒzzúLvw¬å] RJXVóó³ -˜Tü‚çrYÜÿ«;qÓ»Þ¦˜MQ‹ 2|ë}/‚r Ôò9H†F=a²jh5Þýž›1==…çž}¯¿þ FNŸªh ôõ`ë–íØwÖym?ůYc8÷Ü·áœs.À±W_Æ‘#ÏãÄñ×0?_>¦†sŽõë7aûŽ3pÖ9ç·mþƒZpÔê5™÷e5‚ôWà3.‹tYaf@¿ ‰ŸÕqXÿঔ?–À-ù–OqÖ"r÷ùâ6Ù ¯ÅBrJ©NöÜ}×%îH"Â…]†Ç«9΀£È&&œyïNZ^Í™¶Ã:×@ÊǶ„°`š¹†Ç*ûú°rå^}奂ýÏ?÷4λàb¬_¿1 Që¦cë¸øë-³Þß×*WôõõãÊýqåþƒÈd01>†ôÂ<æÓÐzºW ·¯½½ý±È'D„;wûñ c˜››ÅüÜlÛBWW7R]ÝXµjuÙE†:)}¥-½Œ¸UÔ_AíU™6ºlç–±W/¨”ú ÎDVþo½`;ƘŸ‰(ܣ闸 %Þ©ÀñãÇðÊÑ#%ûÏ:û|¸öíH§çðÂóÏ4T¶iæê_êhš†÷þæ-H&S8þú«óÃ¥”¸û—ÿ}äã±(¤(¦ìcjaÐ1•r¿×ó9’ÉÔ’ïÝ7Ãàà* ¶÷4¾f)p¿”r1û^µW¡Þ @¢ÒaHióŸI!uû‚‰hA ù#ïx9ø òòñj¼-ÿØr[þ±å¶@™¼eóÜ!%.’B»ï, æ4 W]sàú·¿«V­nµhK–ënx'Ö®]þþ\Xf™Öáá7£DE³Áu(ë 2 èk¶L…"v¼a÷ymVÕóûŠïáGD´Pï©44L Ë“¨¢PµŽÁç×—ÛÉ·„ÜÏÚó€§Ÿz£#§Kö_vÅ5þ²´†aàæ~}ý­oɱÿªkqN^–¶Ë.¿ªìò¿÷Ýó ˜¹Ö{NQÖÍŽ×7Ò3oÄè€BA ~¦ÙüNmî CÿyÞ9?¶Ç­· ߎÀ¿TS–Æ¢Á8~ ñe¡Édðà÷–ìïïÀ…]V°oÅŠ^ÜòÁ`Ŋ΋ªm.½lÉ4?ÃH`ÿÕו;;;ƒGùu«D«HÊ:Šz‰ˆbÝ…b‰“ç?lä‡yˆr€l¨BEuøÕÝH§K“Õ¸öeÒô âCù8Ö®ÛÐ ñ– Œ1\uÍõ¸êšòkÄŸ}Îùeƒþ}äטžžŠZ¼Z¡—J Åòƒ~èèäúi|>˜dÕW§QÔÍøø(ž~êñ’ý[¶lÇ®ÝgVüÝŠ½øíßù=ìÙ{v”â-R]]xßû—^¶¿â1D„k¯¿©DiY–‰_Ý[ÓJ›¡”c¨?0Œ¼ýqÈ©P( ‘@ú¸á·‹4ú1€àõT5sÏ]w”LacŒáàõ7þV7 ¼ç7nÆoÝü¡e95©Vöì= ·ýÁ§°}ÇǮ߰ {Ï,5ª¿øÞ8ñzÒ•§Ù±õ¸öꕳ–\ …¢€‘µ6Ô=ýÏ£Ùuzÿµ¹ß+<^9zÇ^=Z²ÿÜó/ÄêÕkk.gÇÎ]øØÇÿ nxû»10¸2L;Î9öu>úû„÷üÆêª=!É5n€n”.¬t÷?‹-д^E[KµÔu  š PÔšÒÁÍ­rÂØ÷!ñŸ›*CÛ¶qï=¥K8'“)\¹ÿ`Ýå麎ó.¸çž!NÆñ×^Å›ožÀìÌ4ÒU×@_ ¤R)tu÷`åÊ!lݶ[¶ì¨Kéç³¢·—\r%~ýÀ=ûOŸ>‰çž}²`ö€¢:J™+á"ï7óû¦ "zP ù,€sš)g¹óÄ¡G01>V²ÿŠýÐÕÕøŠ~D„uë6` lŠK.»Ï>ó$ff ƒÿ~uïØ½ç,$‰HëüñÇ«~~ñÅ17·˜ŽuxxýôÓÈf³þçãÇcaaqêòôô4^z©0 cq§N½…ûï»Ë•±±ê+>þØÃèééi‘4íÇL‹tcæÙ}ô£õ¥„-¢ùuN ·#&€:wª¿O:=‡~]:íopå*\ð¶Kb(<ˆºÎaÛ²éÖâDÓt\}àzüôÇ…±6éô<~ð>\sðí‘ÖÿÔSOUý|ôháÐÑéÓ…9$2™ Ž)Ì*Tf±">yòdÁç¹¹¹’zƒÊ|á… >¿ñÆŸgff033SµŒÑ‘Óesd(ž{öɸEPD…tužïH£Û›-2ŒÛï†PƲåþûî*èy\{ÝM}Íà}ï<€ßz׬^5·8Mqæ¾s°iÓÖ’ý‡¸¬÷F¡P(¢DrÞ´îmZÃÑ 4…¸œ9}ª¬Å¾}Ç®š¢ÔÛ•ÎzèŒVÆ·œnX\{Cé´@Û¶q_‹§*ŠeÏwîÜùFðaÕ ¥‹IR~'Œr–wßõ³2Óþ8DìRnsycÈóéR/G§±fÍ:œ}Îù%û¾|¯+Á¡P(‘@Eç†blÚºõ‡hÚYN9쬥]ÌÛ.¼«†–Æ"?SS³þÿ““3UŽì®¾æzFiÐß=wýBtnœƒB¡èÞ ÒBÉÄÞ 3÷C+k‰cYî+3í/•Já²+®i½@1á¦ibv>ptgÐÕ݃Ë.¿ªdÿØØž~êP )Še…”¡éÚð ¢o†VÖçñG,›Oþªk®G*•ŠA¢h˜œrzý“Ó³Gv]rË$YzàWwcaai: …¢MaÚ7C+*¬‚n»í¶W$T0`1RŽñÏÍÎ⑇(9nÕÐjœsî­«%LNÏBJ‰‰%âþ÷àœ—ú—É,àÁ2S: …"èÇDôJX¥5Ÿ ù ïܬ_^ÄtÄ)S rˆç­—ì}'¹\®@¾ûîý%r¹rÓþnc¼d'cY6fçÒ˜œZZ8c×^lÛ¾¯+|Ÿzâqœ{Þ…ZÈä%º©•Tª±¬… …"R©.pÎ!„cÌiÓ[T·(.%Ä7Â,;Ô‰ægìÙóH\ÅëmË)%²Ù àÔ©a¼øÂ3%ÇìÚ}&¶nÛÙjÑZÂÄä4Ƨ¦ã#–1Ú„°q÷?ó?g2õ‹¯ ©Mmjk“M/³{«È[#ã°¦i? ³ìÐ3ÍÃ×Ã.³æº‹V+ÞéùyH)qçÏZâ‘àœãê7Ä$Yô<ýÂ+˜›«¿Ü ¬Zµçž_ºÀñ×áÕWœLzóós%ß+ŠÎ&½Â(tÝ~ª9Æþ @K'}ÜŒ6\MìäÉ7ñâ ÏbxøÍ’ï.®P¶TÈd:þ5ö_u]Y—ý]wþ ¶mãÔ©á¤R(KŒ,€ »Ðð=D3á H5œ8þZÙLºº{pi™)eŠÎ!•Jáò+®.Ù?59‡~}&'ÆcJ¡P,%¤”ÿDD¡GSG“lžák‘”[í4ðܳOaf¦tüšå“Ê(:‹ *$ozø¡_Å„ªP(:ÆX$:5€ˆžèߣ(»Fòe‰M rJ`ÍÚõ8ëìÒ´²ŠÎƒ1Žk¯»©d¿Rþ …"þÝÑ©áÙrs$éï‘?0JÊÔá5¾"~ý_áÚëol ãD[·íÀö»âC¡P,1ˆèï£*;:@§;Aö¯%l€É&7ªºÙÂÁëo )`CœÁ²¬¨N±aöžyvÙ¥eÍu7ÜΗV.…Báô1MÓt–h'rææ{\o«¨£šÑ}â×DT@QOnü_–e]©5=‡²¼+Uºh¯Ñ%"X–MÓ i,ËBWW{%UÑ4W¸>n100°ç¿ízì¡PË%"$*VD¡ˆ‹+V ™LD0s9hšÛ²À[L:Wñ×á5üãˆÔ Òný¬eYûš+©º£Â4M@"¡Ã¶m蚆ÙÙY˜¦‰ééé¶ò$“Id2èí[EØØ¶ Á°¡«k鬡PtBHÌÏÏcrb€›à-cB×u¸YV|õE¥/‚xaÍšu·7úãZˆ<½ÑøÃ¯hr £ºÀƒRºË±J‰d2‰ÙÙY cv¶}RÑÎÍÍâ[ÿûï±cçnlܸF"·HŠ&ÂÆôô^:ò¦§&ãG¡P„ÌØØV¯ÂwÜÑÑQtww#™èÂìì,t]‰ðÕFX+‘ÿø'ÿáðáþÀ–FË é•.°”Œ1pîËf‘Ífñú«ÇÀt ]]]˜š*]}/ üHï:"¾…8úòa}ùp$2):òR*ŠvfE¯3pÞyçA×O3$+Ì>®p|ïÞ}ÿÐÈë¡% Ž÷ìÙówRÊ¿iô÷A€7öÏ9Á¶mhš†é©)¼òÒËX»jU¤ã§¦íx4_®hEgbpÓnŸá)…BQž¾Þ>†Ý»wƒ»1mfÖ‚n~ç/L€ˆþ®AQë"²YEÕ|™$;E’¡‘­8ç " VÓ4d³Yß=¦mCJ #ÆÅ"‰Î5߀T(ímÛàœCº«óÕÜÞ€Î;°/Gy.-1ˆHÙ Ù¶í¸b¤ã¶e!›Í"‘H´$Ë‚i¢7©‚´µ£sŽ.Ã@:—‹[…B€„\\˜1Ø–b "ž¾ìèÌèi‘׌4SIg+)š¹C®²çŒÃàš½0µÆ`wwäõ(–ý]Îó2•žY…Bˆ”þ²¼RpMƒÂ×=!2âêÊ–Ð2€ˆL€Zvb­dr~C+z¡1•FQëûú!¤ÄôB:nQ EÛ@_rtekhÀ©í8ÙÒ:[À[S“`DØ80·(Šaóà*ŒÎΨ…BáqÒÕ‘-£¥Ùµô[ÁØÜ,2¦‰3×oˆ[E°q`½©N¨¥‚ …ýOGG¶ŽÖz§/x­©2ŠbH¢™l‹M#¥ÄÑ‘SèêÆö2ËÂ*œ1œ·i LÛÆëc£q‹£P(Úƒ×\ÝØRZn8Ðÿˆ§ÞèxéÔIXÂÆ…[¶c K*ÊsÑÖèKuáèé“È© …@\:1€8ý€g›.§Â¬€8ÈZ&ž8þ:tÎqÝÞ³°ypUÜ")Úˆ”nàÊ»±ch5f3 x~øÍ¸ER(íÁ³®Nl9ñe¯‘ôßAò{±Õ¯ŒœÂšÞ>l]¹ ûÏØtn&ÓóÎrÅŠeK—‘À@W78c0m¾ò² þS(’þ{\UÇfF·K!>‰k-ÃK½Ø.^xèÕ—‘µLìZ½]†.È[$E›0ŸËâþ—`b~.nQ E=Aˆ¼Ünòi+€tú¥´íoôÑPË¥ðÔd2‰•+W†VžB‘eÙ˜™i ï B¡pa¡är‘ß$ý2„‚B£m†|û€t˜E¦RÉ0‹S( Å2Âh>£kÚÕmmEÛDô@¡^¨înµ:ŸB¡P(#‘h¶²`x IDATIŸst[{Ñv§¿…ăa•74´:¬¢ …B±Œ`Œ¡¯oEãHõ)¬[·®er+ …¢ó "üñÿ1Ö¬Y)%t]yf÷{xÃÅHú uÄê¶aiô!åw¥«Ì¥”°!aƒ8&!¤! MJ MÓœÅ$ý½øêW¾ŒmÛ¶Æx& …B¡hW ÃÀŸüɧqÓ7Ò.JÖ4 Ò÷·, \Ó¯“„”ß%¾§üõÐVkÁ8û4$®°Àâš)yVãÎÿœs˜¦ ÷KÀºõëñíowß}Ž9‚……L•ú´’¸!lÿ¨—Ù™Yœ:} «‡V£¯¿¯Ì•bʺ™jG:e;Ö«1§žL&ƒã¯ÇÊU+±jåJÿäü† h ããæM›‘êjE—,ÓÄëÇcppƒƒƒà÷€pך°m33³E{ ýýŽ‡Ë½w“8uê46oÞ„îÀ.Ñß¿¹¹9 cÝÚuXÑÛDÒ”FÒi¨ð^ŒŒŒ`zj›6oB2‘È{¾[‹Œ9}-ï:­^½ý}}±Éä#%ÆÇ'03;ƒ6B7ô‚ï„üÖÁíšÒñ¨˜ŸŸÇ›o¼›6¡»»»e±[D„ 6ààÁk =Ŷ ˲Édœ`@× rô-^ŸÓDøtK„ ‰Ž2ˆhTZÖ§%ÉïðŸïøªë–1 ŒÁ7¼F›áúë®Åõ×]–\HH!pâÄ›xúé§qæ™gbûöí`Œ 4(¨Ùö›¹·ÙSZÒ1bÆÇÇq×]wáœsÎÁ™gžYx¼w,œ©#ƒ.{ý,Ë‘#Gpøða8p+W®¬éúxýÊÝ?ÿZIœ9ûï¿{÷îÅîÝ»¡i¸æ^#¢–Ý?ÛíqÛÆ‹/¾ˆgžy—]v¶$º"4wýÀªß@Û¶ñÖ[oáÑGÅyç‡mÛ¶-JàM.¤øü¸Ïˆ×ÛáСCxíµ×píµ×bppÐ"´mÛéÉyC†"b‰/ÊuâÄ <òÈ#¸à‚ °sçN·ÃPòW»Ÿ¥xä‘GpêÔ)ìß¿ßyç´"µÐäûtÿüvÙ½/½ôyä\sÍUزu+dQõÅí­ º~ PüN' tuuÁ¶mGÏ9CyÇä§IÓFC&B:ÊÒ´ÛŸ<ôØA Ü–¿ßsÁpÎÛ Ö<õÔSÇ”—7®Ó°Lªabb ###èêêB6›E&“©ÉºfM?ßÌŸÆBXþy§Ói;v Œ1d³Y!@Äýé-ÎoškD ¼×(ŒŒ`ll GÅñãÇ¡iZùq¶:häúÉ<£1g[˜Å©S§Éd it]Ç‚ïi »þ|,áÜ! ÀmÛE:Æ[o½…©©©êõG|ÿc˜™™Áää$^ýuÌÎ: Û¶a¤ÕÜý ªß{ÿ<ånÛ6º»»ýûõ /ø‘ÜÞ4®|€"6L᜿¦i˜Åää$Þzë-¤ÓiX–Ø4ÿþ/’?†íÅIÍÌÌ`jj ÇŽÃðð°ì¦ëºÛ4ׯåþyía8yò$r¹Nœ8±±1,Ö\D„“'Obzz‡F6›uâ´Äâõ”øç .¾ðöØ„lŽœ÷¯ÿú¥ÔÜlï3€<@AðŸeYèIu¹.›4º»»‘³‡+ K6sÜí©T·?$¡iLÓD"‘X¦ˆFšÿRkšÆÓ4ÑÝÝ©©)hš†D"\.çŽqQAÁªë·¦ñŒÛ¶ýF'_«_þ|…ÀW*Þ4 Î9r¹t]÷ ÏHå÷bÏðH&“XXXðe¨úû05H¼1Òl6‹d2é½åÏŽÏ8òäðží¹¹9_Ñ{ïYñsÅ 4j5@*aY–ïø×)›Í"‘Hø‘å•Êlºƒ"dAyäö^çÞ麎ÙÙY¤R)hš†L&]×ýöÂ*Lþù†L&Û¶Ñ×·Âu»Gûþ玗Ã{¦LÓD?æççYõ$r¹cG{zWœû|`!RA# # ˜››~î{Þ‹ÍAÇ£>Œ\rù‘6BAesî(Ó7Þx O<ñÎ:ë,ìØ±£Àp‰ËH&“°m¦iB7>66†{ï½ûöíî]»J¥ „@f!ç_O!@Ñ6üžÙ±cÇð /àâ‹/ƶmÛ`šfõdw ¾¸L"ÂØØ~øalÚ´ gžy&t]÷ ‚0zHAÐuÙlŒ1†—^z O<ñöïß<³%âûGD8zô(žþyœ{î¹Ø±cÇ¢«ÑÞÞ½ðdñÚƒgžy¯¾ú*<ˆžžÿ>yí„w<hƒ € óó’àøñãxôÑGqá…bëÖ­ש˜°ž+&K=Þg)%:„ññq\rÉ%(0røCQáÉâÍæ:zô(üq\|ñ…ضm[àDXשÒ}Ìårxúé§166†ë®»Îo'-Ó1žä===?EˆÓqC==}?—Òþ"€Å…Üš@èëëC:Á† =HuuÅ'(œ±?Æ9‰2™ úûûÑå.Qœ?v YáEk¶÷Ê•†a€ëÎgo™d"rHWÎtgŒ;¬úkÀßîîîF:Foo/4]wzÝM!5ÇŠ+0??®®.ôöõùcÿÀâ½÷þ%’I¿îD"l6‹îînÿYªH îßÀÀ¤”H¥RH&“®¡Ùô굑w?¤ç=â†a8‘Úœ£«««þûäéƒí»¾¾>ÌÍÍA×utuw·æù©„ëáëZуo½‰Þ~$»»Ü`S-a„¤Xk»æ*àîînd³Yôöö#Õ ÷n8mäÂÂz{{ý¶ÑÌZÐuã‹Ä©#•?ÐÁñÏ a^N k|wµ áõc¾aAC –i‚1†D"áZ¦“½y'•Dl²'?Öè¯Ùþ¹ÊÄ h±mœé~ãà$¼ˆ¸Éœ1>Ëíí§R)躎\6ëŒ!7„Ô,Ùlº®Csð„ÐtÝi¼CR ‚ˆÁÌå †ã)q•Z*•rÜÚ]¤håózÜŽ¬äÏ›€œ{í¢$¨ƒ´mwئdˆ$¯-ð ËJפÀÐt;ï–çêO&“~»TK`mW~ßûì ›x¯íô‚C h×,ËrŒE"Ø–å×ëM¹ º¾aÇp{f=#Rw;$^ÛÍ»8}¶©Êc¦£ Òþ$ž$BbÑNÄu›M"7ûþ‘ðÝÅž‹ÝQ² R䥓¬ôœ7E ZÞô)ˆ[Mב3MXnnk"‚Æ×õÏÈm$£í;.\ LÖ„ƒi èFÒ‘«Ù š,€3Œ4dr6 é gª)'@)Úúçþ )À8ƒÆl)³Lçºh›¼Ï¿Æ9rY fÎvãGÜfEHFªùóTÀp VÛ'¶8ô ¸f€qרvo\á˜x¥jžèMœƒ´ˆiÐu ¶%Áȉ³xMmKÓ¯Þ„žüg•»ùQ²œé0s6R)æ_ïØ°ê/Å)X×µEÁ}C)—ËÕÔþ„=WZžË5L'~ Rf¹®ý§pkn=KÀ ¥%ÿHB|p­7éÌÛ4 ÿrç³6\G“€îô-ך5 Ę“¾•{ ÍÆÀxV¼7Î.¥Íƒ®ë~â¢eqL.hü= ò-x¯'éy',ËŠ|Y9yòDþø²¦ë^À™¦Át'ì¿ïYÎï±y×Ç3,£$èù÷<8^Àwï ×ãiýùÙ?ÝwŠqîDZX–å´åÏîÜÆ€ç«/@5‘ïêÏïyÎÐWÐ,€¦càDùX#ï}çîð¤å¦T÷gS¹Ç4[-÷¯x¦ç)uÚîø<€^À$sŸq?ÞDˆ?"M{16ÁB¢ã ¾!mûbû„ó¬rhšÓ´a[Îø +éYsðH“š3&Ž+)ß•D³nþ”>§±q”†7íÏ(«õ”¿×XMskÏÐȈÊÿ[±‡V#µ\¿rÏ…÷×3¯WäL­ã`œûãÈî‘e/›´@ò§üδDƘ¯Øó#í%C0MÓñT„'!o Ù»>^oÍ“)0ÑNÐa²¯'áõ²¥tV˜´ÜÆ€?.8†[Gýå rȼ±Èl6Û’ûôü{Sêòs"X¦ î>ãMÑ Aè‹1+ùuž·-?e«kØ–»~Åõ5{u­œÉóŒ ÎyÁ8{±Œ„¨‹óx3¼&|£)•f Š.×¥žçUóDDÆ-G+YVÑ÷ˆèÏã–C¡P(íý9}/n)ZͲ3€ˆþZJ©Ò+ ŲG~…8ýuÜRÄÁ²4€sþ)~· …B¡ˆ ˆó%™æ·–­ º÷Ç-†B¡P(ZŒÄý º%n1âdYD$Àé‡#­H²ò[eÉŠ¶åÉ­]`~)å¤I…ÛÒ¥Áëè¿gÞVôuàõ‹öþ)ЍÐN· !µ‡Áé"ªï•^b,kˆè}já …B¡XŒ€ÑˆèTÜ‚ÄͲ7€ˆž£›˜qˢȣÍ<íF»zLŠ6Æ£›‰èù¸i”àBD÷CÒûã–C¡P(!éýD¤â¾\”iôÈÒ@’(Ü‘E›B¡ˆ åAY&Hº•4úIÜb´Ê(‚4ú€þ0n9 …Bô‡NÛ®ÈGe NÿПFWA­ž…¢ z¬ª'[êz-èO6]QŒ2*@œ¾Ðgã–C¡P(BŸuÚrE9”PâôE@~¡Ùr„ Æ „€”œsH! a,ú.ˆ” ò>8› çÜ‘K,z$,ËkÝãAŒÁ4Mèºî_'_ö8qëîõaîõ‚{M…ˆÞ“#lÛ¹RÔ',:×"ïÉQÁÿÅŸ½{DDÐ4 RJH! Ž‹ïùöþzÏ-c œs0Æ`ÛöâµófN´H>ÿ9‘Ìm¼ý¦iæ–'OØÏ}ñ¹æÝG¯ °, ‚mÛR:×±×(ï=¶ ]ׯ…×v5$‡ü‚Ó†+*¡ €ˆó¿ä_5Sã¶eÁ4MhšÛmЉ1Xfô3½zl÷÷^&Û¶1??Î9Èm$!% Ãp¾÷Žïè†t: ι#C‘Âk eMÓ?H ®iB —Í‚çŒsX¦é+Zá6ÐÍf#¯?ƈ¹\¦+§§>!Nž<é(~ÎÁ9/è(õ4Ù—ÂQæ¹\RJ$SLÓÄôô4R©Òé4Þ|ã HwŒÒ¶7¥'7E§ i,Ë‚mÛƒF §ÞFn!㸖íhÝÅ=‹âøƒ©©)Àôô4Nœ8á7˜ÞpŽçvŽD>Æœû4?ïì°f&§@D.q³ oøÔû}¤Ò9×orrš¦ajj o¼ñ†ÿ¼y]”xcئiúÊžsŽ\.‡+V`tt ò 7F!?†Á£øq!\@!t]Çøø8’É$fggqrxØošâóô> !0== !Nœ8y÷Ëÿ£¾š¦!“É •J!›Íbzz†a`zzÚo—ʇÿ½”µyëvÕó¯ƒ%½„HT|ç;ßúK>_ëñÙ¬ã6Ö4 “““èêêBww72GÁ±b+7d@Øðd"לñÚD"©©)pÎÑÓÓÓ4‘H$ løÿ·ÂBø d.—ƒ3ý8MÓBi€ë%ß`Œaff===þ÷Þxr6›E2™ŒT–L6 ]×!…€aàp ¬\¹²Ä€,6X“œ e»[###X¹r%t]÷{p]áÓž!&„@OO&''8Ï~2™tÆÝ=#×u;{ÆC>aÞ¸?w=%sssô¿ "Ìë—°é0;;‹þþ~?×ó.yñQã½Gä!ž>}ëÖ­óº $ð…[oýÈ_F.èCyàÖ[?ò—/½t8G@MÁžbaóæÍX¿~½ïÆ-iB6Üï©jšÝà0M xöÙg±}ûv¬^½ÚáiÈår0 à XlΨ¥'Ê9‡0-œ8q£££Ø·ozzz „€ñ{~£Xn:ÆK/½„Õ«WcýúõÆT2™D.—‹T>îz¼á;gbrr¦ibãÆX½zuÁñ­6ˆsssB`Ë–-X·n¿¿A€ž’²,Ëÿ_Ó4>|'OžÄùçŸï?KRÊ@þûWé1oÖ°,ËN›œœÄÑ£G±mÛ6 ø½Þj4«€½söþ÷Êô €'NÀ0 ìÛ·Ï7f5M«Ü>…Œgpx÷åôéÓ°, {öìÁ wH¢øøˆ>»{÷^íßÊhÝ»÷~QJ;)ÿ&èXoœ?•Jáèѣؼy36nÜè<øîxe ä¥Iiˆ0>>ާŸ~===عs§3FiYàÜ€ðÆ¶¥l¾~÷oÅfŒÈßN/éĉX¿~=‡†Ûn] @qCëÞ—‰‰ 9rƒƒƒØµk—{(ùr—xpBFÂéÕúcÙ8zä^~ùeìܹ«]…»xÅ4Ù€) )ý¡‘µk×bçgøcÇ­˜è!òºˆ0::Љ‰ lذƒƒƒ…±yq9þý«t™šßS¾BàÍ7ßÄóÏ?¡¡!ì<ã ¬½*a(`/š¾è³pÇÜOŸ>Í›7£¯¿V½î°ðî_þµxõÕW±råJlÙ²¥p s1DJÄÕ<ÿQ@ñ/I[¦ù÷ÕŽãþÔ#¯§BD pw1ò€¼Òì€Za^ì¯/¸pƒ¼Õò¨$$ˆ3ç7P“õ7#äôR5B&g¸鄼g¶JnÃb°””Ò½_îµ éD¸G= î<±¨ÜlI0m 6¯?ZìÕh>ˆ´ê×`¤Á¶Üë!ºž„‘Ž«#iKó¢Ö8wÏõ.$¹ß-öüIç·÷¯iñwœHƒ´¸Ö½ pn¸/aa%…ãõ!˜Ò•#ï³”¤óÙî<ß‚ ¹³¤¡2(Æ’1§ŸábD0-k1ÿþDHLeøk• IˆÓ?Ô³€PË’´5*¡¼F//°'‘ZBÊ·™ÚcxÖdñ= åþÅ{›¦Šrïìç;F$ݪÒû62B€4úHz/€ú³ú¨@mÁPqÑ6Y ËPI¦V*¯§]pb¼fíxŸ)º_Þ …åÙa¨Š IïU û„ƒ2B‚4ú ]`$nY:Žj=$…¢*)ÊŽR $k<Œ€ÑujIßðP@ˆÑý`t-€ÃqËÒ©»GÛÅ(©ÑZ¹ÖÄx<%[ð·h_Kh“g%ˆÊ™;Cþ˜8 F×Ñýq ²”P@ÈÑó`têA vèÁÅn„”¹í6Ž\î>ÅrïÚàZ”Pí:4œë~!q?$¢çãe©¡ € ¢Sàt„Ä- µ8óömþ¾¢ã£°05kþT®v#vc@Ñy,ó À’ö§Òæü6‰~NˆèT\ò/e”D$ˆ±›ù•¸eQ,MÚÝi™|Kaü_Q‚}…ˆÝLñjdËeD qþ)ýyÁ¾†×·nVZÜÊ}ç.Èá-0Ww[)¶r9ÇóöÇ)k«\ñÔ¾’©~qSA†JrzyÚBö<Ê=_Ë)ÿ|Ë–­ŸŠ[Œ¥Ž2Zÿk’ô»ˆm„2Ú Òød¼vZIDATèë`t$Å-‹B¡P4Ä!0ºˆ4úzÜ¢( Q@BDO’Æ.ä×â–E¡P(G~4v=·$ŠR”ÐÆ矄¤ÈÆ-‹B¡PÔA’>Fœ2nA•Q@›C}Œ.P³ EGàDù_@}#nQÕQ@@D/º³¾·, …BQùE7ÊÿŸ%Q£ €‚8ÿ,Ýàhܲ( EG!èFâü³q ¢¨et¤ÓÏÁè\@þshe9kª»cB´l½ùbY⨷Œ k²—[;>Žõä½uì[yªÕED¾LÅ×£-îcQp½Zül¼wîßÚïŸüg0:—túy4Ò)¢B-çI¿àtÜò,W–£‚kMÑœ†¤ß!Îÿ€ˆâFQ?Êè`H£ÛÁèl@~7nY–:JéÕŽç ˆÃC¢(O9·¿Á¿ Fg“F·7'™"N”ÐáÑ(qþ!Hú0‚ªãeW ¯¥Ì*)EçÑà}¤ç"¢Ñ°eR´e,H£ï€Ñ>@~«ôË¢±ÅZ_|eTe¹)ÂüóÍÿ_‹íO¹¡›ú‡sä·Àhiôp¥SÄ…2–D4Fœ’np¬ÖßUUdªqW¸ä+‹jÊDKŽct3qþQ"‹[Ex(` BýŒöòËǪÆ:O¹‘;3 _Ñ-‹ë—7#¢$Z¼è,‹ëÑiäß“¢Ù-ÁÈ/ƒÑ^Òè¡Ë¥ˆ-nÑ@D9Ÿ–Rþ;$¾àŠ& M®¶¬¿W~YÅ–?}2FZ¦t¦–ó ý.šЉ[¾VÜ?ïYÍû\µV‰Áé/ˆØýQ‹¦ˆe,qˆè~Wæ2¹Oë þ_tIáÌ#‚ifÁ9Á²rÐôàîFº[HÄ«K âXtN°Í,4`Q;ªÊ)ñÅX çZ hšæÊâìÂãÜÿ%Ä),wê·­I0’(Y=ºÕö¦•…npHØ“¶ƹ›O"Úû'¥ðï$À5‚-LçI€÷( ÿ‘’ÂŽF¾|e˼"!aC78,;Wø^µÂaÿ¹&–MgÒräa2 ÈÏ‘Æÿ6Zí€ò×-#zè¡ Bäþ«¡'>*„@&“Æ[o½…ÁÁA¬^½¹œ…D")%r¹inƒ­‚ó“Û‰ÉÉIŒŽŽbóæÍèêêröžÒü©léÙ9 £¿¿«V­Ó5!`LÓlIÿ±}â—5WªX(`óÒK‡ÿóã=öù]»v­Ú±cGICÄÈQ:Í)à ÊSjf&‹ááa;v çž{.†††œÆ=à)mVÁ15>C‡aûöíØ¼y3HãÐ4ÍïqzŠ%*lÛc ¶mûÆÒo¼Ã‡ã¼óÎÃÚµk«þ>jgš&¦§§ñÌ3Ï`Ïž=X·n]Aï:j‰W—÷.—ƒ”/¾ø"Nž<‰Ë/¿]]]¾âó  P6K¥r<™8çÁSO=…½{÷bóæÍ¾G£‘{Õ¨@Dc–ia݆ _­»RÅ’@Å,cvïÞûÕ¿û»¿û6ãÚçþ„Ü5¤ wl€”@Ó hÞï§çf1ŸYÀÊÕCòe¨F˜ ®à\Üÿ»“)<öØcèííźñÿ·ww1r•uÇ¿¿ç93}-´Jy vEË"AD#F#©A|«ÄxËÜ” b¸ñ†À½â‚ MŒÆÔ  FƒDÅ¢Ò"Di¬-miE«ÛÝÙ9çù{1gfg_ÚmwwöìÎþ?ÉIwgfÏùïÙÓóüÏÿyžs:cÆšMê6C y®WØ aÊ`Ã#GŽ0::Êš5kXÛÙO³tRÛopÒ¯f³ÉÊ•+9çÜs'<[¢ß H'ÉèŽÓ(cÛ·oû÷ïgõêÕ¬Y³f|LBOƒ›ÊJÀ|8îzz^ÏóœÑÑQV­ZźõëOnÅs<þ{«FÏ ¶²oI:zrA¸AäÓ—¹{î¹çèµ×^·Uy"Ùc@÷DieŸi¿yN*«fÖí†huc8Ñ2Ÿ¦[çððp·O›ž*I·±é3K‰f³ÙýÚR¢V«u»HúÀø€È û§ózY‚ïT'RQ´Ç*ô¹2Ò³ŒÐkP&ã©^¯O©BXJ}yØÎñŽÇVÙÒyÀV­V£V«a)}9e™× yL! )Ö¶zãï¼àP£± ø²YëÛß”ôññ«†qÍñÕm8ò‚"7, K¢–5¦N_Z(²2êõÓ"°$B»t› ÍqÿÌØ„K4Y{=Vöy "­±lnyüŒÛï¶÷Öýtû¿ýuJ iÔO'†Z9v$`©1¢>Ï’h5ÛƒìBˆ`í~ýT´¥ÖXB†Dg0e9u‘È âNݤ_·V; R‘h޶Ú/ H1i|¿ÎÆÌ?)$ûÒ zvÖrÇ+n©ö¬‚nÁ´EÒ« 1G¹s”R¢ÑhÐl6»7ÝÉ[­þWz¯{×[.õzáááökå²Þ+â~Ë[- ,W‡@(Çäy¾`Uˆéôa;v¬ ”߇¾Oßl«Õëíª•Y·BbìÎì”ÀËo&tô³‚Ò9ŽRQŠ¢]©(¶zþ¦Óêܰgîñ½Jb‹B¸EòÆßMä €›–2mW WcÜìéç¶b–aeÿmgêXç„Ý)sŸh™³I÷µŸ|·»<Ï©×ëí˜:ñ°2‘•åâcw›í+Þþ`‡ñ$gº;þõ&a1¶gôÞ?aAöQ™¨M>ò<Ÿ8Q,ÀÔÿä­OèT‹ºá¶gu0ÓÀ¹uìÝ¥®ö'ö¹ãñÀ¢U —€¶oWsî„ÞmU —(êѪƒq‹›'î¤(jAA÷1Óc‡OyååÙ¤¥óú²7ygoqÓ°ýstAµ­ê`ÜÒà €;i’ E=DÐùe"p ê˜œ[æ” ÿùŠzHÒÂß5Ë-Yž¸S&©U&Ê®·f³ž»s‹˜©œD18ÇÛ[ ­m(þVÕ¹¥Ç7k’’¢¶)†‹@w¯U“s½¨Áïx­Üw‘¢¶Iý~R—dž¸yQÜ„i Æ‹ó±Î fÿ»ehIT¢Œ1mQ ›|pŸ›/ž¸y¥LÛ•…›HºñdÕñ¸åMK=‹O’t«²p“OçsóÍתéY…p;AC`Í)Ÿ±òmÓŸ¨ÏEY*—SUÙŸ«öÓ”­ÚÄeé›å~Tj/$d©½–žý1ó~š§¿ß©kbPqXÎ͇WAÛ?¸ðâ ÷VŒsž¸Eehhh/ð ð ™Ýhf_ú°®âМ;‡À#„Jz©ê`œ›Ž'nÑ*Oœ/w[n›Qú"è Ài‡æÜtFÁžÀ”ɻ³Ü¢çcÜ’ L;ã‰i âq ¯:.·ìåˆÇ1m!èLÅx§7þn©ð €[R$Ûífv:ŸGi3è6`EÅá¹åáØÓXØAäÇ’FªȹÙðÀ-Y剷“  nCés ÏçUž,ûÁ~Š…ŸyZ þ·äyàBùT´å‚™ÝHJŸÁôiĵÕFç–$ãˆgú™äsƒÈ7zÞof)¸¥O> œ]qxnq: ö ,ŠìàÃø€Â¥IìúðÛø÷ã;7‘'ÎMÒ3~€ƒ^êÙõŠºÎd× »Æ,­”²ž?íCæO™¥„B !FŠVŽ j1;Á³ìçB3ÌÆ7dfHj¿äyŽ$Š¢˜øžÍGp'^GJ‰ã0*^½¢Âþ€š¿¿þúvÏÃÆXž87ƒõë×ïvÓžr€™m>„éƒÈ®Æ¢O·+63¬((Ê ffÆèèè„F¹ß$u·'§>©(ˆ1’eFI¤¢è~®÷³óäb'fÁŸCÿ$i×|oĹAç €s³P68»€ïw^3³ äl"ð~HWaºq%pÖ\¶bìþÛ©dYF¡ëTe£?]3B˜ÃÃôZ­ 1÷þü,ÁxÙþJâ52vIÚ7Û:çÆyàÜ<)¦}À3½¯›Ùzà àr——"..æ$¦$vJÿ˜‘ç9YÖþoc$Æ ‘ÀÔîŽr»©(ȲŒZ­F­V KiJ7Áqö`ìvxø;ð7Iûðk8çJž8×geCvxaò{fvc\H,.@Ú˜ç#6‡ìŒsBŒëRQB V¯066FžçäyŽ¥þÞ”®·ô?)x$µ+å±±±öë! 8d–X²†íÇØÿÄl/EüuÞ’t´¯Á;çŽËç*T6€;ËeZfFÞ]Ç ÖšÙÙÅYy«X³rõª÷ŽŒŒ¾gddôLag¶Zh•a+@+ NWûɉ  Ž¨ad@¤ý °ÎE½ (9F 𣂰cBÇ ûŸÐ •ì?)ñoKù»#džÿUkÔ4[c‡ß9røµk×*ïÎèœ[¤þ2qqÌØ J IEND®B`‚osmose-emulator-1.4/src/osmose-emulator.svg000066400000000000000000003672521341430144300211700ustar00rootroot00000000000000 Osmose Emulator image/svg+xml Osmose Emulator 06-04-2017 Carlos Donizete Froes [a.k.a coringao] Sega Master System and Game Gear console emulator Osmose