From c3ef85490a895d5a4b9d5105ef7ca750c7c843cd Mon Sep 17 00:00:00 2001 From: Marco Maccaferri Date: Wed, 26 Dec 2018 09:12:35 +0100 Subject: [PATCH] Added Z80 core emulator --- LICENSE.z80core | 678 ++++ build.xml | 1 + src/z80core/MemIoOps.java | 106 + src/z80core/NotifyOps.java | 14 + src/z80core/Z80.java | 6464 ++++++++++++++++++++++++++++++++++++ src/z80core/Z80State.java | 418 +++ 6 files changed, 7681 insertions(+) create mode 100644 LICENSE.z80core create mode 100644 src/z80core/MemIoOps.java create mode 100644 src/z80core/NotifyOps.java create mode 100644 src/z80core/Z80.java create mode 100644 src/z80core/Z80State.java diff --git a/LICENSE.z80core b/LICENSE.z80core new file mode 100644 index 0000000..e4e004d --- /dev/null +++ b/LICENSE.z80core @@ -0,0 +1,678 @@ +**Copyright © 2008-2015 José Luis Sánchez** + +#### The GNU GPL LICENSE (GPLv3) + + 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. + + + Copyright (C) + + 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: + + Copyright (C) + 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 +. diff --git a/build.xml b/build.xml index 1f84965..c1b718a 100644 --- a/build.xml +++ b/build.xml @@ -233,6 +233,7 @@ + diff --git a/src/z80core/MemIoOps.java b/src/z80core/MemIoOps.java new file mode 100644 index 0000000..64096fb --- /dev/null +++ b/src/z80core/MemIoOps.java @@ -0,0 +1,106 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package z80core; + +/** + * + * @author jsanchez + */ +public class MemIoOps { + private byte z80Ram[] = null; + private byte z80Ports[] = null; + private long tstates = 0; + + public MemIoOps() { + z80Ram = new byte[0x10000]; + z80Ports = new byte[0x10000]; + } + + public MemIoOps(int ramSize, int portSize) { + if (ramSize < 0 || ramSize > 0x10000) + throw new IndexOutOfBoundsException("ramSize Out of Range [0x0000 - 0x10000"); + + if (ramSize > 0) { + z80Ram = new byte[ramSize]; + } + + if (portSize < 0 || portSize > 0x10000) + throw new IndexOutOfBoundsException("portSize Out of Range [0x0000 - 0x10000"); + + if (portSize > 0) { + z80Ports = new byte[portSize]; + } + } + + public void setRam(byte ram[]) { + z80Ram = ram; + } + + public void setPorts(byte ports[]) { + z80Ram = ports; + } + + public int fetchOpcode(int address) { + // 3 clocks to fetch opcode from RAM and 1 execution clock + tstates += 4; + return z80Ram[address] & 0xff; + } + + public int peek8(int address) { + tstates += 3; // 3 clocks for read byte from RAM + return z80Ram[address] & 0xff; + } + + public void poke8(int address, int value) { + tstates += 3; // 3 clocks for write byte to RAM + z80Ram[address] = (byte)value; + } + + public int peek16(int address) { + int lsb = peek8(address); + int msb = peek8(address + 1); + return (msb << 8) | lsb; + } + + public void poke16(int address, int word) { + poke8(address, word); + poke8(address + 1, word >>> 8); + } + + public int inPort(int port) { + tstates += 4; // 4 clocks for read byte from bus + return z80Ports[port] & 0xff; + } + + public void outPort(int port, int value) { + tstates += 4; // 4 clocks for write byte to bus + z80Ports[port] = (byte)value; + } + + public void addressOnBus(int address, int tstates) { + // Additional clocks to be added on some instructions + // Not to be changed, really. + this.tstates += tstates; + } + + public void interruptHandlingTime(int tstates) { + // Additional clocks to be added on INT & NMI + // Not to be changed, really. + this.tstates += tstates; + } + + public boolean isActiveINT() { + return false; + } + + public long getTstates() { + return tstates; + } + + public void reset() { + tstates = 0; + } +} diff --git a/src/z80core/NotifyOps.java b/src/z80core/NotifyOps.java new file mode 100644 index 0000000..6c3a5ae --- /dev/null +++ b/src/z80core/NotifyOps.java @@ -0,0 +1,14 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package z80core; + +/** + * + * @author jsanchez + */ +public interface NotifyOps { + int breakpoint(int address, int opcode); + void execDone(); +} diff --git a/src/z80core/Z80.java b/src/z80core/Z80.java new file mode 100644 index 0000000..57a160c --- /dev/null +++ b/src/z80core/Z80.java @@ -0,0 +1,6464 @@ +//----------------------------------------------------------------------------- +//Title: Emulador en Java de un Sinclair ZX Spectrum 48K +//Version: 1.0 B +//Copyright: Copyright (c) 2004 +//Author: Alberto Sánchez Terrén +//Clase: Z80.java +//Descripción: La clase Z80 es la más extensa de todas ya que debe implementar +// la estructura del microprocesador Z80 y la ejecuci�n de todas +// las instrucciones del repertorio del mismo. +//----------------------------------------------------------------------------- +/* + * Versión: 2.0 + * Autor: José Luis Sánchez Villanueva + * + * Notas: 09/01/2008 pasa los 68 tests de ZEXALL, con lo que se supone + * que realiza una implementación correcta de la Z80. + * + * 14/01/2008 pasa también los tests de fuse 0.10, exceptuando + * los que fuse no implementa bien (BIT n,(HL)). + * Del resto, cumple con los contenidos de los registros, flags, + * y t-estados. + * + * 15/01/2008 faltaban los flags de las instrucciones IN r,(C). + * + * 03/12/2008 se descomponen las instrucciones para poder + * implementar la contended-memory del Spectrum. + * + * 21/09/2009 modificación a lo bestia del emulador. Los flags + * se convierten de boolean a bits en un int. El único + * que se deja como estaba es el carryFlag. Ahora los + * flags se sacan de tablas precalculadas. + * + * 22/09/2009 Optimizado el tratamiento del HALFCARRY_FLAG en los + * métodos add16/add/sub/cp. + * + * 23/09/2009 Los métodos de más 8000 bytecodes no son compilados + * por el JIT a menos que se obliguemos a ello, cosa poco aconsejable. + * El método decodeDDFDCD original tenía más de 12000 bytecodes, así que + * se subdivide en 2 métodos que procesan los códigos por rangos: + * 0x00-0x7F y 0x80-0xFF quedando todos por debajo de los 7000 bytecodes. + * + * 25/09/2009 Se completa la emulación del registro interno MEMPTR. + * Ahora el core-Z80 supera todos los test de MEMPTR del z80tests.tap. + * (http://homepage.ntlworld.com/mark.woodmass/z80tests.tap) + * Mis agradecimientos a "The Woodster" por el programa, a Boo-boo que + * investigo el funcionamiento de MEMPTR y a Vladimir Kladov por + * traducir al inglés el documento original. + * + * 02/10/2009 Se modifica el core para que soporte el retriggering de + * interrupciones, cosa que en realidad, estaba pensada desde el + * principio. + * + * 28/03/2010 Se corrige un problema con el manejo de las interrupciones. + * Para ello es necesario introducir el flag 'halted'. El problema surgía + * únicamente cuando la INT se producía cuando la instrucción a la que + * apunta PC es un HALT pero éste aún no se ha ejecutado. En ese caso, + * el HALT se ejecutará a la vuelta de la interrupción. Hasta ahora, + * la dirección de retorno de la INT que se guardaba en el stack era la + * de PC+1 como si el HALT ya se hubiera ejecutado, cuando esto último + * era falso. Gracias a Woodster por el programa de test y por informarme + * del fallo. Thanks!, Woodster. :) + * Creo también los métodos isHalted/setHalted para acceder al flag. De paso, + * duplico el método push para que tenga dos parámetros y poder usarla así + * con los registros de propósito general, para que sea más rápido. + * + * 23/08/2010 Increíble!. Después de tanto tiempo, aún he tenido que + * corregir la instrucción LD SP, IX(IY) que realizaba los 2 estados de + * contención sobre PC en lugar de sobre IR que es lo correcto. De paso + * he verificado que todos los usos de getRegIR() son correctos. + * + * 29/05/2011 Corregida la inicialización de los registros dependiendo + * de si es por un reset a través de dicho pin o si es por inicio de + * alimentación al chip. + * + * 04/06/2011 Creados los métodos de acceso al registro oculto MEMPTR + * para que puedar cargarse/guardarse en los snapshots de tipo SZX. + * + * 06/06/2011 Pequeñas optimizaciones en LDI/LDD y CPI/CPD. Se eliminan + * los métodos set/reset porque, al no afectar a los flags, es más + * rápido aplicar la operación lógica con la máscara donde proceda que + * llamar a un método pasándole dos parámetros. Se elimina también el + * método EXX y su código se pone en el switch principal. + * + * 07/06/2011 En las instrucciones INC/DEC (HL) el estado adicional + * estaba mal puesto, ya que va después del read y no antes. Corregido. + * + * 04/07/2011 Se elimina el método push añadido el 28/03/2010 y se usa + * el que queda en todos los casos. El código de RETI se unifica con + * RETN y sus códigos duplicados. Ligeras modificaciones en DJNZ y en + * LDI/LDD/CPI/CPD. Se optimiza el tratamiento del registro MEMPTR. + * + * 11/07/2011 Se optimiza el tratamiento del carryFlag en las instrucciones + * SUB/SBC/SBC16/CP. Se optimiza el tratamiento del HalfCarry en las + * instruciones ADC/ADC16/SBC/SBC16. + * + * 25/09/2011 Introducidos los métodos get/setTimeout. De esa forma, + * además de recibir una notificación después de cada instrucción ejecutada + * se puede recibir tras N ciclos. En cualquier caso, execDone será llamada + * con el número de ciclos ejecutados, sea tras una sola instrucción o tras + * expirar el timeout programado. Si hay un timeout, éste seguirá vigente + * hasta que se programe otro o se ponga a false execDone. Si el timeout + * se programa a cero, se llamará a execDone tras cada instrucción. + * + * 08/10/2011 En los métodos xor, or y cp se aseguran de que valores > 0xff + * pasados como parámetro no le afecten. + * + * 11/10/2011 Introducida la nueva funcionalidad que permite definir + * breakpoints. Cuando se va a ejecutar el opcode que está en esa dirección + * se llama al método atAddress. Se separan en dos interfaces las llamadas a + * los accesos a memoria de las llamadas de notificación. + * + * 13/10/2011 Corregido un error en la emulación de las instrucciones + * DD/FD que no van seguidas de un código de instrucción adecuado a IX o IY. + * Tal y como se trataban hasta ahora, se comprobaban las interrupciones entre + * el/los códigos DD/FD y el código de instrucción que le seguía. + * + * 02/12/2011 Creados los métodos necesarios para poder grabar y cargar el + * estado de la CPU de una sola vez a través de la clase Z80State. Los modos + * de interrupción pasan a estar en una enumeración. Se proporcionan métodos de + * acceso a los registros alternativos de 8 bits. + * + * 03/06/2012 Eliminada la adición del 25/09/2011. El núcleo de la Z80 no tiene + * que preocuparse por timeouts ni zarandajas semejantes. Eso ahora es + * responsabilidad de la clase Clock. Se mantiene la funcionalidad del execDone + * por si fuera necesario en algún momento avisar tras cada ejecución de + * instrucción (para un depurador, por ejemplo). + * + * 10/12/2012 Actualizada la emulación con las últimas investigaciones llevadas a + * cabo por Patrik Rak, respecto al comportamiento de los bits 3 y 5 del registro F + * en las instrucciones CCF/SCF. Otro de los tests de Patrik demuestra que, además, + * la emulación de MEMPTR era incompleta (por no estar completamente descrita). + * El comportamiento coincide con el de un Z80 de Zilog, no con los clónicos NEC. + * + * 25/01/2018 Una secuencia potencialmente infinita de DD/FD acaba por provocar un + * error de Stack Overflow. Se modifica el core para que se trate como lo que es, + * un prefijo del código que viene detrás. + * Se cambia también el lugar de comprobación de la INT a donde corresponde, el final + * de la ejecución de la instrucción. + * La activación de INT depende ahora de Clock, no del Spectrum en sí mismo. + * + * 27/01/2018 Generalizo la solución de los prefijos para que se pueda aplicar también a + * CB y ED. Se elimina el miembro opCode y se convierte en variable local. + * + * 27/01/2018 (reloaded) Estrictamente hablando, al final del ciclo de máquina de la + * instrucción se comprueban, por este orden, BUSRQ, NMI e INT. La primera no la + * emulamos y la segunda, si la movemos a su sitio, nos ahorramos una comparación. + * Se reorganizan también las comparaciones de la INT, así solo se llama al método de Clock + * si las interrupciones están habilitadas y no hay pendiente un EI. + * + * 29/01/2018 CB es el único prefijo de instrucción cuyo byte siguiente produce SIEMPRE un + * código de instrucción válido, de modo que no merece la pena dividirlo en dos y es mejor + * que se ejecute como una unidad indivisible. + */ +package z80core; + +import java.util.Arrays; + +public class Z80 { + + private MemIoOps MemIoImpl; + private NotifyOps NotifyImpl; + // Se está ejecutando una instrucción DDXX, EDXX o FDXX + // Solo puede (debería) contener uno de 4 valores [0x00, 0xDD, 0xED, 0xFD] + private int prefixOpcode = 0x00; + // Subsistema de notificaciones + private boolean execDone = false; + // Posiciones de los flags + private static final int CARRY_MASK = 0x01; + private static final int ADDSUB_MASK = 0x02; + private static final int PARITY_MASK = 0x04; + private static final int OVERFLOW_MASK = 0x04; // alias de PARITY_MASK + private static final int BIT3_MASK = 0x08; + private static final int HALFCARRY_MASK = 0x10; + private static final int BIT5_MASK = 0x20; + private static final int ZERO_MASK = 0x40; + private static final int SIGN_MASK = 0x80; + // Máscaras de conveniencia + private static final int FLAG_53_MASK = BIT5_MASK | BIT3_MASK; + private static final int FLAG_SZ_MASK = SIGN_MASK | ZERO_MASK; + private static final int FLAG_SZHN_MASK = FLAG_SZ_MASK | HALFCARRY_MASK | ADDSUB_MASK; + private static final int FLAG_SZP_MASK = FLAG_SZ_MASK | PARITY_MASK; + private static final int FLAG_SZHP_MASK = FLAG_SZP_MASK | HALFCARRY_MASK; + // Acumulador y resto de registros de 8 bits + private int regA, regB, regC, regD, regE, regH, regL; + // Flags sIGN, zERO, 5, hALFCARRY, 3, pARITY y ADDSUB (n) + private int sz5h3pnFlags; + // El flag Carry es el único que se trata aparte + private boolean carryFlag; + /* Flags para indicar la modificación del registro F en la instrucción actual + * y en la anterior. + * Son necesarios para emular el comportamiento de los bits 3 y 5 del + * registro F con las instrucciones CCF/SCF. + * + * http://www.worldofspectrum.org/forums/showthread.php?t=41834 + * http://www.worldofspectrum.org/forums/showthread.php?t=41704 + * + * Thanks to Patrik Rak for his tests and investigations. + */ + private boolean flagQ, lastFlagQ; + // Acumulador alternativo y flags -- 8 bits + private int regAx; + private int regFx; + // Registros alternativos + private int regBx, regCx, regDx, regEx, regHx, regLx; + // Registros de propósito específico + // *PC -- Program Counter -- 16 bits* + private int regPC; + // *IX -- Registro de índice -- 16 bits* + private int regIX; + // *IY -- Registro de índice -- 16 bits* + private int regIY; + // *SP -- Stack Pointer -- 16 bits* + private int regSP; + // *I -- Vector de interrupción -- 8 bits* + private int regI; + // *R -- Refresco de memoria -- 7 bits* + private int regR; + // *R7 -- Refresco de memoria -- 1 bit* (bit superior de R) + private boolean regRbit7; + //Flip-flops de interrupción + private boolean ffIFF1 = false; + private boolean ffIFF2 = false; + // EI solo habilita las interrupciones DESPUES de ejecutar la + // siguiente instrucción (excepto si la siguiente instrucción es un EI...) + private boolean pendingEI = false; + // Estado de la línea NMI + private boolean activeNMI = false; + // Si está activa la línea INT + // En el 48 y los +2a/+3 la línea INT se activa durante 32 ciclos de reloj + // En el 128 y +2, se activa 36 ciclos de reloj + private boolean activeINT = false; + // Modos de interrupción + public enum IntMode { IM0, IM1, IM2 }; + // Modo de interrupción + private IntMode modeINT = IntMode.IM0; + // halted == true cuando la CPU está ejecutando un HALT (28/03/2010) + private boolean halted = false; + // pinReset == true, se ha producido un reset a través de la patilla + private boolean pinReset = false; + /* + * Registro interno que usa la CPU de la siguiente forma + * + * ADD HL,xx = Valor del registro H antes de la suma + * LD r,(IX/IY+d) = Byte superior de la suma de IX/IY+d + * JR d = Byte superior de la dirección de destino del salto + * + * 04/12/2008 No se vayan todavía, aún hay más. Con lo que se ha + * implementado hasta ahora parece que funciona. El resto de + * la historia está contada en: + * http://zx.pk.ru/attachment.php?attachmentid=2989 + * + * 25/09/2009 Se ha completado la emulación de MEMPTR. A señalar que + * no se puede comprobar si MEMPTR se ha emulado bien hasta + * que no se emula el comportamiento del registro en las + * instrucciones CPI y CPD. Sin ello, todos los tests de + * z80tests.tap fallarán aunque se haya emulado bien al + * registro en TODAS las otras instrucciones. + * Shit yourself, little parrot. + */ + private int memptr; + + /* Algunos flags se precalculan para un tratamiento más rápido + * Concretamente, SIGN, ZERO, los bits 3, 5, PARITY y ADDSUB: + * sz53n_addTable tiene el ADDSUB flag a 0 y paridad sin calcular + * sz53pn_addTable tiene el ADDSUB flag a 0 y paridad calculada + * sz53n_subTable tiene el ADDSUB flag a 1 y paridad sin calcular + * sz53pn_subTable tiene el ADDSUB flag a 1 y paridad calculada + * El resto de bits están a 0 en las cuatro tablas lo que es + * importante para muchas operaciones que ponen ciertos flags a 0 por real + * decreto. Si lo ponen a 1 por el mismo método basta con hacer un OR con + * la máscara correspondiente. + */ + private static final int sz53n_addTable[] = new int[256]; + private static final int sz53pn_addTable[] = new int[256]; + private static final int sz53n_subTable[] = new int[256]; + private static final int sz53pn_subTable[] = new int[256]; + + static { + boolean evenBits; + + for (int idx = 0; idx < 256; idx++) { + if (idx > 0x7f) { + sz53n_addTable[idx] |= SIGN_MASK; + } + + evenBits = true; + for (int mask = 0x01; mask < 0x100; mask <<= 1) { + if ((idx & mask) != 0) { + evenBits = !evenBits; + } + } + + sz53n_addTable[idx] |= (idx & FLAG_53_MASK); + sz53n_subTable[idx] = sz53n_addTable[idx] | ADDSUB_MASK; + + if (evenBits) { + sz53pn_addTable[idx] = sz53n_addTable[idx] | PARITY_MASK; + sz53pn_subTable[idx] = sz53n_subTable[idx] | PARITY_MASK; + } else { + sz53pn_addTable[idx] = sz53n_addTable[idx]; + sz53pn_subTable[idx] = sz53n_subTable[idx]; + } + } + + sz53n_addTable[0] |= ZERO_MASK; + sz53pn_addTable[0] |= ZERO_MASK; + sz53n_subTable[0] |= ZERO_MASK; + sz53pn_subTable[0] |= ZERO_MASK; + } + + // Un true en una dirección indica que se debe notificar que se va a + // ejecutar la instrucción que está en esa direción. + private final boolean breakpointAt[] = new boolean[65536]; + + // Constructor de la clase + public Z80(MemIoOps memory, NotifyOps notify) { + MemIoImpl = memory; + NotifyImpl = notify; + execDone = false; + Arrays.fill(breakpointAt, false); + reset(); + } + + public void setMemIoHandler(MemIoOps memIo) { + MemIoImpl = memIo; + } + + public void setNotifyHandler(NotifyOps notify) { + NotifyImpl = notify; + } + + // Acceso a registros de 8 bits + public final int getRegA() { + return regA; + } + + public final void setRegA(int value) { + regA = value & 0xff; + } + + public final int getRegB() { + return regB; + } + + public final void setRegB(int value) { + regB = value & 0xff; + } + + public final int getRegC() { + return regC; + } + + public final void setRegC(int value) { + regC = value & 0xff; + } + + public final int getRegD() { + return regD; + } + + public final void setRegD(int value) { + regD = value & 0xff; + } + + public final int getRegE() { + return regE; + } + + public final void setRegE(int value) { + regE = value & 0xff; + } + + public final int getRegH() { + return regH; + } + + public final void setRegH(int value) { + regH = value & 0xff; + } + + public final int getRegL() { + return regL; + } + + public final void setRegL(int value) { + regL = value & 0xff; + } + + // Acceso a registros alternativos de 8 bits + public final int getRegAx() { + return regAx; + } + + public final void setRegAx(int value) { + regAx = value & 0xff; + } + + public final int getRegFx() { + return regFx; + } + + public final void setRegFx(int value) { + regFx = value & 0xff; + } + + public final int getRegBx() { + return regBx; + } + + public final void setRegBx(int value) { + regBx = value & 0xff; + } + + public final int getRegCx() { + return regCx; + } + + public final void setRegCx(int value) { + regCx = value & 0xff; + } + + public final int getRegDx() { + return regDx; + } + + public final void setRegDx(int value) { + regDx = value & 0xff; + } + + public final int getRegEx() { + return regEx; + } + + public final void setRegEx(int value) { + regEx = value & 0xff; + } + + public final int getRegHx() { + return regHx; + } + + public final void setRegHx(int value) { + regHx = value & 0xff; + } + + public final int getRegLx() { + return regLx; + } + + public final void setRegLx(int value) { + regLx = value & 0xff; + } + + // Acceso a registros de 16 bits + public final int getRegAF() { + return (regA << 8) | (carryFlag ? sz5h3pnFlags | CARRY_MASK : sz5h3pnFlags); + } + + public final void setRegAF(int word) { + regA = (word >>> 8) & 0xff; + + sz5h3pnFlags = word & 0xfe; + carryFlag = (word & CARRY_MASK) != 0; + } + + public final int getRegAFx() { + return (regAx << 8) | regFx; + } + + public final void setRegAFx(int word) { + regAx = (word >>> 8) & 0xff; + regFx = word & 0xff; + } + + public final int getRegBC() { + return (regB << 8) | regC; + } + + public final void setRegBC(int word) { + regB = (word >>> 8) & 0xff; + regC = word & 0xff; + } + + private void incRegBC() { + if (++regC < 0x100) { + return; + } + + regC = 0; + + if (++regB < 0x100) { + return; + } + + regB = 0; + } + + private void decRegBC() { + if (--regC >= 0) { + return; + } + + regC = 0xff; + + if (--regB >= 0) { + return; + } + + regB = 0xff; + } + + public final int getRegBCx() { + return (regBx << 8) | regCx; + } + + public final void setRegBCx(int word) { + regBx = (word >>> 8) & 0xff; + regCx = word & 0xff; + } + + public final int getRegDE() { + return (regD << 8) | regE; + } + + public final void setRegDE(int word) { + regD = (word >>> 8) & 0xff; + regE = word & 0xff; + } + + private void incRegDE() { + if (++regE < 0x100) { + return; + } + + regE = 0; + + if (++regD < 0x100) { + return; + } + + regD = 0; + } + + private void decRegDE() { + if (--regE >= 0) { + return; + } + + regE = 0xff; + + if (--regD >= 0) { + return; + } + + regD = 0xff; + } + + public final int getRegDEx() { + return (regDx << 8) | regEx; + } + + public final void setRegDEx(int word) { + regDx = (word >>> 8) & 0xff; + regEx = word & 0xff; + } + + public final int getRegHL() { + return (regH << 8) | regL; + } + + public final void setRegHL(int word) { + regH = (word >>> 8) & 0xff; + regL = word & 0xff; + } + + /* Las funciones incRegXX y decRegXX están escritas pensando en que + * puedan aprovechar el camino más corto aunque tengan un poco más de + * código (al menos en bytecodes lo tienen) + */ + private void incRegHL() { + if (++regL < 0x100) { + return; + } + + regL = 0; + + if (++regH < 0x100) { + return; + } + + regH = 0; + } + + private void decRegHL() { + if (--regL >= 0) { + return; + } + + regL = 0xff; + + if (--regH >= 0) { + return; + } + + regH = 0xff; + } + + public final int getRegHLx() { + return (regHx << 8) | regLx; + } + + public final void setRegHLx(int word) { + regHx = (word >>> 8) & 0xff; + regLx = word & 0xff; + } + + // Acceso a registros de propósito específico + public final int getRegPC() { + return regPC; + } + + public final void setRegPC(int address) { + regPC = address & 0xffff; + } + + public final int getRegSP() { + return regSP; + } + + public final void setRegSP(int word) { + regSP = word & 0xffff; + } + + public final int getRegIX() { + return regIX; + } + + public final void setRegIX(int word) { + regIX = word & 0xffff; + } + + public final int getRegIY() { + return regIY; + } + + public final void setRegIY(int word) { + regIY = word & 0xffff; + } + + public final int getRegI() { + return regI; + } + + public final void setRegI(int value) { + regI = value & 0xff; + } + + public final int getRegR() { + return regRbit7 ? (regR & 0x7f) | SIGN_MASK : regR & 0x7f; + } + + public final void setRegR(int value) { + regR = value & 0x7f; + regRbit7 = (value > 0x7f); + } + + public final int getPairIR() { + if (regRbit7) { + return (regI << 8) | ((regR & 0x7f) | SIGN_MASK); + } + return (regI << 8) | (regR & 0x7f); + } + + // Acceso al registro oculto MEMPTR + public final int getMemPtr() { + return memptr & 0xffff; + } + + public final void setMemPtr(int word) { + memptr = word & 0xffff; + } + + // Acceso a los flags uno a uno + public final boolean isCarryFlag() { + return carryFlag; + } + + public final void setCarryFlag(boolean state) { + carryFlag = state; + } + + public final boolean isAddSubFlag() { + return (sz5h3pnFlags & ADDSUB_MASK) != 0; + } + + public final void setAddSubFlag(boolean state) { + if (state) { + sz5h3pnFlags |= ADDSUB_MASK; + } else { + sz5h3pnFlags &= ~ADDSUB_MASK; + } + } + + public final boolean isParOverFlag() { + return (sz5h3pnFlags & PARITY_MASK) != 0; + } + + public final void setParOverFlag(boolean state) { + if (state) { + sz5h3pnFlags |= PARITY_MASK; + } else { + sz5h3pnFlags &= ~PARITY_MASK; + } + } + + public final boolean isBit3Flag() { + return (sz5h3pnFlags & BIT3_MASK) != 0; + } + + public final void setBit3Fag(boolean state) { + if (state) { + sz5h3pnFlags |= BIT3_MASK; + } else { + sz5h3pnFlags &= ~BIT3_MASK; + } + } + + public final boolean isHalfCarryFlag() { + return (sz5h3pnFlags & HALFCARRY_MASK) != 0; + } + + public final void setHalfCarryFlag(boolean state) { + if (state) { + sz5h3pnFlags |= HALFCARRY_MASK; + } else { + sz5h3pnFlags &= ~HALFCARRY_MASK; + } + } + + public final boolean isBit5Flag() { + return (sz5h3pnFlags & BIT5_MASK) != 0; + } + + public final void setBit5Flag(boolean state) { + if (state) { + sz5h3pnFlags |= BIT5_MASK; + } else { + sz5h3pnFlags &= ~BIT5_MASK; + } + } + + public final boolean isZeroFlag() { + return (sz5h3pnFlags & ZERO_MASK) != 0; + } + + public final void setZeroFlag(boolean state) { + if (state) { + sz5h3pnFlags |= ZERO_MASK; + } else { + sz5h3pnFlags &= ~ZERO_MASK; + } + } + + public final boolean isSignFlag() { + return sz5h3pnFlags >= SIGN_MASK; + } + + public final void setSignFlag(boolean state) { + if (state) { + sz5h3pnFlags |= SIGN_MASK; + } else { + sz5h3pnFlags &= ~SIGN_MASK; + } + } + + // Acceso a los flags F + public final int getFlags() { + return carryFlag ? sz5h3pnFlags | CARRY_MASK : sz5h3pnFlags; + } + + public final void setFlags(int regF) { + sz5h3pnFlags = regF & 0xfe; + + carryFlag = (regF & CARRY_MASK) != 0; + } + + // Acceso a los flip-flops de interrupción + public final boolean isIFF1() { + return ffIFF1; + } + + public final void setIFF1(boolean state) { + ffIFF1 = state; + } + + public final boolean isIFF2() { + return ffIFF2; + } + + public final void setIFF2(boolean state) { + ffIFF2 = state; + } + + public final boolean isNMI() { + return activeNMI; + } + + public final void setNMI(boolean nmi) { + activeNMI = nmi; + } + + // La línea de NMI se activa por impulso, no por nivel + public final void triggerNMI() { + activeNMI = true; + } + + // La línea INT se activa por nivel + public final boolean isINTLine() { + return activeINT; + } + + public final void setINTLine(boolean intLine) { + activeINT = intLine; + } + + //Acceso al modo de interrupción + public final IntMode getIM() { + return modeINT; + } + + public final void setIM(IntMode mode) { + modeINT = mode; + } + + public final boolean isHalted() { + return halted; + } + + public void setHalted(boolean state) { + halted = state; + } + + public void setPinReset() { + pinReset = true; + } + + public final boolean isPendingEI() { + return pendingEI; + } + + public final void setPendingEI(boolean state) { + pendingEI = state; + } + + public final Z80State getZ80State() { + Z80State state = new Z80State(); + state.setRegA(regA); + state.setRegF(getFlags()); + state.setRegB(regB); + state.setRegC(regC); + state.setRegD(regD); + state.setRegE(regE); + state.setRegH(regH); + state.setRegL(regL); + state.setRegAx(regAx); + state.setRegFx(regFx); + state.setRegBx(regBx); + state.setRegCx(regCx); + state.setRegDx(regDx); + state.setRegEx(regEx); + state.setRegHx(regHx); + state.setRegLx(regLx); + state.setRegIX(regIX); + state.setRegIY(regIY); + state.setRegSP(regSP); + state.setRegPC(regPC); + state.setRegI(regI); + state.setRegR(getRegR()); + state.setMemPtr(memptr); + state.setHalted(halted); + state.setIFF1(ffIFF1); + state.setIFF2(ffIFF2); + state.setIM(modeINT); + state.setINTLine(activeINT); + state.setPendingEI(pendingEI); + state.setNMI(activeNMI); + state.setFlagQ(lastFlagQ); + return state; + } + + public final void setZ80State(Z80State state) { + regA = state.getRegA(); + setFlags(state.getRegF()); + regB = state.getRegB(); + regC = state.getRegC(); + regD = state.getRegD(); + regE = state.getRegE(); + regH = state.getRegH(); + regL = state.getRegL(); + regAx = state.getRegAx(); + regFx = state.getRegFx(); + regBx = state.getRegBx(); + regCx = state.getRegCx(); + regDx = state.getRegDx(); + regEx = state.getRegEx(); + regHx = state.getRegHx(); + regLx = state.getRegLx(); + regIX = state.getRegIX(); + regIY = state.getRegIY(); + regSP = state.getRegSP(); + regPC = state.getRegPC(); + regI = state.getRegI(); + setRegR(state.getRegR()); + memptr = state.getMemPtr(); + halted = state.isHalted(); + ffIFF1 = state.isIFF1(); + ffIFF2 = state.isIFF2(); + modeINT = state.getIM(); + activeINT = state.isINTLine(); + pendingEI = state.isPendingEI(); + activeNMI = state.isNMI(); + flagQ = false; + lastFlagQ = state.isFlagQ(); + } + + // Reset + /* Según el documento de Sean Young, que se encuentra en + * [http://www.myquest.com/z80undocumented], la mejor manera de emular el + * reset es poniendo PC, IFF1, IFF2, R e IM0 a 0 y todos los demás registros + * a 0xFFFF. + * + * 29/05/2011: cuando la CPU recibe alimentación por primera vez, los + * registros PC e IR se inicializan a cero y el resto a 0xFF. + * Si se produce un reset a través de la patilla correspondiente, + * los registros PC e IR se inicializan a 0 y el resto se preservan. + * En cualquier caso, todo parece depender bastante del modelo + * concreto de Z80, así que se escoge el comportamiento del + * modelo Zilog Z8400APS. Z80A CPU. + * http://www.worldofspectrum.org/forums/showthread.php?t=34574 + */ + public final void reset() { + if (pinReset) { + pinReset = false; + } else { + regA = regAx = 0xff; + setFlags(0xff); + regFx = 0xff; + regB = regBx = 0xff; + regC = regCx = 0xff; + regD = regDx = 0xff; + regE = regEx = 0xff; + regH = regHx = 0xff; + regL = regLx = 0xff; + + regIX = regIY = 0xffff; + + regSP = 0xffff; + + memptr = 0xffff; + } + + regPC = 0; + regI = regR = 0; + regRbit7 = false; + ffIFF1 = false; + ffIFF2 = false; + pendingEI = false; + activeNMI = false; + activeINT = false; + halted = false; + setIM(IntMode.IM0); + lastFlagQ = false; + prefixOpcode = 0x00; + } + + // Rota a la izquierda el valor del argumento + // El bit 0 y el flag C toman el valor del bit 7 antes de la operación + private int rlc(int oper8) { + carryFlag = (oper8 > 0x7f); + oper8 = (oper8 << 1) & 0xfe; + if (carryFlag) { + oper8 |= CARRY_MASK; + } + sz5h3pnFlags = sz53pn_addTable[oper8]; + flagQ = true; + return oper8; + } + + // Rota a la izquierda el valor del argumento + // El bit 7 va al carry flag + // El bit 0 toma el valor del flag C antes de la operación + private int rl(int oper8) { + boolean carry = carryFlag; + carryFlag = (oper8 > 0x7f); + oper8 = (oper8 << 1) & 0xfe; + if (carry) { + oper8 |= CARRY_MASK; + } + sz5h3pnFlags = sz53pn_addTable[oper8]; + flagQ = true; + return oper8; + } + + // Rota a la izquierda el valor del argumento + // El bit 7 va al carry flag + // El bit 0 toma el valor 0 + private int sla(int oper8) { + carryFlag = (oper8 > 0x7f); + oper8 = (oper8 << 1) & 0xfe; + sz5h3pnFlags = sz53pn_addTable[oper8]; + flagQ = true; + return oper8; + } + + // Rota a la izquierda el valor del argumento (como sla salvo por el bit 0) + // El bit 7 va al carry flag + // El bit 0 toma el valor 1 + // Instrucción indocumentada + private int sll(int oper8) { + carryFlag = (oper8 > 0x7f); + oper8 = ((oper8 << 1) | CARRY_MASK) & 0xff; + sz5h3pnFlags = sz53pn_addTable[oper8]; + flagQ = true; + return oper8; + } + + // Rota a la derecha el valor del argumento + // El bit 7 y el flag C toman el valor del bit 0 antes de la operación + private int rrc(int oper8) { + carryFlag = (oper8 & CARRY_MASK) != 0; + oper8 >>>= 1; + if (carryFlag) { + oper8 |= SIGN_MASK; + } + sz5h3pnFlags = sz53pn_addTable[oper8]; + flagQ = true; + return oper8; + } + + // Rota a la derecha el valor del argumento + // El bit 0 va al carry flag + // El bit 7 toma el valor del flag C antes de la operación + private int rr(int oper8) { + boolean carry = carryFlag; + carryFlag = (oper8 & CARRY_MASK) != 0; + oper8 >>>= 1; + if (carry) { + oper8 |= SIGN_MASK; + } + sz5h3pnFlags = sz53pn_addTable[oper8]; + flagQ = true; + return oper8; + } + + // A = A7 A6 A5 A4 (HL)3 (HL)2 (HL)1 (HL)0 + // (HL) = A3 A2 A1 A0 (HL)7 (HL)6 (HL)5 (HL)4 + // Los bits 3,2,1 y 0 de (HL) se copian a los bits 3,2,1 y 0 de A. + // Los 4 bits bajos que había en A se copian a los bits 7,6,5 y 4 de (HL). + // Los 4 bits altos que había en (HL) se copian a los 4 bits bajos de (HL) + // Los 4 bits superiores de A no se tocan. ¡p'habernos matao! + private void rrd() { + int aux = (regA & 0x0f) << 4; + memptr = getRegHL(); + int memHL = MemIoImpl.peek8(memptr); + regA = (regA & 0xf0) | (memHL & 0x0f); + MemIoImpl.addressOnBus(memptr, 4); + MemIoImpl.poke8(memptr, (memHL >>> 4) | aux); + sz5h3pnFlags = sz53pn_addTable[regA]; + memptr++; + flagQ = true; + } + + // A = A7 A6 A5 A4 (HL)7 (HL)6 (HL)5 (HL)4 + // (HL) = (HL)3 (HL)2 (HL)1 (HL)0 A3 A2 A1 A0 + // Los 4 bits bajos que había en (HL) se copian a los bits altos de (HL). + // Los 4 bits altos que había en (HL) se copian a los 4 bits bajos de A + // Los bits 3,2,1 y 0 de A se copian a los bits 3,2,1 y 0 de (HL). + // Los 4 bits superiores de A no se tocan. ¡p'habernos matao! + private void rld() { + int aux = regA & 0x0f; + memptr = getRegHL(); + int memHL = MemIoImpl.peek8(memptr); + regA = (regA & 0xf0) | (memHL >>> 4); + MemIoImpl.addressOnBus(memptr, 4); + MemIoImpl.poke8(memptr, ((memHL << 4) | aux) & 0xff); + sz5h3pnFlags = sz53pn_addTable[regA]; + memptr++; + flagQ = true; + } + + // Rota a la derecha 1 bit el valor del argumento + // El bit 0 pasa al carry. + // El bit 7 conserva el valor que tenga + private int sra(int oper8) { + int sign = oper8 & SIGN_MASK; + carryFlag = (oper8 & CARRY_MASK) != 0; + oper8 = (oper8 >> 1) | sign; + sz5h3pnFlags = sz53pn_addTable[oper8]; + flagQ = true; + return oper8; + } + + // Rota a la derecha 1 bit el valor del argumento + // El bit 0 pasa al carry. + // El bit 7 toma el valor 0 + private int srl(int oper8) { + carryFlag = (oper8 & CARRY_MASK) != 0; + oper8 >>>= 1; + sz5h3pnFlags = sz53pn_addTable[oper8]; + flagQ = true; + return oper8; + } + + /* + * Half-carry flag: + * + * FLAG = (A^B^RESULT)&0x10 for any operation + * + * Overflow flag: + * + * FLAG = ~(A^B)&(B^RESULT)&0x80 for addition [ADD/ADC] + * FLAG = (A^B)&(A^RESULT)&0x80 for subtraction [SUB/SBC] + * + * For INC/DEC, you can use following simplifications: + * + * INC: + * H_FLAG = (RESULT&0x0F)==0x00 + * V_FLAG = RESULT==0x80 + * + * DEC: + * H_FLAG = (RESULT&0x0F)==0x0F + * V_FLAG = RESULT==0x7F + */ + // Incrementa un valor de 8 bits modificando los flags oportunos + private int inc8(int oper8) { + oper8 = (oper8 + 1) & 0xff; + + sz5h3pnFlags = sz53n_addTable[oper8]; + + if ((oper8 & 0x0f) == 0) { + sz5h3pnFlags |= HALFCARRY_MASK; + } + + if (oper8 == 0x80) { + sz5h3pnFlags |= OVERFLOW_MASK; + } + + flagQ = true; + return oper8; + } + + // Decrementa un valor de 8 bits modificando los flags oportunos + private int dec8(int oper8) { + oper8 = (oper8 - 1) & 0xff; + + sz5h3pnFlags = sz53n_subTable[oper8]; + + if ((oper8 & 0x0f) == 0x0f) { + sz5h3pnFlags |= HALFCARRY_MASK; + } + + if (oper8 == 0x7f) { + sz5h3pnFlags |= OVERFLOW_MASK; + } + + flagQ = true; + return oper8; + } + + // Suma de 8 bits afectando a los flags + private void add(int oper8) { + int res = regA + oper8; + + carryFlag = res > 0xff; + res &= 0xff; + sz5h3pnFlags = sz53n_addTable[res]; + + /* El módulo 16 del resultado será menor que el módulo 16 del registro A + * si ha habido HalfCarry. Sucede lo mismo para todos los métodos suma + * SIN carry */ + if ((res & 0x0f) < (regA & 0x0f)) { + sz5h3pnFlags |= HALFCARRY_MASK; + } + + if (((regA ^ ~oper8) & (regA ^ res)) > 0x7f) { + sz5h3pnFlags |= OVERFLOW_MASK; + } + + regA = res; + flagQ = true; + } + + // Suma con acarreo de 8 bits + private void adc(int oper8) { + int res = regA + oper8; + + if (carryFlag) { + res++; + } + + carryFlag = res > 0xff; + res &= 0xff; + sz5h3pnFlags = sz53n_addTable[res]; + + if (((regA ^ oper8 ^ res) & 0x10) != 0) { + sz5h3pnFlags |= HALFCARRY_MASK; + } + + if (((regA ^ ~oper8) & (regA ^ res)) > 0x7f) { + sz5h3pnFlags |= OVERFLOW_MASK; + } + + regA = res; + flagQ = true; + } + + // Suma dos operandos de 16 bits sin carry afectando a los flags + private int add16(int reg16, int oper16) { + oper16 += reg16; + + carryFlag = oper16 > 0xffff; + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZP_MASK) | ((oper16 >>> 8) & FLAG_53_MASK); + oper16 &= 0xffff; + + if ((oper16 & 0x0fff) < (reg16 & 0x0fff)) { + sz5h3pnFlags |= HALFCARRY_MASK; + } + + memptr = reg16 + 1; + flagQ = true; + return oper16; + } + + // Suma con acarreo de 16 bits + private void adc16(int reg16) { + int regHL = getRegHL(); + memptr = regHL + 1; + + int res = regHL + reg16; + if (carryFlag) { + res++; + } + + carryFlag = res > 0xffff; + res &= 0xffff; + setRegHL(res); + + sz5h3pnFlags = sz53n_addTable[regH]; + if (res != 0) { + sz5h3pnFlags &= ~ZERO_MASK; + } + + if (((res ^ regHL ^ reg16) & 0x1000) != 0) { + sz5h3pnFlags |= HALFCARRY_MASK; + } + + if (((regHL ^ ~reg16) & (regHL ^ res)) > 0x7fff) { + sz5h3pnFlags |= OVERFLOW_MASK; + } + + flagQ = true; + } + + // Resta de 8 bits + private void sub(int oper8) { + int res = regA - oper8; + + carryFlag = res < 0; + res &= 0xff; + sz5h3pnFlags = sz53n_subTable[res]; + + /* El módulo 16 del resultado será mayor que el módulo 16 del registro A + * si ha habido HalfCarry. Sucede lo mismo para todos los métodos resta + * SIN carry, incluido cp */ + if ((res & 0x0f) > (regA & 0x0f)) { + sz5h3pnFlags |= HALFCARRY_MASK; + } + + if (((regA ^ oper8) & (regA ^ res)) > 0x7f) { + sz5h3pnFlags |= OVERFLOW_MASK; + } + + regA = res; + flagQ = true; + } + + // Resta con acarreo de 8 bits + private void sbc(int oper8) { + int res = regA - oper8; + + if (carryFlag) { + res--; + } + + carryFlag = res < 0; + res &= 0xff; + sz5h3pnFlags = sz53n_subTable[res]; + + if (((regA ^ oper8 ^ res) & 0x10) != 0) { + sz5h3pnFlags |= HALFCARRY_MASK; + } + + if (((regA ^ oper8) & (regA ^ res)) > 0x7f) { + sz5h3pnFlags |= OVERFLOW_MASK; + } + + regA = res; + flagQ = true; + } + + // Resta con acarreo de 16 bits + private void sbc16(int reg16) { + int regHL = getRegHL(); + memptr = regHL + 1; + + int res = regHL - reg16; + if (carryFlag) { + res--; + } + + carryFlag = res < 0; + res &= 0xffff; + setRegHL(res); + + sz5h3pnFlags = sz53n_subTable[regH]; + if (res != 0) { + sz5h3pnFlags &= ~ZERO_MASK; + } + + if (((res ^ regHL ^ reg16) & 0x1000) != 0) { + sz5h3pnFlags |= HALFCARRY_MASK; + } + + if (((regHL ^ reg16) & (regHL ^ res)) > 0x7fff) { + sz5h3pnFlags |= OVERFLOW_MASK; + } + flagQ = true; + } + + // Operación AND lógica + private void and(int oper8) { + regA &= oper8; + carryFlag = false; + sz5h3pnFlags = sz53pn_addTable[regA] | HALFCARRY_MASK; + flagQ = true; + } + + // Operación XOR lógica + private void xor(int oper8) { + regA = (regA ^ oper8) & 0xff; + carryFlag = false; + sz5h3pnFlags = sz53pn_addTable[regA]; + flagQ = true; + } + + // Operación OR lógica + private void or(int oper8) { + regA = (regA | oper8) & 0xff; + carryFlag = false; + sz5h3pnFlags = sz53pn_addTable[regA]; + flagQ = true; + } + + // Operación de comparación con el registro A + // es como SUB, pero solo afecta a los flags + // Los flags SIGN y ZERO se calculan a partir del resultado + // Los flags 3 y 5 se copian desde el operando (sigh!) + private void cp(int oper8) { + int res = regA - (oper8 & 0xff); + + carryFlag = res < 0; + res &= 0xff; + + sz5h3pnFlags = (sz53n_addTable[oper8] & FLAG_53_MASK) + | // No necesito preservar H, pero está a 0 en la tabla de todas formas + (sz53n_subTable[res] & FLAG_SZHN_MASK); + + if ((res & 0x0f) > (regA & 0x0f)) { + sz5h3pnFlags |= HALFCARRY_MASK; + } + + if (((regA ^ oper8) & (regA ^ res)) > 0x7f) { + sz5h3pnFlags |= OVERFLOW_MASK; + } + + flagQ = true; + } + + // DAA + private void daa() { + int suma = 0; + boolean carry = carryFlag; + + if ((sz5h3pnFlags & HALFCARRY_MASK) != 0 || (regA & 0x0f) > 0x09) { + suma = 6; + } + + if (carry || (regA > 0x99)) { + suma |= 0x60; + } + + if (regA > 0x99) { + carry = true; + } + + if ((sz5h3pnFlags & ADDSUB_MASK) != 0) { + sub(suma); + sz5h3pnFlags = (sz5h3pnFlags & HALFCARRY_MASK) | sz53pn_subTable[regA]; + } else { + add(suma); + sz5h3pnFlags = (sz5h3pnFlags & HALFCARRY_MASK) | sz53pn_addTable[regA]; + } + + carryFlag = carry; + // Los add/sub ya ponen el resto de los flags + flagQ = true; + } + + // POP + private int pop() { + int word = MemIoImpl.peek16(regSP); + regSP = (regSP + 2) & 0xffff; + return word; + } + + // PUSH + private void push(int word) { + regSP = (regSP - 1) & 0xffff; + MemIoImpl.poke8(regSP, word >>> 8); + regSP = (regSP - 1) & 0xffff; + MemIoImpl.poke8(regSP, word); + } + + // LDI + private void ldi() { + int work8 = MemIoImpl.peek8(getRegHL()); + int regDE = getRegDE(); + MemIoImpl.poke8(regDE, work8); + MemIoImpl.addressOnBus(regDE, 2); + incRegHL(); + incRegDE(); + decRegBC(); + work8 += regA; + + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZ_MASK) | (work8 & BIT3_MASK); + + if ((work8 & ADDSUB_MASK) != 0) { + sz5h3pnFlags |= BIT5_MASK; + } + + if (regC != 0 || regB != 0) { + sz5h3pnFlags |= PARITY_MASK; + } + flagQ = true; + } + + // LDD + private void ldd() { + int work8 = MemIoImpl.peek8(getRegHL()); + int regDE = getRegDE(); + MemIoImpl.poke8(regDE, work8); + MemIoImpl.addressOnBus(regDE, 2); + decRegHL(); + decRegDE(); + decRegBC(); + work8 += regA; + + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZ_MASK) | (work8 & BIT3_MASK); + + if ((work8 & ADDSUB_MASK) != 0) { + sz5h3pnFlags |= BIT5_MASK; + } + + if (regC != 0 || regB != 0) { + sz5h3pnFlags |= PARITY_MASK; + } + flagQ = true; + } + + // CPI + private void cpi() { + int regHL = getRegHL(); + int memHL = MemIoImpl.peek8(regHL); + boolean carry = carryFlag; // lo guardo porque cp lo toca + cp(memHL); + carryFlag = carry; + MemIoImpl.addressOnBus(regHL, 5); + incRegHL(); + decRegBC(); + memHL = regA - memHL - ((sz5h3pnFlags & HALFCARRY_MASK) != 0 ? 1 : 0); + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHN_MASK) | (memHL & BIT3_MASK); + + if ((memHL & ADDSUB_MASK) != 0) { + sz5h3pnFlags |= BIT5_MASK; + } + + if (regC != 0 || regB != 0) { + sz5h3pnFlags |= PARITY_MASK; + } + + memptr++; + flagQ = true; + } + + // CPD + private void cpd() { + int regHL = getRegHL(); + int memHL = MemIoImpl.peek8(regHL); + boolean carry = carryFlag; // lo guardo porque cp lo toca + cp(memHL); + carryFlag = carry; + MemIoImpl.addressOnBus(regHL, 5); + decRegHL(); + decRegBC(); + memHL = regA - memHL - ((sz5h3pnFlags & HALFCARRY_MASK) != 0 ? 1 : 0); + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHN_MASK) | (memHL & BIT3_MASK); + + if ((memHL & ADDSUB_MASK) != 0) { + sz5h3pnFlags |= BIT5_MASK; + } + + if (regC != 0 || regB != 0) { + sz5h3pnFlags |= PARITY_MASK; + } + + memptr--; + flagQ = true; + } + + // INI + private void ini() { + memptr = getRegBC(); + MemIoImpl.addressOnBus(getPairIR(), 1); + int work8 = MemIoImpl.inPort(memptr); + MemIoImpl.poke8(getRegHL(), work8); + + memptr++; + regB = (regB - 1) & 0xff; + + incRegHL(); + + sz5h3pnFlags = sz53pn_addTable[regB]; + if (work8 > 0x7f) { + sz5h3pnFlags |= ADDSUB_MASK; + } + + carryFlag = false; + int tmp = work8 + ((regC + 1) & 0xff); + if (tmp > 0xff) { + sz5h3pnFlags |= HALFCARRY_MASK; + carryFlag = true; + } + + if ((sz53pn_addTable[((tmp & 0x07) ^ regB)] + & PARITY_MASK) == PARITY_MASK) { + sz5h3pnFlags |= PARITY_MASK; + } else { + sz5h3pnFlags &= ~PARITY_MASK; + } + flagQ = true; + } + + // IND + private void ind() { + memptr = getRegBC(); + MemIoImpl.addressOnBus(getPairIR(), 1); + int work8 = MemIoImpl.inPort(memptr); + MemIoImpl.poke8(getRegHL(), work8); + + memptr--; + regB = (regB - 1) & 0xff; + + decRegHL(); + + sz5h3pnFlags = sz53pn_addTable[regB]; + if (work8 > 0x7f) { + sz5h3pnFlags |= ADDSUB_MASK; + } + + carryFlag = false; + int tmp = work8 + ((regC - 1) & 0xff); + if (tmp > 0xff) { + sz5h3pnFlags |= HALFCARRY_MASK; + carryFlag = true; + } + + if ((sz53pn_addTable[((tmp & 0x07) ^ regB)] + & PARITY_MASK) == PARITY_MASK) { + sz5h3pnFlags |= PARITY_MASK; + } else { + sz5h3pnFlags &= ~PARITY_MASK; + } + flagQ = true; + } + + // OUTI + private void outi() { + + MemIoImpl.addressOnBus(getPairIR(), 1); + + regB = (regB - 1) & 0xff; + memptr = getRegBC(); + + int work8 = MemIoImpl.peek8(getRegHL()); + MemIoImpl.outPort(memptr, work8); + memptr++; + + incRegHL(); + + carryFlag = false; + if (work8 > 0x7f) { + sz5h3pnFlags = sz53n_subTable[regB]; + } else { + sz5h3pnFlags = sz53n_addTable[regB]; + } + + if ((regL + work8) > 0xff) { + sz5h3pnFlags |= HALFCARRY_MASK; + carryFlag = true; + } + + if ((sz53pn_addTable[(((regL + work8) & 0x07) ^ regB)] + & PARITY_MASK) == PARITY_MASK) { + sz5h3pnFlags |= PARITY_MASK; + } + flagQ = true; + } + + // OUTD + private void outd() { + + MemIoImpl.addressOnBus(getPairIR(), 1); + + regB = (regB - 1) & 0xff; + memptr = getRegBC(); + + int work8 = MemIoImpl.peek8(getRegHL()); + MemIoImpl.outPort(memptr, work8); + memptr--; + + decRegHL(); + + carryFlag = false; + if (work8 > 0x7f) { + sz5h3pnFlags = sz53n_subTable[regB]; + } else { + sz5h3pnFlags = sz53n_addTable[regB]; + } + + if ((regL + work8) > 0xff) { + sz5h3pnFlags |= HALFCARRY_MASK; + carryFlag = true; + } + + if ((sz53pn_addTable[(((regL + work8) & 0x07) ^ regB)] + & PARITY_MASK) == PARITY_MASK) { + sz5h3pnFlags |= PARITY_MASK; + } + flagQ = true; + } + + // Pone a 1 el Flag Z si el bit b del registro + // r es igual a 0 + /* + * En contra de lo que afirma el Z80-Undocumented, los bits 3 y 5 toman + * SIEMPRE el valor de los bits correspondientes del valor a comparar para + * las instrucciones BIT n,r. Para BIT n,(HL) toman el valor del registro + * escondido (memptr), y para las BIT n, (IX/IY+n) toman el valor de los + * bits superiores de la dirección indicada por IX/IY+n. + * + * 04/12/08 Confirmado el comentario anterior: + * http://scratchpad.wikia.com/wiki/Z80 + */ + private void bit(int mask, int reg) { + boolean zeroFlag = (mask & reg) == 0; + + sz5h3pnFlags = (sz53n_addTable[reg] & ~FLAG_SZP_MASK) | HALFCARRY_MASK; + + if (zeroFlag) { + sz5h3pnFlags |= (PARITY_MASK | ZERO_MASK); + } + + if (mask == SIGN_MASK && !zeroFlag) { + sz5h3pnFlags |= SIGN_MASK; + } + flagQ = true; + } + + //Interrupción + /* Desglose de la interrupción, según el modo: + * IM0: + * M1: 7 T-Estados -> reconocer INT y decSP + * M2: 3 T-Estados -> escribir byte alto y decSP + * M3: 3 T-Estados -> escribir byte bajo y salto a N + * IM1: + * M1: 7 T-Estados -> reconocer INT y decSP + * M2: 3 T-Estados -> escribir byte alto PC y decSP + * M3: 3 T-Estados -> escribir byte bajo PC y PC=0x0038 + * IM2: + * M1: 7 T-Estados -> reconocer INT y decSP + * M2: 3 T-Estados -> escribir byte alto y decSP + * M3: 3 T-Estados -> escribir byte bajo + * M4: 3 T-Estados -> leer byte bajo del vector de INT + * M5: 3 T-Estados -> leer byte alto y saltar a la rutina de INT + */ + private void interruption() { + + //System.out.println(String.format("INT at %d T-States", tEstados)); +// int tmp = tEstados; // peek8 modifica los tEstados + lastFlagQ = false; + // Si estaba en un HALT esperando una INT, lo saca de la espera + if (halted) { + halted = false; + regPC = (regPC + 1) & 0xffff; + } + + MemIoImpl.interruptHandlingTime(7); + + regR++; + ffIFF1 = ffIFF2 = false; + push(regPC); // el push a�adir� 6 t-estados (+contended si toca) + if (modeINT == IntMode.IM2) { + regPC = MemIoImpl.peek16((regI << 8) | 0xff); // +6 t-estados + } else { + regPC = 0x0038; + } + memptr = regPC; + //System.out.println(String.format("Coste INT: %d", tEstados-tmp)); + } + + //Interrupción NMI, no utilizado por ahora + /* Desglose de ciclos de máquina y T-Estados + * M1: 5 T-Estados -> extraer opcode (pá ná, es tontería) y decSP + * M2: 3 T-Estados -> escribe byte alto de PC y decSP + * M3: 3 T-Estados -> escribe byte bajo de PC y PC=0x0066 + */ + private void nmi() { + lastFlagQ = false; + // Esta lectura consigue dos cosas: + // 1.- La lectura del opcode del M1 que se descarta + // 2.- Si estaba en un HALT esperando una INT, lo saca de la espera + MemIoImpl.fetchOpcode(regPC); + MemIoImpl.interruptHandlingTime(1); + if (halted) { + halted = false; + regPC = (regPC + 1) & 0xffff; + } + regR++; + ffIFF1 = false; + push(regPC); // 3+3 t-estados + contended si procede + regPC = memptr = 0x0066; + } + + public final boolean isBreakpoint(int address) { + return breakpointAt[address & 0xffff]; + } + + public final void setBreakpoint(int address, boolean state) { + breakpointAt[address & 0xffff] = state; + } + + public void resetBreakpoints() { + Arrays.fill(breakpointAt, false); + } + + public boolean isExecDone() { + return execDone; + } + + public void setExecDone(boolean state) { + execDone = state; + } + + /* Los tEstados transcurridos se calculan teniendo en cuenta el número de + * ciclos de máquina reales que se ejecutan. Esa es la única forma de poder + * simular la contended memory del Spectrum. + */ + public final void execute() { + + int opCode = MemIoImpl.fetchOpcode(regPC); + regR++; + + if (prefixOpcode == 0 && breakpointAt[regPC]) { + opCode = NotifyImpl.breakpoint(regPC, opCode); + } + + regPC = (regPC + 1) & 0xffff; + + flagQ = false; + + // El prefijo 0xCB no cuenta para esta guerra. + // En CBxx todas las xx producen un código válido + // de instrucción, incluyendo CBCB. + switch (prefixOpcode) { + case 0x00: + decodeOpcode(opCode); + break; + case 0xDD: + regIX = decodeDDFD(opCode, regIX); + break; + case 0xED: + decodeED(opCode); + break; + case 0xFD: + regIY = decodeDDFD(opCode, regIY); + break; + default: + System.out.println(String.format("ERROR!: prefixOpcode = %02x, opCode = %02x", prefixOpcode, opCode)); + } + + if (prefixOpcode != 0x00) { + return; + } + + lastFlagQ = flagQ; + + // Si está pendiente la activación de la interrupción y el + // código que se acaba de ejecutar no es el propio EI + if (pendingEI && opCode != 0xFB) { + pendingEI = false; + } + + if (execDone) { + NotifyImpl.execDone(); + } + + // Primero se comprueba NMI + // Si se activa NMI no se comprueba INT porque la siguiente + // instrucción debe ser la de 0x0066. + if (activeNMI) { + activeNMI = false; + nmi(); + return; + } + + // Ahora se comprueba si hay una INT + if (ffIFF1 && !pendingEI && MemIoImpl.isActiveINT()) { + interruption(); + } + } + + private void decodeOpcode(int opCode) { + + switch (opCode) { +// case 0x00: /* NOP */ +// break; + case 0x01: { /* LD BC,nn */ + setRegBC(MemIoImpl.peek16(regPC)); + regPC = (regPC + 2) & 0xffff; + break; + } + case 0x02: { /* LD (BC),A */ + MemIoImpl.poke8(getRegBC(), regA); + memptr = (regA << 8) | ((regC + 1) & 0xff); + break; + } + case 0x03: { /* INC BC */ + MemIoImpl.addressOnBus(getPairIR(), 2); + incRegBC(); + break; + } + case 0x04: { /* INC B */ + regB = inc8(regB); + break; + } + case 0x05: { /* DEC B */ + regB = dec8(regB); + break; + } + case 0x06: { /* LD B,n */ + regB = MemIoImpl.peek8(regPC); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x07: { /* RLCA */ + carryFlag = (regA > 0x7f); + regA = (regA << 1) & 0xff; + if (carryFlag) { + regA |= CARRY_MASK; + } + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZP_MASK) | (regA & FLAG_53_MASK); + flagQ = true; + break; + } + case 0x08: { /* EX AF,AF' */ + int work8 = regA; + regA = regAx; + regAx = work8; + + work8 = getFlags(); + setFlags(regFx); + regFx = work8; + break; + } + case 0x09: { /* ADD HL,BC */ + MemIoImpl.addressOnBus(getPairIR(), 7); + setRegHL(add16(getRegHL(), getRegBC())); + break; + } + case 0x0A: { /* LD A,(BC) */ + memptr = getRegBC(); + regA = MemIoImpl.peek8(memptr++); + break; + } + case 0x0B: { /* DEC BC */ + MemIoImpl.addressOnBus(getPairIR(), 2); + decRegBC(); + break; + } + case 0x0C: { /* INC C */ + regC = inc8(regC); + break; + } + case 0x0D: { /* DEC C */ + regC = dec8(regC); + break; + } + case 0x0E: { /* LD C,n */ + regC = MemIoImpl.peek8(regPC); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x0F: { /* RRCA */ + carryFlag = (regA & CARRY_MASK) != 0; + regA >>>= 1; + if (carryFlag) { + regA |= SIGN_MASK; + } + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZP_MASK) | (regA & FLAG_53_MASK); + flagQ = true; + break; + } + case 0x10: { /* DJNZ e */ + MemIoImpl.addressOnBus(getPairIR(), 1); + byte offset = (byte) MemIoImpl.peek8(regPC); + regB--; + if (regB != 0) { + regB &= 0xff; + MemIoImpl.addressOnBus(regPC, 5); + regPC = memptr = (regPC + offset + 1) & 0xffff; + } else { + regPC = (regPC + 1) & 0xffff; + } + break; + } + case 0x11: { /* LD DE,nn */ + setRegDE(MemIoImpl.peek16(regPC)); + regPC = (regPC + 2) & 0xffff; + break; + } + case 0x12: { /* LD (DE),A */ + MemIoImpl.poke8(getRegDE(), regA); + memptr = (regA << 8) | ((regE + 1) & 0xff); + break; + } + case 0x13: { /* INC DE */ + MemIoImpl.addressOnBus(getPairIR(), 2); + incRegDE(); + break; + } + case 0x14: { /* INC D */ + regD = inc8(regD); + break; + } + case 0x15: { /* DEC D */ + regD = dec8(regD); + break; + } + case 0x16: { /* LD D,n */ + regD = MemIoImpl.peek8(regPC); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x17: { /* RLA */ + boolean oldCarry = carryFlag; + carryFlag = (regA > 0x7f); + regA = (regA << 1) & 0xff; + if (oldCarry) { + regA |= CARRY_MASK; + } + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZP_MASK) | (regA & FLAG_53_MASK); + flagQ = true; + break; + } + case 0x18: { /* JR e */ + byte offset = (byte) MemIoImpl.peek8(regPC); + MemIoImpl.addressOnBus(regPC, 5); + regPC = memptr = (regPC + offset + 1) & 0xffff; + break; + } + case 0x19: { /* ADD HL,DE */ + MemIoImpl.addressOnBus(getPairIR(), 7); + setRegHL(add16(getRegHL(), getRegDE())); + break; + } + case 0x1A: { /* LD A,(DE) */ + memptr = getRegDE(); + regA = MemIoImpl.peek8(memptr++); + break; + } + case 0x1B: { /* DEC DE */ + MemIoImpl.addressOnBus(getPairIR(), 2); + decRegDE(); + break; + } + case 0x1C: { /* INC E */ + regE = inc8(regE); + break; + } + case 0x1D: { /* DEC E */ + regE = dec8(regE); + break; + } + case 0x1E: { /* LD E,n */ + regE = MemIoImpl.peek8(regPC); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x1F: { /* RRA */ + boolean oldCarry = carryFlag; + carryFlag = (regA & CARRY_MASK) != 0; + regA >>>= 1; + if (oldCarry) { + regA |= SIGN_MASK; + } + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZP_MASK) | (regA & FLAG_53_MASK); + flagQ = true; + break; + } + case 0x20: { /* JR NZ,e */ + byte offset = (byte) MemIoImpl.peek8(regPC); + if ((sz5h3pnFlags & ZERO_MASK) == 0) { + MemIoImpl.addressOnBus(regPC, 5); + regPC += offset; + memptr = regPC + 1; + } + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x21: { /* LD HL,nn */ + setRegHL(MemIoImpl.peek16(regPC)); + regPC = (regPC + 2) & 0xffff; + break; + } + case 0x22: { /* LD (nn),HL */ + memptr = MemIoImpl.peek16(regPC); + MemIoImpl.poke16(memptr++, getRegHL()); + regPC = (regPC + 2) & 0xffff; + break; + } + case 0x23: { /* INC HL */ + MemIoImpl.addressOnBus(getPairIR(), 2); + incRegHL(); + break; + } + case 0x24: { /* INC H */ + regH = inc8(regH); + break; + } + case 0x25: { /* DEC H */ + regH = dec8(regH); + break; + } + case 0x26: { /* LD H,n */ + regH = MemIoImpl.peek8(regPC); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x27: { /* DAA */ + daa(); + break; + } + case 0x28: { /* JR Z,e */ + byte offset = (byte) MemIoImpl.peek8(regPC); + if ((sz5h3pnFlags & ZERO_MASK) != 0) { + MemIoImpl.addressOnBus(regPC, 5); + regPC += offset; + memptr = regPC + 1; + } + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x29: { /* ADD HL,HL */ + MemIoImpl.addressOnBus(getPairIR(), 7); + int work16 = getRegHL(); + setRegHL(add16(work16, work16)); + break; + } + case 0x2A: { /* LD HL,(nn) */ + memptr = MemIoImpl.peek16(regPC); + setRegHL(MemIoImpl.peek16(memptr++)); + regPC = (regPC + 2) & 0xffff; + break; + } + case 0x2B: { /* DEC HL */ + MemIoImpl.addressOnBus(getPairIR(), 2); + decRegHL(); + break; + } + case 0x2C: { /* INC L */ + regL = inc8(regL); + break; + } + case 0x2D: { /* DEC L */ + regL = dec8(regL); + break; + } + case 0x2E: { /* LD L,n */ + regL = MemIoImpl.peek8(regPC); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x2F: { /* CPL */ + regA ^= 0xff; + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZP_MASK) | HALFCARRY_MASK + | (regA & FLAG_53_MASK) | ADDSUB_MASK; + flagQ = true; + break; + } + case 0x30: { /* JR NC,e */ + byte offset = (byte) MemIoImpl.peek8(regPC); + if (!carryFlag) { + MemIoImpl.addressOnBus(regPC, 5); + regPC += offset; + memptr = regPC + 1; + } + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x31: { /* LD SP,nn */ + regSP = MemIoImpl.peek16(regPC); + regPC = (regPC + 2) & 0xffff; + break; + } + case 0x32: { /* LD (nn),A */ + memptr = MemIoImpl.peek16(regPC); + MemIoImpl.poke8(memptr, regA); + memptr = (regA << 8) | ((memptr + 1) & 0xff); + regPC = (regPC + 2) & 0xffff; + break; + } + case 0x33: { /* INC SP */ + MemIoImpl.addressOnBus(getPairIR(), 2); + regSP = (regSP + 1) & 0xffff; + break; + } + case 0x34: { /* INC (HL) */ + int work16 = getRegHL(); + int work8 = inc8(MemIoImpl.peek8(work16)); + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0x35: { /* DEC (HL) */ + int work16 = getRegHL(); + int work8 = dec8(MemIoImpl.peek8(work16)); + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0x36: { /* LD (HL),n */ + MemIoImpl.poke8(getRegHL(), MemIoImpl.peek8(regPC)); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x37: { /* SCF */ + int regQ = lastFlagQ ? sz5h3pnFlags : 0; + carryFlag = true; + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZP_MASK) | (((regQ ^ sz5h3pnFlags) | regA) & FLAG_53_MASK); + flagQ = true; + break; + } + case 0x38: { /* JR C,e */ + byte offset = (byte) MemIoImpl.peek8(regPC); + if (carryFlag) { + MemIoImpl.addressOnBus(regPC, 5); + regPC += offset; + memptr = regPC + 1; + } + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x39: { /* ADD HL,SP */ + MemIoImpl.addressOnBus(getPairIR(), 7); + setRegHL(add16(getRegHL(), regSP)); + break; + } + case 0x3A: { /* LD A,(nn) */ + memptr = MemIoImpl.peek16(regPC); + regA = MemIoImpl.peek8(memptr++); + regPC = (regPC + 2) & 0xffff; + break; + } + case 0x3B: { /* DEC SP */ + MemIoImpl.addressOnBus(getPairIR(), 2); + regSP = (regSP - 1) & 0xffff; + break; + } + case 0x3C: { /* INC A */ + regA = inc8(regA); + break; + } + case 0x3D: { /* DEC A */ + regA = dec8(regA); + break; + } + case 0x3E: { /* LD A,n */ + regA = MemIoImpl.peek8(regPC); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x3F: { /* CCF */ + int regQ = lastFlagQ ? sz5h3pnFlags : 0; + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZP_MASK) | (((regQ ^ sz5h3pnFlags) | regA) & FLAG_53_MASK); + if (carryFlag) { + sz5h3pnFlags |= HALFCARRY_MASK; + } + carryFlag = !carryFlag; + flagQ = true; + break; + } +// case 0x40: { /* LD B,B */ +// break; +// } + case 0x41: { /* LD B,C */ + regB = regC; + break; + } + case 0x42: { /* LD B,D */ + regB = regD; + break; + } + case 0x43: { /* LD B,E */ + regB = regE; + break; + } + case 0x44: { /* LD B,H */ + regB = regH; + break; + } + case 0x45: { /* LD B,L */ + regB = regL; + break; + } + case 0x46: { /* LD B,(HL) */ + regB = MemIoImpl.peek8(getRegHL()); + break; + } + case 0x47: { /* LD B,A */ + regB = regA; + break; + } + case 0x48: { /* LD C,B */ + regC = regB; + break; + } +// case 0x49: { /* LD C,C */ +// break; +// } + case 0x4A: { /* LD C,D */ + regC = regD; + break; + } + case 0x4B: { /* LD C,E */ + regC = regE; + break; + } + case 0x4C: { /* LD C,H */ + regC = regH; + break; + } + case 0x4D: { /* LD C,L */ + regC = regL; + break; + } + case 0x4E: { /* LD C,(HL) */ + regC = MemIoImpl.peek8(getRegHL()); + break; + } + case 0x4F: { /* LD C,A */ + regC = regA; + break; + } + case 0x50: { /* LD D,B */ + regD = regB; + break; + } + case 0x51: { /* LD D,C */ + regD = regC; + break; + } +// case 0x52: { /* LD D,D */ +// break; +// } + case 0x53: { /* LD D,E */ + regD = regE; + break; + } + case 0x54: { /* LD D,H */ + regD = regH; + break; + } + case 0x55: { /* LD D,L */ + regD = regL; + break; + } + case 0x56: { /* LD D,(HL) */ + regD = MemIoImpl.peek8(getRegHL()); + break; + } + case 0x57: { /* LD D,A */ + regD = regA; + break; + } + case 0x58: { /* LD E,B */ + regE = regB; + break; + } + case 0x59: { /* LD E,C */ + regE = regC; + break; + } + case 0x5A: { /* LD E,D */ + regE = regD; + break; + } +// case 0x5B: { /* LD E,E */ +// break; +// } + case 0x5C: { /* LD E,H */ + regE = regH; + break; + } + case 0x5D: { /* LD E,L */ + regE = regL; + break; + } + case 0x5E: { /* LD E,(HL) */ + regE = MemIoImpl.peek8(getRegHL()); + break; + } + case 0x5F: { /* LD E,A */ + regE = regA; + break; + } + case 0x60: { /* LD H,B */ + regH = regB; + break; + } + case 0x61: { /* LD H,C */ + regH = regC; + break; + } + case 0x62: { /* LD H,D */ + regH = regD; + break; + } + case 0x63: { /* LD H,E */ + regH = regE; + break; + } +// case 0x64: { /* LD H,H */ +// break; +// } + case 0x65: { /* LD H,L */ + regH = regL; + break; + } + case 0x66: { /* LD H,(HL) */ + regH = MemIoImpl.peek8(getRegHL()); + break; + } + case 0x67: { /* LD H,A */ + regH = regA; + break; + } + case 0x68: { /* LD L,B */ + regL = regB; + break; + } + case 0x69: { /* LD L,C */ + regL = regC; + break; + } + case 0x6A: { /* LD L,D */ + regL = regD; + break; + } + case 0x6B: { /* LD L,E */ + regL = regE; + break; + } + case 0x6C: { /* LD L,H */ + regL = regH; + break; + } +// case 0x6D: { /* LD L,L */ +// break; +// } + case 0x6E: { /* LD L,(HL) */ + regL = MemIoImpl.peek8(getRegHL()); + break; + } + case 0x6F: { /* LD L,A */ + regL = regA; + break; + } + case 0x70: { /* LD (HL),B */ + MemIoImpl.poke8(getRegHL(), regB); + break; + } + case 0x71: { /* LD (HL),C */ + MemIoImpl.poke8(getRegHL(), regC); + break; + } + case 0x72: { /* LD (HL),D */ + MemIoImpl.poke8(getRegHL(), regD); + break; + } + case 0x73: { /* LD (HL),E */ + MemIoImpl.poke8(getRegHL(), regE); + break; + } + case 0x74: { /* LD (HL),H */ + MemIoImpl.poke8(getRegHL(), regH); + break; + } + case 0x75: { /* LD (HL),L */ + MemIoImpl.poke8(getRegHL(), regL); + break; + } + case 0x76: { /* HALT */ + regPC = (regPC - 1) & 0xffff; + halted = true; + break; + } + case 0x77: { /* LD (HL),A */ + MemIoImpl.poke8(getRegHL(), regA); + break; + } + case 0x78: { /* LD A,B */ + regA = regB; + break; + } + case 0x79: { /* LD A,C */ + regA = regC; + break; + } + case 0x7A: { /* LD A,D */ + regA = regD; + break; + } + case 0x7B: { /* LD A,E */ + regA = regE; + break; + } + case 0x7C: { /* LD A,H */ + regA = regH; + break; + } + case 0x7D: { /* LD A,L */ + regA = regL; + break; + } + case 0x7E: { /* LD A,(HL) */ + regA = MemIoImpl.peek8(getRegHL()); + break; + } +// case 0x7F: { /* LD A,A */ +// break; +// } + case 0x80: { /* ADD A,B */ + add(regB); + break; + } + case 0x81: { /* ADD A,C */ + add(regC); + break; + } + case 0x82: { /* ADD A,D */ + add(regD); + break; + } + case 0x83: { /* ADD A,E */ + add(regE); + break; + } + case 0x84: { /* ADD A,H */ + add(regH); + break; + } + case 0x85: { /* ADD A,L */ + add(regL); + break; + } + case 0x86: { /* ADD A,(HL) */ + add(MemIoImpl.peek8(getRegHL())); + break; + } + case 0x87: { /* ADD A,A */ + add(regA); + break; + } + case 0x88: { /* ADC A,B */ + adc(regB); + break; + } + case 0x89: { /* ADC A,C */ + adc(regC); + break; + } + case 0x8A: { /* ADC A,D */ + adc(regD); + break; + } + case 0x8B: { /* ADC A,E */ + adc(regE); + break; + } + case 0x8C: { /* ADC A,H */ + adc(regH); + break; + } + case 0x8D: { /* ADC A,L */ + adc(regL); + break; + } + case 0x8E: { /* ADC A,(HL) */ + adc(MemIoImpl.peek8(getRegHL())); + break; + } + case 0x8F: { /* ADC A,A */ + adc(regA); + break; + } + case 0x90: { /* SUB B */ + sub(regB); + break; + } + case 0x91: { /* SUB C */ + sub(regC); + break; + } + case 0x92: { /* SUB D */ + sub(regD); + break; + } + case 0x93: { /* SUB E */ + sub(regE); + break; + } + case 0x94: { /* SUB H */ + sub(regH); + break; + } + case 0x95: { /* SUB L */ + sub(regL); + break; + } + case 0x96: { /* SUB (HL) */ + sub(MemIoImpl.peek8(getRegHL())); + break; + } + case 0x97: { /* SUB A */ + sub(regA); + break; + } + case 0x98: { /* SBC A,B */ + sbc(regB); + break; + } + case 0x99: { /* SBC A,C */ + sbc(regC); + break; + } + case 0x9A: { /* SBC A,D */ + sbc(regD); + break; + } + case 0x9B: { /* SBC A,E */ + sbc(regE); + break; + } + case 0x9C: { /* SBC A,H */ + sbc(regH); + break; + } + case 0x9D: { /* SBC A,L */ + sbc(regL); + break; + } + case 0x9E: { /* SBC A,(HL) */ + sbc(MemIoImpl.peek8(getRegHL())); + break; + } + case 0x9F: { /* SBC A,A */ + sbc(regA); + break; + } + case 0xA0: { /* AND B */ + and(regB); + break; + } + case 0xA1: { /* AND C */ + and(regC); + break; + } + case 0xA2: { /* AND D */ + and(regD); + break; + } + case 0xA3: { /* AND E */ + and(regE); + break; + } + case 0xA4: { /* AND H */ + and(regH); + break; + } + case 0xA5: { /* AND L */ + and(regL); + break; + } + case 0xA6: { /* AND (HL) */ + and(MemIoImpl.peek8(getRegHL())); + break; + } + case 0xA7: { /* AND A */ + and(regA); + break; + } + case 0xA8: { /* XOR B */ + xor(regB); + break; + } + case 0xA9: { /* XOR C */ + xor(regC); + break; + } + case 0xAA: { /* XOR D */ + xor(regD); + break; + } + case 0xAB: { /* XOR E */ + xor(regE); + break; + } + case 0xAC: { /* XOR H */ + xor(regH); + break; + } + case 0xAD: { /* XOR L */ + xor(regL); + break; + } + case 0xAE: { /* XOR (HL) */ + xor(MemIoImpl.peek8(getRegHL())); + break; + } + case 0xAF: { /* XOR A */ + xor(regA); + break; + } + case 0xB0: { /* OR B */ + or(regB); + break; + } + case 0xB1: { /* OR C */ + or(regC); + break; + } + case 0xB2: { /* OR D */ + or(regD); + break; + } + case 0xB3: { /* OR E */ + or(regE); + break; + } + case 0xB4: { /* OR H */ + or(regH); + break; + } + case 0xB5: { /* OR L */ + or(regL); + break; + } + case 0xB6: { /* OR (HL) */ + or(MemIoImpl.peek8(getRegHL())); + break; + } + case 0xB7: { /* OR A */ + or(regA); + break; + } + case 0xB8: { /* CP B */ + cp(regB); + break; + } + case 0xB9: { /* CP C */ + cp(regC); + break; + } + case 0xBA: { /* CP D */ + cp(regD); + break; + } + case 0xBB: { /* CP E */ + cp(regE); + break; + } + case 0xBC: { /* CP H */ + cp(regH); + break; + } + case 0xBD: { /* CP L */ + cp(regL); + break; + } + case 0xBE: { /* CP (HL) */ + cp(MemIoImpl.peek8(getRegHL())); + break; + } + case 0xBF: { /* CP A */ + cp(regA); + break; + } + case 0xC0: { /* RET NZ */ + MemIoImpl.addressOnBus(getPairIR(), 1); + if ((sz5h3pnFlags & ZERO_MASK) == 0) { + regPC = memptr = pop(); + } + break; + } + case 0xC1: { /* POP BC */ + setRegBC(pop()); + break; + } + case 0xC2: { /* JP NZ,nn */ + memptr = MemIoImpl.peek16(regPC); + if ((sz5h3pnFlags & ZERO_MASK) == 0) { + regPC = memptr; + break; + } + regPC = (regPC + 2) & 0xffff; + break; + } + case 0xC3: { /* JP nn */ + memptr = regPC = MemIoImpl.peek16(regPC); + break; + } + case 0xC4: { /* CALL NZ,nn */ + memptr = MemIoImpl.peek16(regPC); + if ((sz5h3pnFlags & ZERO_MASK) == 0) { + MemIoImpl.addressOnBus((regPC + 1) & 0xffff, 1); + push(regPC + 2); + regPC = memptr; + break; + } + regPC = (regPC + 2) & 0xffff; + break; + } + case 0xC5: { /* PUSH BC */ + MemIoImpl.addressOnBus(getPairIR(), 1); + push(getRegBC()); + break; + } + case 0xC6: { /* ADD A,n */ + add(MemIoImpl.peek8(regPC)); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0xC7: { /* RST 00H */ + MemIoImpl.addressOnBus(getPairIR(), 1); + push(regPC); + regPC = memptr = 0x00; + break; + } + case 0xC8: { /* RET Z */ + MemIoImpl.addressOnBus(getPairIR(), 1); + if ((sz5h3pnFlags & ZERO_MASK) != 0) { + regPC = memptr = pop(); + } + break; + } + case 0xC9: { /* RET */ + regPC = memptr = pop(); + break; + } + case 0xCA: { /* JP Z,nn */ + memptr = MemIoImpl.peek16(regPC); + if ((sz5h3pnFlags & ZERO_MASK) != 0) { + regPC = memptr; + break; + } + regPC = (regPC + 2) & 0xffff; + break; + } + case 0xCB: { /* Subconjunto de instrucciones */ + decodeCB(); + break; + } + case 0xCC: { /* CALL Z,nn */ + memptr = MemIoImpl.peek16(regPC); + if ((sz5h3pnFlags & ZERO_MASK) != 0) { + MemIoImpl.addressOnBus((regPC + 1) & 0xffff, 1); + push(regPC + 2); + regPC = memptr; + break; + } + regPC = (regPC + 2) & 0xffff; + break; + } + case 0xCD: { /* CALL nn */ + memptr = MemIoImpl.peek16(regPC); + MemIoImpl.addressOnBus((regPC + 1) & 0xffff, 1); + push(regPC + 2); + regPC = memptr; + break; + } + case 0xCE: { /* ADC A,n */ + adc(MemIoImpl.peek8(regPC)); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0xCF: { /* RST 08H */ + MemIoImpl.addressOnBus(getPairIR(), 1); + push(regPC); + regPC = memptr = 0x08; + break; + } + case 0xD0: { /* RET NC */ + MemIoImpl.addressOnBus(getPairIR(), 1); + if (!carryFlag) { + regPC = memptr = pop(); + } + break; + } + case 0xD1: { /* POP DE */ + setRegDE(pop()); + break; + } + case 0xD2: { /* JP NC,nn */ + memptr = MemIoImpl.peek16(regPC); + if (!carryFlag) { + regPC = memptr; + break; + } + regPC = (regPC + 2) & 0xffff; + break; + } + case 0xD3: { /* OUT (n),A */ + int work8 = MemIoImpl.peek8(regPC); + memptr = regA << 8; + MemIoImpl.outPort(memptr | work8, regA); + memptr |= ((work8 + 1) & 0xff); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0xD4: { /* CALL NC,nn */ + memptr = MemIoImpl.peek16(regPC); + if (!carryFlag) { + MemIoImpl.addressOnBus((regPC + 1) & 0xffff, 1); + push(regPC + 2); + regPC = memptr; + break; + } + regPC = (regPC + 2) & 0xffff; + break; + } + case 0xD5: { /* PUSH DE */ + MemIoImpl.addressOnBus(getPairIR(), 1); + push(getRegDE()); + break; + } + case 0xD6: { /* SUB n */ + sub(MemIoImpl.peek8(regPC)); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0xD7: { /* RST 10H */ + MemIoImpl.addressOnBus(getPairIR(), 1); + push(regPC); + regPC = memptr = 0x10; + break; + } + case 0xD8: { /* RET C */ + MemIoImpl.addressOnBus(getPairIR(), 1); + if (carryFlag) { + regPC = memptr = pop(); + } + break; + } + case 0xD9: { /* EXX */ + int work8 = regB; + regB = regBx; + regBx = work8; + + work8 = regC; + regC = regCx; + regCx = work8; + + work8 = regD; + regD = regDx; + regDx = work8; + + work8 = regE; + regE = regEx; + regEx = work8; + + work8 = regH; + regH = regHx; + regHx = work8; + + work8 = regL; + regL = regLx; + regLx = work8; + break; + } + case 0xDA: { /* JP C,nn */ + memptr = MemIoImpl.peek16(regPC); + if (carryFlag) { + regPC = memptr; + break; + } + regPC = (regPC + 2) & 0xffff; + break; + } + case 0xDB: { /* IN A,(n) */ + memptr = (regA << 8) | MemIoImpl.peek8(regPC); + regA = MemIoImpl.inPort(memptr++); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0xDC: { /* CALL C,nn */ + memptr = MemIoImpl.peek16(regPC); + if (carryFlag) { + MemIoImpl.addressOnBus((regPC + 1) & 0xffff, 1); + push(regPC + 2); + regPC = memptr; + break; + } + regPC = (regPC + 2) & 0xffff; + break; + } + case 0xDD: { /* Subconjunto de instrucciones */ + prefixOpcode = 0xDD; + break; + } + case 0xDE: { /* SBC A,n */ + sbc(MemIoImpl.peek8(regPC)); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0xDF: { /* RST 18H */ + MemIoImpl.addressOnBus(getPairIR(), 1); + push(regPC); + regPC = memptr = 0x18; + break; + } + case 0xE0: /* RET PO */ + MemIoImpl.addressOnBus(getPairIR(), 1); + if ((sz5h3pnFlags & PARITY_MASK) == 0) { + regPC = memptr = pop(); + } + break; + case 0xE1: /* POP HL */ + setRegHL(pop()); + break; + case 0xE2: /* JP PO,nn */ + memptr = MemIoImpl.peek16(regPC); + if ((sz5h3pnFlags & PARITY_MASK) == 0) { + regPC = memptr; + break; + } + regPC = (regPC + 2) & 0xffff; + break; + case 0xE3: { /* EX (SP),HL */ + // Instrucción de ejecución sutil. + int work16 = regH; + int work8 = regL; + setRegHL(MemIoImpl.peek16(regSP)); + MemIoImpl.addressOnBus((regSP + 1) & 0xffff, 1); + // No se usa poke16 porque el Z80 escribe los bytes AL REVES + MemIoImpl.poke8((regSP + 1) & 0xffff, work16); + MemIoImpl.poke8(regSP, work8); + MemIoImpl.addressOnBus(regSP, 2); + memptr = getRegHL(); + break; + } + case 0xE4: /* CALL PO,nn */ + memptr = MemIoImpl.peek16(regPC); + if ((sz5h3pnFlags & PARITY_MASK) == 0) { + MemIoImpl.addressOnBus((regPC + 1) & 0xffff, 1); + push(regPC + 2); + regPC = memptr; + break; + } + regPC = (regPC + 2) & 0xffff; + break; + case 0xE5: /* PUSH HL */ + MemIoImpl.addressOnBus(getPairIR(), 1); + push(getRegHL()); + break; + case 0xE6: /* AND n */ + and(MemIoImpl.peek8(regPC)); + regPC = (regPC + 1) & 0xffff; + break; + case 0xE7: /* RST 20H */ + MemIoImpl.addressOnBus(getPairIR(), 1); + push(regPC); + regPC = memptr = 0x20; + break; + case 0xE8: /* RET PE */ + MemIoImpl.addressOnBus(getPairIR(), 1); + if ((sz5h3pnFlags & PARITY_MASK) != 0) { + regPC = memptr = pop(); + } + break; + case 0xE9: /* JP (HL) */ + regPC = getRegHL(); + break; + case 0xEA: /* JP PE,nn */ + memptr = MemIoImpl.peek16(regPC); + if ((sz5h3pnFlags & PARITY_MASK) != 0) { + regPC = memptr; + break; + } + regPC = (regPC + 2) & 0xffff; + break; + case 0xEB: { /* EX DE,HL */ + int work8 = regH; + regH = regD; + regD = work8; + + work8 = regL; + regL = regE; + regE = work8; + break; + } + case 0xEC: /* CALL PE,nn */ + memptr = MemIoImpl.peek16(regPC); + if ((sz5h3pnFlags & PARITY_MASK) != 0) { + MemIoImpl.addressOnBus((regPC + 1) & 0xffff, 1); + push(regPC + 2); + regPC = memptr; + break; + } + regPC = (regPC + 2) & 0xffff; + break; + case 0xED: /*Subconjunto de instrucciones*/ + prefixOpcode = 0xED; + break; + case 0xEE: /* XOR n */ + xor(MemIoImpl.peek8(regPC)); + regPC = (regPC + 1) & 0xffff; + break; + case 0xEF: /* RST 28H */ + MemIoImpl.addressOnBus(getPairIR(), 1); + push(regPC); + regPC = memptr = 0x28; + break; + case 0xF0: /* RET P */ + MemIoImpl.addressOnBus(getPairIR(), 1); + if (sz5h3pnFlags < SIGN_MASK) { + regPC = memptr = pop(); + } + break; + case 0xF1: /* POP AF */ + setRegAF(pop()); + break; + case 0xF2: /* JP P,nn */ + memptr = MemIoImpl.peek16(regPC); + if (sz5h3pnFlags < SIGN_MASK) { + regPC = memptr; + break; + } + regPC = (regPC + 2) & 0xffff; + break; + case 0xF3: /* DI */ + ffIFF1 = ffIFF2 = false; + break; + case 0xF4: /* CALL P,nn */ + memptr = MemIoImpl.peek16(regPC); + if (sz5h3pnFlags < SIGN_MASK) { + MemIoImpl.addressOnBus((regPC + 1) & 0xffff, 1); + push(regPC + 2); + regPC = memptr; + break; + } + regPC = (regPC + 2) & 0xffff; + break; + case 0xF5: /* PUSH AF */ + MemIoImpl.addressOnBus(getPairIR(), 1); + push(getRegAF()); + break; + case 0xF6: /* OR n */ + or(MemIoImpl.peek8(regPC)); + regPC = (regPC + 1) & 0xffff; + break; + case 0xF7: /* RST 30H */ + MemIoImpl.addressOnBus(getPairIR(), 1); + push(regPC); + regPC = memptr = 0x30; + break; + case 0xF8: /* RET M */ + MemIoImpl.addressOnBus(getPairIR(), 1); + if (sz5h3pnFlags > 0x7f) { + regPC = memptr = pop(); + } + break; + case 0xF9: /* LD SP,HL */ + MemIoImpl.addressOnBus(getPairIR(), 2); + regSP = getRegHL(); + break; + case 0xFA: /* JP M,nn */ + memptr = MemIoImpl.peek16(regPC); + if (sz5h3pnFlags > 0x7f) { + regPC = memptr; + break; + } + regPC = (regPC + 2) & 0xffff; + break; + case 0xFB: /* EI */ + ffIFF1 = ffIFF2 = true; + pendingEI = true; + break; + case 0xFC: /* CALL M,nn */ + memptr = MemIoImpl.peek16(regPC); + if (sz5h3pnFlags > 0x7f) { + MemIoImpl.addressOnBus((regPC + 1) & 0xffff, 1); + push(regPC + 2); + regPC = memptr; + break; + } + regPC = (regPC + 2) & 0xffff; + break; + case 0xFD: /* Subconjunto de instrucciones */ + prefixOpcode = 0xFD; + break; + case 0xFE: /* CP n */ + cp(MemIoImpl.peek8(regPC)); + regPC = (regPC + 1) & 0xffff; + break; + case 0xFF: /* RST 38H */ + MemIoImpl.addressOnBus(getPairIR(), 1); + push(regPC); + regPC = memptr = 0x38; + } /* del switch( codigo ) */ + } + + //Subconjunto de instrucciones 0xCB + private void decodeCB() { + int opCode = MemIoImpl.fetchOpcode(regPC); + regPC = (regPC + 1) & 0xffff; + regR++; + + switch (opCode) { + case 0x00: { /* RLC B */ + regB = rlc(regB); + break; + } + case 0x01: { /* RLC C */ + regC = rlc(regC); + break; + } + case 0x02: { /* RLC D */ + regD = rlc(regD); + break; + } + case 0x03: { /* RLC E */ + regE = rlc(regE); + break; + } + case 0x04: { /* RLC H */ + regH = rlc(regH); + break; + } + case 0x05: { /* RLC L */ + regL = rlc(regL); + break; + } + case 0x06: { /* RLC (HL) */ + int work16 = getRegHL(); + int work8 = rlc(MemIoImpl.peek8(work16)); + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0x07: { /* RLC A */ + regA = rlc(regA); + break; + } + case 0x08: { /* RRC B */ + regB = rrc(regB); + break; + } + case 0x09: { /* RRC C */ + regC = rrc(regC); + break; + } + case 0x0A: { /* RRC D */ + regD = rrc(regD); + break; + } + case 0x0B: { /* RRC E */ + regE = rrc(regE); + break; + } + case 0x0C: { /* RRC H */ + regH = rrc(regH); + break; + } + case 0x0D: { /* RRC L */ + regL = rrc(regL); + break; + } + case 0x0E: { /* RRC (HL) */ + int work16 = getRegHL(); + int work8 = rrc(MemIoImpl.peek8(work16)); + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0x0F: { /* RRC A */ + regA = rrc(regA); + break; + } + case 0x10: { /* RL B */ + regB = rl(regB); + break; + } + case 0x11: { /* RL C */ + regC = rl(regC); + break; + } + case 0x12: { /* RL D */ + regD = rl(regD); + break; + } + case 0x13: { /* RL E */ + regE = rl(regE); + break; + } + case 0x14: { /* RL H */ + regH = rl(regH); + break; + } + case 0x15: { /* RL L */ + regL = rl(regL); + break; + } + case 0x16: { /* RL (HL) */ + int work16 = getRegHL(); + int work8 = rl(MemIoImpl.peek8(work16)); + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0x17: { /* RL A */ + regA = rl(regA); + break; + } + case 0x18: { /* RR B */ + regB = rr(regB); + break; + } + case 0x19: { /* RR C */ + regC = rr(regC); + break; + } + case 0x1A: { /* RR D */ + regD = rr(regD); + break; + } + case 0x1B: { /* RR E */ + regE = rr(regE); + break; + } + case 0x1C: { /*RR H*/ + regH = rr(regH); + break; + } + case 0x1D: { /* RR L */ + regL = rr(regL); + break; + } + case 0x1E: { /* RR (HL) */ + int work16 = getRegHL(); + int work8 = rr(MemIoImpl.peek8(work16)); + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0x1F: { /* RR A */ + regA = rr(regA); + break; + } + case 0x20: { /* SLA B */ + regB = sla(regB); + break; + } + case 0x21: { /* SLA C */ + regC = sla(regC); + break; + } + case 0x22: { /* SLA D */ + regD = sla(regD); + break; + } + case 0x23: { /* SLA E */ + regE = sla(regE); + break; + } + case 0x24: { /* SLA H */ + regH = sla(regH); + break; + } + case 0x25: { /* SLA L */ + regL = sla(regL); + break; + } + case 0x26: { /* SLA (HL) */ + int work16 = getRegHL(); + int work8 = sla(MemIoImpl.peek8(work16)); + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0x27: { /* SLA A */ + regA = sla(regA); + break; + } + case 0x28: { /* SRA B */ + regB = sra(regB); + break; + } + case 0x29: { /* SRA C */ + regC = sra(regC); + break; + } + case 0x2A: { /* SRA D */ + regD = sra(regD); + break; + } + case 0x2B: { /* SRA E */ + regE = sra(regE); + break; + } + case 0x2C: { /* SRA H */ + regH = sra(regH); + break; + } + case 0x2D: { /* SRA L */ + regL = sra(regL); + break; + } + case 0x2E: { /* SRA (HL) */ + int work16 = getRegHL(); + int work8 = sra(MemIoImpl.peek8(work16)); + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0x2F: { /* SRA A */ + regA = sra(regA); + break; + } + case 0x30: { /* SLL B */ + regB = sll(regB); + break; + } + case 0x31: { /* SLL C */ + regC = sll(regC); + break; + } + case 0x32: { /* SLL D */ + regD = sll(regD); + break; + } + case 0x33: { /* SLL E */ + regE = sll(regE); + break; + } + case 0x34: { /* SLL H */ + regH = sll(regH); + break; + } + case 0x35: { /* SLL L */ + regL = sll(regL); + break; + } + case 0x36: { /* SLL (HL) */ + int work16 = getRegHL(); + int work8 = sll(MemIoImpl.peek8(work16)); + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0x37: { /* SLL A */ + regA = sll(regA); + break; + } + case 0x38: { /* SRL B */ + regB = srl(regB); + break; + } + case 0x39: { /* SRL C */ + regC = srl(regC); + break; + } + case 0x3A: { /* SRL D */ + regD = srl(regD); + break; + } + case 0x3B: { /* SRL E */ + regE = srl(regE); + break; + } + case 0x3C: { /* SRL H */ + regH = srl(regH); + break; + } + case 0x3D: { /* SRL L */ + regL = srl(regL); + break; + } + case 0x3E: { /* SRL (HL) */ + int work16 = getRegHL(); + int work8 = srl(MemIoImpl.peek8(work16)); + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0x3F: { /* SRL A */ + regA = srl(regA); + break; + } + case 0x40: { /* BIT 0,B */ + bit(0x01, regB); + break; + } + case 0x41: { /* BIT 0,C */ + bit(0x01, regC); + break; + } + case 0x42: { /* BIT 0,D */ + bit(0x01, regD); + break; + } + case 0x43: { /* BIT 0,E */ + bit(0x01, regE); + break; + } + case 0x44: { /* BIT 0,H */ + bit(0x01, regH); + break; + } + case 0x45: { /* BIT 0,L */ + bit(0x01, regL); + break; + } + case 0x46: { /* BIT 0,(HL) */ + int work16 = getRegHL(); + bit(0x01, MemIoImpl.peek8(work16)); + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) + | ((memptr >>> 8) & FLAG_53_MASK); + MemIoImpl.addressOnBus(work16, 1); + break; + } + case 0x47: { /* BIT 0,A */ + bit(0x01, regA); + break; + } + case 0x48: { /* BIT 1,B */ + bit(0x02, regB); + break; + } + case 0x49: { /* BIT 1,C */ + bit(0x02, regC); + break; + } + case 0x4A: { /* BIT 1,D */ + bit(0x02, regD); + break; + } + case 0x4B: { /* BIT 1,E */ + bit(0x02, regE); + break; + } + case 0x4C: { /* BIT 1,H */ + bit(0x02, regH); + break; + } + case 0x4D: { /* BIT 1,L */ + bit(0x02, regL); + break; + } + case 0x4E: { /* BIT 1,(HL) */ + int work16 = getRegHL(); + bit(0x02, MemIoImpl.peek8(work16)); + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) + | ((memptr >>> 8) & FLAG_53_MASK); + MemIoImpl.addressOnBus(work16, 1); + break; + } + case 0x4F: { /* BIT 1,A */ + bit(0x02, regA); + break; + } + case 0x50: { /* BIT 2,B */ + bit(0x04, regB); + break; + } + case 0x51: { /* BIT 2,C */ + bit(0x04, regC); + break; + } + case 0x52: { /* BIT 2,D */ + bit(0x04, regD); + break; + } + case 0x53: { /* BIT 2,E */ + bit(0x04, regE); + break; + } + case 0x54: { /* BIT 2,H */ + bit(0x04, regH); + break; + } + case 0x55: { /* BIT 2,L */ + bit(0x04, regL); + break; + } + case 0x56: { /* BIT 2,(HL) */ + int work16 = getRegHL(); + bit(0x04, MemIoImpl.peek8(work16)); + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) + | ((memptr >>> 8) & FLAG_53_MASK); + MemIoImpl.addressOnBus(work16, 1); + break; + } + case 0x57: { /* BIT 2,A */ + bit(0x04, regA); + break; + } + case 0x58: { /* BIT 3,B */ + bit(0x08, regB); + break; + } + case 0x59: { /* BIT 3,C */ + bit(0x08, regC); + break; + } + case 0x5A: { /* BIT 3,D */ + bit(0x08, regD); + break; + } + case 0x5B: { /* BIT 3,E */ + bit(0x08, regE); + break; + } + case 0x5C: { /* BIT 3,H */ + bit(0x08, regH); + break; + } + case 0x5D: { /* BIT 3,L */ + bit(0x08, regL); + break; + } + case 0x5E: { /* BIT 3,(HL) */ + int work16 = getRegHL(); + bit(0x08, MemIoImpl.peek8(work16)); + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) + | ((memptr >>> 8) & FLAG_53_MASK); + MemIoImpl.addressOnBus(work16, 1); + break; + } + case 0x5F: { /* BIT 3,A */ + bit(0x08, regA); + break; + } + case 0x60: { /* BIT 4,B */ + bit(0x10, regB); + break; + } + case 0x61: { /* BIT 4,C */ + bit(0x10, regC); + break; + } + case 0x62: { /* BIT 4,D */ + bit(0x10, regD); + break; + } + case 0x63: { /* BIT 4,E */ + bit(0x10, regE); + break; + } + case 0x64: { /* BIT 4,H */ + bit(0x10, regH); + break; + } + case 0x65: { /* BIT 4,L */ + bit(0x10, regL); + break; + } + case 0x66: { /* BIT 4,(HL) */ + int work16 = getRegHL(); + bit(0x10, MemIoImpl.peek8(work16)); + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) + | ((memptr >>> 8) & FLAG_53_MASK); + MemIoImpl.addressOnBus(work16, 1); + break; + } + case 0x67: { /* BIT 4,A */ + bit(0x10, regA); + break; + } + case 0x68: { /* BIT 5,B */ + bit(0x20, regB); + break; + } + case 0x69: { /* BIT 5,C */ + bit(0x20, regC); + break; + } + case 0x6A: { /* BIT 5,D */ + bit(0x20, regD); + break; + } + case 0x6B: { /* BIT 5,E */ + bit(0x20, regE); + break; + } + case 0x6C: { /* BIT 5,H */ + bit(0x20, regH); + break; + } + case 0x6D: { /* BIT 5,L */ + bit(0x20, regL); + break; + } + case 0x6E: { /* BIT 5,(HL) */ + int work16 = getRegHL(); + bit(0x20, MemIoImpl.peek8(work16)); + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) + | ((memptr >>> 8) & FLAG_53_MASK); + MemIoImpl.addressOnBus(work16, 1); + break; + } + case 0x6F: { /* BIT 5,A */ + bit(0x20, regA); + break; + } + case 0x70: { /* BIT 6,B */ + bit(0x40, regB); + break; + } + case 0x71: { /* BIT 6,C */ + bit(0x40, regC); + break; + } + case 0x72: { /* BIT 6,D */ + bit(0x40, regD); + break; + } + case 0x73: { /* BIT 6,E */ + bit(0x40, regE); + break; + } + case 0x74: { /* BIT 6,H */ + bit(0x40, regH); + break; + } + case 0x75: { /* BIT 6,L */ + bit(0x40, regL); + break; + } + case 0x76: { /* BIT 6,(HL) */ + int work16 = getRegHL(); + bit(0x40, MemIoImpl.peek8(work16)); + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) + | ((memptr >>> 8) & FLAG_53_MASK); + MemIoImpl.addressOnBus(work16, 1); + break; + } + case 0x77: { /* BIT 6,A */ + bit(0x40, regA); + break; + } + case 0x78: { /* BIT 7,B */ + bit(0x80, regB); + break; + } + case 0x79: { /* BIT 7,C */ + bit(0x80, regC); + break; + } + case 0x7A: { /* BIT 7,D */ + bit(0x80, regD); + break; + } + case 0x7B: { /* BIT 7,E */ + bit(0x80, regE); + break; + } + case 0x7C: { /* BIT 7,H */ + bit(0x80, regH); + break; + } + case 0x7D: { /* BIT 7,L */ + bit(0x80, regL); + break; + } + case 0x7E: { /* BIT 7,(HL) */ + int work16 = getRegHL(); + bit(0x80, MemIoImpl.peek8(work16)); + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) + | ((memptr >>> 8) & FLAG_53_MASK); + MemIoImpl.addressOnBus(work16, 1); + break; + } + case 0x7F: { /* BIT 7,A */ + bit(0x80, regA); + break; + } + case 0x80: { /* RES 0,B */ + regB &= 0xFE; + break; + } + case 0x81: { /* RES 0,C */ + regC &= 0xFE; + break; + } + case 0x82: { /* RES 0,D */ + regD &= 0xFE; + break; + } + case 0x83: { /* RES 0,E */ + regE &= 0xFE; + break; + } + case 0x84: { /* RES 0,H */ + regH &= 0xFE; + break; + } + case 0x85: { /* RES 0,L */ + regL &= 0xFE; + break; + } + case 0x86: { /* RES 0,(HL) */ + int work16 = getRegHL(); + int work8 = MemIoImpl.peek8(work16) & 0xFE; + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0x87: { /* RES 0,A */ + regA &= 0xFE; + break; + } + case 0x88: { /* RES 1,B */ + regB &= 0xFD; + break; + } + case 0x89: { /* RES 1,C */ + regC &= 0xFD; + break; + } + case 0x8A: { /* RES 1,D */ + regD &= 0xFD; + break; + } + case 0x8B: { /* RES 1,E */ + regE &= 0xFD; + break; + } + case 0x8C: { /* RES 1,H */ + regH &= 0xFD; + break; + } + case 0x8D: { /* RES 1,L */ + regL &= 0xFD; + break; + } + case 0x8E: { /* RES 1,(HL) */ + int work16 = getRegHL(); + int work8 = MemIoImpl.peek8(work16) & 0xFD; + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0x8F: { /* RES 1,A */ + regA &= 0xFD; + break; + } + case 0x90: { /* RES 2,B */ + regB &= 0xFB; + break; + } + case 0x91: { /* RES 2,C */ + regC &= 0xFB; + break; + } + case 0x92: { /* RES 2,D */ + regD &= 0xFB; + break; + } + case 0x93: { /* RES 2,E */ + regE &= 0xFB; + break; + } + case 0x94: { /* RES 2,H */ + regH &= 0xFB; + break; + } + case 0x95: { /* RES 2,L */ + regL &= 0xFB; + break; + } + case 0x96: { /* RES 2,(HL) */ + int work16 = getRegHL(); + int work8 = MemIoImpl.peek8(work16) & 0xFB; + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0x97: { /* RES 2,A */ + regA &= 0xFB; + break; + } + case 0x98: { /* RES 3,B */ + regB &= 0xF7; + break; + } + case 0x99: { /* RES 3,C */ + regC &= 0xF7; + break; + } + case 0x9A: { /* RES 3,D */ + regD &= 0xF7; + break; + } + case 0x9B: { /* RES 3,E */ + regE &= 0xF7; + break; + } + case 0x9C: { /* RES 3,H */ + regH &= 0xF7; + break; + } + case 0x9D: { /* RES 3,L */ + regL &= 0xF7; + break; + } + case 0x9E: { /* RES 3,(HL) */ + int work16 = getRegHL(); + int work8 = MemIoImpl.peek8(work16) & 0xF7; + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0x9F: { /* RES 3,A */ + regA &= 0xF7; + break; + } + case 0xA0: { /* RES 4,B */ + regB &= 0xEF; + break; + } + case 0xA1: { /* RES 4,C */ + regC &= 0xEF; + break; + } + case 0xA2: { /* RES 4,D */ + regD &= 0xEF; + break; + } + case 0xA3: { /* RES 4,E */ + regE &= 0xEF; + break; + } + case 0xA4: { /* RES 4,H */ + regH &= 0xEF; + break; + } + case 0xA5: { /* RES 4,L */ + regL &= 0xEF; + break; + } + case 0xA6: { /* RES 4,(HL) */ + int work16 = getRegHL(); + int work8 = MemIoImpl.peek8(work16) & 0xEF; + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0xA7: { /* RES 4,A */ + regA &= 0xEF; + break; + } + case 0xA8: { /* RES 5,B */ + regB &= 0xDF; + break; + } + case 0xA9: { /* RES 5,C */ + regC &= 0xDF; + break; + } + case 0xAA: { /* RES 5,D */ + regD &= 0xDF; + break; + } + case 0xAB: { /* RES 5,E */ + regE &= 0xDF; + break; + } + case 0xAC: { /* RES 5,H */ + regH &= 0xDF; + break; + } + case 0xAD: { /* RES 5,L */ + regL &= 0xDF; + break; + } + case 0xAE: { /* RES 5,(HL) */ + int work16 = getRegHL(); + int work8 = MemIoImpl.peek8(work16) & 0xDF; + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0xAF: { /* RES 5,A */ + regA &= 0xDF; + break; + } + case 0xB0: { /* RES 6,B */ + regB &= 0xBF; + break; + } + case 0xB1: { /* RES 6,C */ + regC &= 0xBF; + break; + } + case 0xB2: { /* RES 6,D */ + regD &= 0xBF; + break; + } + case 0xB3: { /* RES 6,E */ + regE &= 0xBF; + break; + } + case 0xB4: { /* RES 6,H */ + regH &= 0xBF; + break; + } + case 0xB5: { /* RES 6,L */ + regL &= 0xBF; + break; + } + case 0xB6: { /* RES 6,(HL) */ + int work16 = getRegHL(); + int work8 = MemIoImpl.peek8(work16) & 0xBF; + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0xB7: { /* RES 6,A */ + regA &= 0xBF; + break; + } + case 0xB8: { /* RES 7,B */ + regB &= 0x7F; + break; + } + case 0xB9: { /* RES 7,C */ + regC &= 0x7F; + break; + } + case 0xBA: { /* RES 7,D */ + regD &= 0x7F; + break; + } + case 0xBB: { /* RES 7,E */ + regE &= 0x7F; + break; + } + case 0xBC: { /* RES 7,H */ + regH &= 0x7F; + break; + } + case 0xBD: { /* RES 7,L */ + regL &= 0x7F; + break; + } + case 0xBE: { /* RES 7,(HL) */ + int work16 = getRegHL(); + int work8 = MemIoImpl.peek8(work16) & 0x7F; + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0xBF: { /* RES 7,A */ + regA &= 0x7F; + break; + } + case 0xC0: { /* SET 0,B */ + regB |= 0x01; + break; + } + case 0xC1: { /* SET 0,C */ + regC |= 0x01; + break; + } + case 0xC2: { /* SET 0,D */ + regD |= 0x01; + break; + } + case 0xC3: { /* SET 0,E */ + regE |= 0x01; + break; + } + case 0xC4: { /* SET 0,H */ + regH |= 0x01; + break; + } + case 0xC5: { /* SET 0,L */ + regL |= 0x01; + break; + } + case 0xC6: { /* SET 0,(HL) */ + int work16 = getRegHL(); + int work8 = MemIoImpl.peek8(work16) | 0x01; + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0xC7: { /* SET 0,A */ + regA |= 0x01; + break; + } + case 0xC8: { /* SET 1,B */ + regB |= 0x02; + break; + } + case 0xC9: { /* SET 1,C */ + regC |= 0x02; + break; + } + case 0xCA: { /* SET 1,D */ + regD |= 0x02; + break; + } + case 0xCB: { /* SET 1,E */ + regE |= 0x02; + break; + } + case 0xCC: { /* SET 1,H */ + regH |= 0x02; + break; + } + case 0xCD: { /* SET 1,L */ + regL |= 0x02; + break; + } + case 0xCE: { /* SET 1,(HL) */ + int work16 = getRegHL(); + int work8 = MemIoImpl.peek8(work16) | 0x02; + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0xCF: { /* SET 1,A */ + regA |= 0x02; + break; + } + case 0xD0: { /* SET 2,B */ + regB |= 0x04; + break; + } + case 0xD1: { /* SET 2,C */ + regC |= 0x04; + break; + } + case 0xD2: { /* SET 2,D */ + regD |= 0x04; + break; + } + case 0xD3: { /* SET 2,E */ + regE |= 0x04; + break; + } + case 0xD4: { /* SET 2,H */ + regH |= 0x04; + break; + } + case 0xD5: { /* SET 2,L */ + regL |= 0x04; + break; + } + case 0xD6: { /* SET 2,(HL) */ + int work16 = getRegHL(); + int work8 = MemIoImpl.peek8(work16) | 0x04; + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0xD7: { /* SET 2,A */ + regA |= 0x04; + break; + } + case 0xD8: { /* SET 3,B */ + regB |= 0x08; + break; + } + case 0xD9: { /* SET 3,C */ + regC |= 0x08; + break; + } + case 0xDA: { /* SET 3,D */ + regD |= 0x08; + break; + } + case 0xDB: { /* SET 3,E */ + regE |= 0x08; + break; + } + case 0xDC: { /* SET 3,H */ + regH |= 0x08; + break; + } + case 0xDD: { /* SET 3,L */ + regL |= 0x08; + break; + } + case 0xDE: { /* SET 3,(HL) */ + int work16 = getRegHL(); + int work8 = MemIoImpl.peek8(work16) | 0x08; + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0xDF: { /* SET 3,A */ + regA |= 0x08; + break; + } + case 0xE0: { /* SET 4,B */ + regB |= 0x10; + break; + } + case 0xE1: { /* SET 4,C */ + regC |= 0x10; + break; + } + case 0xE2: { /* SET 4,D */ + regD |= 0x10; + break; + } + case 0xE3: { /* SET 4,E */ + regE |= 0x10; + break; + } + case 0xE4: { /* SET 4,H */ + regH |= 0x10; + break; + } + case 0xE5: { /* SET 4,L */ + regL |= 0x10; + break; + } + case 0xE6: { /* SET 4,(HL) */ + int work16 = getRegHL(); + int work8 = MemIoImpl.peek8(work16) | 0x10; + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0xE7: { /* SET 4,A */ + regA |= 0x10; + break; + } + case 0xE8: { /* SET 5,B */ + regB |= 0x20; + break; + } + case 0xE9: { /* SET 5,C */ + regC |= 0x20; + break; + } + case 0xEA: { /* SET 5,D */ + regD |= 0x20; + break; + } + case 0xEB: { /* SET 5,E */ + regE |= 0x20; + break; + } + case 0xEC: { /* SET 5,H */ + regH |= 0x20; + break; + } + case 0xED: { /* SET 5,L */ + regL |= 0x20; + break; + } + case 0xEE: { /* SET 5,(HL) */ + int work16 = getRegHL(); + int work8 = MemIoImpl.peek8(work16) | 0x20; + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0xEF: { /* SET 5,A */ + regA |= 0x20; + break; + } + case 0xF0: { /* SET 6,B */ + regB |= 0x40; + break; + } + case 0xF1: { /* SET 6,C */ + regC |= 0x40; + break; + } + case 0xF2: { /* SET 6,D */ + regD |= 0x40; + break; + } + case 0xF3: { /* SET 6,E */ + regE |= 0x40; + break; + } + case 0xF4: { /* SET 6,H */ + regH |= 0x40; + break; + } + case 0xF5: { /* SET 6,L */ + regL |= 0x40; + break; + } + case 0xF6: { /* SET 6,(HL) */ + int work16 = getRegHL(); + int work8 = MemIoImpl.peek8(work16) | 0x40; + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0xF7: { /* SET 6,A */ + regA |= 0x40; + break; + } + case 0xF8: { /* SET 7,B */ + regB |= 0x80; + break; + } + case 0xF9: { /* SET 7,C */ + regC |= 0x80; + break; + } + case 0xFA: { /* SET 7,D */ + regD |= 0x80; + break; + } + case 0xFB: { /* SET 7,E */ + regE |= 0x80; + break; + } + case 0xFC: { /* SET 7,H */ + regH |= 0x80; + break; + } + case 0xFD: { /* SET 7,L */ + regL |= 0x80; + break; + } + case 0xFE: { /* SET 7,(HL) */ + int work16 = getRegHL(); + int work8 = MemIoImpl.peek8(work16) | 0x80; + MemIoImpl.addressOnBus(work16, 1); + MemIoImpl.poke8(work16, work8); + break; + } + case 0xFF: { /* SET 7,A */ + regA |= 0x80; + break; + } + default: { +// System.out.println("Error instrucción CB " + Integer.toHexString(opCode)); + break; + } + } + } + + //Subconjunto de instrucciones 0xDD / 0xFD + /* + * Hay que tener en cuenta el manejo de secuencias códigos DD/FD que no + * hacen nada. Según el apartado 3.7 del documento + * [http://www.myquest.nl/z80undocumented/z80-documented-v0.91.pdf] + * secuencias de códigos como FD DD 00 21 00 10 NOP NOP NOP LD HL,1000h + * activan IY con el primer FD, IX con el segundo DD y vuelven al + * registro HL con el código NOP. Es decir, si detrás del código DD/FD no + * viene una instrucción que maneje el registro HL, el código DD/FD + * "se olvida" y hay que procesar la instrucción como si nunca se + * hubiera visto el prefijo (salvo por los 4 t-estados que ha costado). + * Naturalmente, en una serie repetida de DDFD no hay que comprobar las + * interrupciones entre cada prefijo. + */ + private int decodeDDFD(int opCode, int regIXY) { + prefixOpcode = 0; + switch (opCode) { + case 0x09: { /* ADD IX,BC */ + MemIoImpl.addressOnBus(getPairIR(), 7); + regIXY = add16(regIXY, getRegBC()); + break; + } + case 0x19: { /* ADD IX,DE */ + MemIoImpl.addressOnBus(getPairIR(), 7); + regIXY = add16(regIXY, getRegDE()); + break; + } + case 0x21: { /* LD IX,nn */ + regIXY = MemIoImpl.peek16(regPC); + regPC = (regPC + 2) & 0xffff; + break; + } + case 0x22: { /* LD (nn),IX */ + memptr = MemIoImpl.peek16(regPC); + MemIoImpl.poke16(memptr++, regIXY); + regPC = (regPC + 2) & 0xffff; + break; + } + case 0x23: { /* INC IX */ + MemIoImpl.addressOnBus(getPairIR(), 2); + regIXY = (regIXY + 1) & 0xffff; + break; + } + case 0x24: { /* INC IXh */ + regIXY = (inc8(regIXY >>> 8) << 8) | (regIXY & 0xff); + break; + } + case 0x25: { /* DEC IXh */ + regIXY = (dec8(regIXY >>> 8) << 8) | (regIXY & 0xff); + break; + } + case 0x26: { /* LD IXh,n */ + regIXY = (MemIoImpl.peek8(regPC) << 8) | (regIXY & 0xff); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x29: { /* ADD IX,IX */ + MemIoImpl.addressOnBus(getPairIR(), 7); + regIXY = add16(regIXY, regIXY); + break; + } + case 0x2A: { /* LD IX,(nn) */ + memptr = MemIoImpl.peek16(regPC); + regIXY = MemIoImpl.peek16(memptr++); + regPC = (regPC + 2) & 0xffff; + break; + } + case 0x2B: { /* DEC IX */ + MemIoImpl.addressOnBus(getPairIR(), 2); + regIXY = (regIXY - 1) & 0xffff; + break; + } + case 0x2C: { /* INC IXl */ + regIXY = (regIXY & 0xff00) | inc8(regIXY & 0xff); + break; + } + case 0x2D: { /* DEC IXl */ + regIXY = (regIXY & 0xff00) | dec8(regIXY & 0xff); + break; + } + case 0x2E: { /* LD IXl,n */ + regIXY = (regIXY & 0xff00) | MemIoImpl.peek8(regPC); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x34: { /* INC (IX+d) */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + MemIoImpl.addressOnBus(regPC, 5); + int work8 = MemIoImpl.peek8(memptr); + MemIoImpl.addressOnBus(memptr, 1); + MemIoImpl.poke8(memptr, inc8(work8)); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x35: { /* DEC (IX+d) */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + MemIoImpl.addressOnBus(regPC, 5); + int work8 = MemIoImpl.peek8(memptr); + MemIoImpl.addressOnBus(memptr, 1); + MemIoImpl.poke8(memptr, dec8(work8)); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x36: { /* LD (IX+d),n */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + regPC = (regPC + 1) & 0xffff; + int work8 = MemIoImpl.peek8(regPC); + MemIoImpl.addressOnBus(regPC, 2); + regPC = (regPC + 1) & 0xffff; + MemIoImpl.poke8(memptr, work8); + break; + } + case 0x39: { /* ADD IX,SP */ + MemIoImpl.addressOnBus(getPairIR(), 7); + regIXY = add16(regIXY, regSP); + break; + } + case 0x44: { /* LD B,IXh */ + regB = regIXY >>> 8; + break; + } + case 0x45: { /* LD B,IXl */ + regB = regIXY & 0xff; + break; + } + case 0x46: { /* LD B,(IX+d) */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + MemIoImpl.addressOnBus(regPC, 5); + regB = MemIoImpl.peek8(memptr); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x4C: { /* LD C,IXh */ + regC = regIXY >>> 8; + break; + } + case 0x4D: { /* LD C,IXl */ + regC = regIXY & 0xff; + break; + } + case 0x4E: { /* LD C,(IX+d) */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + MemIoImpl.addressOnBus(regPC, 5); + regC = MemIoImpl.peek8(memptr); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x54: { /* LD D,IXh */ + regD = regIXY >>> 8; + break; + } + case 0x55: { /* LD D,IXl */ + regD = regIXY & 0xff; + break; + } + case 0x56: { /* LD D,(IX+d) */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + MemIoImpl.addressOnBus(regPC, 5); + regD = MemIoImpl.peek8(memptr); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x5C: { /* LD E,IXh */ + regE = regIXY >>> 8; + break; + } + case 0x5D: { /* LD E,IXl */ + regE = regIXY & 0xff; + break; + } + case 0x5E: { /* LD E,(IX+d) */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + MemIoImpl.addressOnBus(regPC, 5); + regE = MemIoImpl.peek8(memptr); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x60: { /* LD IXh,B */ + regIXY = (regIXY & 0x00ff) | (regB << 8); + break; + } + case 0x61: { /* LD IXh,C */ + regIXY = (regIXY & 0x00ff) | (regC << 8); + break; + } + case 0x62: { /* LD IXh,D */ + regIXY = (regIXY & 0x00ff) | (regD << 8); + break; + } + case 0x63: { /* LD IXh,E */ + regIXY = (regIXY & 0x00ff) | (regE << 8); + break; + } + case 0x64: { /* LD IXh,IXh */ + break; + } + case 0x65: { /* LD IXh,IXl */ + regIXY = (regIXY & 0x00ff) | ((regIXY & 0xff) << 8); + break; + } + case 0x66: { /* LD H,(IX+d) */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + MemIoImpl.addressOnBus(regPC, 5); + regH = MemIoImpl.peek8(memptr); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x67: { /* LD IXh,A */ + regIXY = (regIXY & 0x00ff) | (regA << 8); + break; + } + case 0x68: { /* LD IXl,B */ + regIXY = (regIXY & 0xff00) | regB; + break; + } + case 0x69: { /* LD IXl,C */ + regIXY = (regIXY & 0xff00) | regC; + break; + } + case 0x6A: { /* LD IXl,D */ + regIXY = (regIXY & 0xff00) | regD; + break; + } + case 0x6B: { /* LD IXl,E */ + regIXY = (regIXY & 0xff00) | regE; + break; + } + case 0x6C: { /* LD IXl,IXh */ + regIXY = (regIXY & 0xff00) | (regIXY >>> 8); + break; + } + case 0x6D: { /* LD IXl,IXl */ + break; + } + case 0x6E: { /* LD L,(IX+d) */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + MemIoImpl.addressOnBus(regPC, 5); + regL = MemIoImpl.peek8(memptr); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x6F: { /* LD IXl,A */ + regIXY = (regIXY & 0xff00) | regA; + break; + } + case 0x70: { /* LD (IX+d),B */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + MemIoImpl.addressOnBus(regPC, 5); + MemIoImpl.poke8(memptr, regB); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x71: { /* LD (IX+d),C */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + MemIoImpl.addressOnBus(regPC, 5); + MemIoImpl.poke8(memptr, regC); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x72: { /* LD (IX+d),D */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + MemIoImpl.addressOnBus(regPC, 5); + MemIoImpl.poke8(memptr, regD); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x73: { /* LD (IX+d),E */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + MemIoImpl.addressOnBus(regPC, 5); + MemIoImpl.poke8(memptr, regE); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x74: { /* LD (IX+d),H */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + MemIoImpl.addressOnBus(regPC, 5); + MemIoImpl.poke8(memptr, regH); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x75: { /* LD (IX+d),L */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + MemIoImpl.addressOnBus(regPC, 5); + MemIoImpl.poke8(memptr, regL); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x77: { /* LD (IX+d),A */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + MemIoImpl.addressOnBus(regPC, 5); + MemIoImpl.poke8(memptr, regA); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x7C: { /* LD A,IXh */ + regA = regIXY >>> 8; + break; + } + case 0x7D: { /* LD A,IXl */ + regA = regIXY & 0xff; + break; + } + case 0x7E: { /* LD A,(IX+d) */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + MemIoImpl.addressOnBus(regPC, 5); + regA = MemIoImpl.peek8(memptr); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x84: { /* ADD A,IXh */ + add(regIXY >>> 8); + break; + } + case 0x85: { /* ADD A,IXl */ + add(regIXY & 0xff); + break; + } + case 0x86: { /* ADD A,(IX+d) */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + MemIoImpl.addressOnBus(regPC, 5); + add(MemIoImpl.peek8(memptr)); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x8C: { /* ADC A,IXh */ + adc(regIXY >>> 8); + break; + } + case 0x8D: { /* ADC A,IXl */ + adc(regIXY & 0xff); + break; + } + case 0x8E: { /* ADC A,(IX+d) */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + MemIoImpl.addressOnBus(regPC, 5); + adc(MemIoImpl.peek8(memptr)); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x94: { /* SUB IXh */ + sub(regIXY >>> 8); + break; + } + case 0x95: { /* SUB IXl */ + sub(regIXY & 0xff); + break; + } + case 0x96: { /* SUB (IX+d) */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + MemIoImpl.addressOnBus(regPC, 5); + sub(MemIoImpl.peek8(memptr)); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0x9C: { /* SBC A,IXh */ + sbc(regIXY >>> 8); + break; + } + case 0x9D: { /* SBC A,IXl */ + sbc(regIXY & 0xff); + break; + } + case 0x9E: { /* SBC A,(IX+d) */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + MemIoImpl.addressOnBus(regPC, 5); + sbc(MemIoImpl.peek8(memptr)); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0xA4: { /* AND IXh */ + and(regIXY >>> 8); + break; + } + case 0xA5: { /* AND IXl */ + and(regIXY & 0xff); + break; + } + case 0xA6: { /* AND (IX+d) */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + MemIoImpl.addressOnBus(regPC, 5); + and(MemIoImpl.peek8(memptr)); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0xAC: { /* XOR IXh */ + xor(regIXY >>> 8); + break; + } + case 0xAD: { /* XOR IXl */ + xor(regIXY & 0xff); + break; + } + case 0xAE: { /* XOR (IX+d) */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + MemIoImpl.addressOnBus(regPC, 5); + xor(MemIoImpl.peek8(memptr)); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0xB4: { /* OR IXh */ + or(regIXY >>> 8); + break; + } + case 0xB5: { /* OR IXl */ + or(regIXY & 0xff); + break; + } + case 0xB6: { /* OR (IX+d) */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + MemIoImpl.addressOnBus(regPC, 5); + or(MemIoImpl.peek8(memptr)); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0xBC: { /* CP IXh */ + cp(regIXY >>> 8); + break; + } + case 0xBD: { /* CP IXl */ + cp(regIXY & 0xff); + break; + } + case 0xBE: { /* CP (IX+d) */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + MemIoImpl.addressOnBus(regPC, 5); + cp(MemIoImpl.peek8(memptr)); + regPC = (regPC + 1) & 0xffff; + break; + } + case 0xCB: { /* Subconjunto de instrucciones */ + memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; + regPC = (regPC + 1) & 0xffff; + opCode = MemIoImpl.peek8(regPC); + MemIoImpl.addressOnBus(regPC, 2); + regPC = (regPC + 1) & 0xffff; + if (opCode < 0x80) { + decodeDDFDCBto7F(opCode, memptr); + } else { + decodeDDFDCBtoFF(opCode, memptr); + } + break; + } + case 0xDD: { + prefixOpcode = 0xDD; + break; + } + case 0xE1: { /* POP IX */ + regIXY = pop(); + break; + } + case 0xE3: { /* EX (SP),IX */ + // Instrucción de ejecución sutil como pocas... atento al dato. + int work16 = regIXY; + regIXY = MemIoImpl.peek16(regSP); + MemIoImpl.addressOnBus((regSP + 1) & 0xffff, 1); + MemIoImpl.poke8((regSP + 1) & 0xffff, work16 >>> 8); + MemIoImpl.poke8(regSP, work16); + MemIoImpl.addressOnBus(regSP, 2); + memptr = regIXY; + break; + } + case 0xE5: { /* PUSH IX */ + MemIoImpl.addressOnBus(getPairIR(), 1); + push(regIXY); + break; + } + case 0xE9: { /* JP (IX) */ + regPC = regIXY; + break; + } + case 0xED: { + prefixOpcode = 0xED; + break; + } + case 0xF9: { /* LD SP,IX */ + MemIoImpl.addressOnBus(getPairIR(), 2); + regSP = regIXY; + break; + } + case 0xFD: { + prefixOpcode = 0xFD; + break; + } + default: { + // Detrás de un DD/FD o varios en secuencia venía un código + // que no correspondía con una instrucción que involucra a + // IX o IY. Se trata como si fuera un código normal. + // Sin esto, además de emular mal, falla el test + // ld , de ZEXALL. + +// System.out.println("Error instrucción DD/FD" + Integer.toHexString(opCode)); + + if (breakpointAt[regPC]) { + opCode = NotifyImpl.breakpoint(regPC, opCode); + } + + decodeOpcode(opCode); + break; + } + } + return regIXY; + } + + // Subconjunto de instrucciones 0xDDCB desde el código 0x00 hasta el 0x7F + private void decodeDDFDCBto7F(int opCode, int address) { + + switch (opCode) { + case 0x00: { /* RLC (IX+d),B */ + regB = rlc(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regB); + break; + } + case 0x01: { /* RLC (IX+d),C */ + regC = rlc(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regC); + break; + } + case 0x02: { /* RLC (IX+d),D */ + regD = rlc(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regD); + break; + } + case 0x03: { /* RLC (IX+d),E */ + regE = rlc(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regE); + break; + } + case 0x04: { /* RLC (IX+d),H */ + regH = rlc(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regH); + break; + } + case 0x05: { /* RLC (IX+d),L */ + regL = rlc(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regL); + break; + } + case 0x06: { /* RLC (IX+d) */ + int work8 = rlc(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, work8); + break; + } + case 0x07: { /* RLC (IX+d),A */ + regA = rlc(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regA); + break; + } + case 0x08: { /* RRC (IX+d),B */ + regB = rrc(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regB); + break; + } + case 0x09: { /* RRC (IX+d),C */ + regC = rrc(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regC); + break; + } + case 0x0A: { /* RRC (IX+d),D */ + regD = rrc(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regD); + break; + } + case 0x0B: { /* RRC (IX+d),E */ + regE = rrc(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regE); + break; + } + case 0x0C: { /* RRC (IX+d),H */ + regH = rrc(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regH); + break; + } + case 0x0D: { /* RRC (IX+d),L */ + regL = rrc(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regL); + break; + } + case 0x0E: { /* RRC (IX+d) */ + int work8 = rrc(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, work8); + break; + } + case 0x0F: { /* RRC (IX+d),A */ + regA = rrc(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regA); + break; + } + case 0x10: { /* RL (IX+d),B */ + regB = rl(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regB); + break; + } + case 0x11: { /* RL (IX+d),C */ + regC = rl(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regC); + break; + } + case 0x12: { /* RL (IX+d),D */ + regD = rl(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regD); + break; + } + case 0x13: { /* RL (IX+d),E */ + regE = rl(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regE); + break; + } + case 0x14: { /* RL (IX+d),H */ + regH = rl(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regH); + break; + } + case 0x15: { /* RL (IX+d),L */ + regL = rl(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regL); + break; + } + case 0x16: { /* RL (IX+d) */ + int work8 = rl(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, work8); + break; + } + case 0x17: { /* RL (IX+d),A */ + regA = rl(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regA); + break; + } + case 0x18: { /* RR (IX+d),B */ + regB = rr(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regB); + break; + } + case 0x19: { /* RR (IX+d),C */ + regC = rr(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regC); + break; + } + case 0x1A: { /* RR (IX+d),D */ + regD = rr(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regD); + break; + } + case 0x1B: { /* RR (IX+d),E */ + regE = rr(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regE); + break; + } + case 0x1C: { /* RR (IX+d),H */ + regH = rr(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regH); + break; + } + case 0x1D: { /* RR (IX+d),L */ + regL = rr(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regL); + break; + } + case 0x1E: { /* RR (IX+d) */ + int work8 = rr(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, work8); + break; + } + case 0x1F: { /* RR (IX+d),A */ + regA = rr(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regA); + break; + } + case 0x20: { /* SLA (IX+d),B */ + regB = sla(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regB); + break; + } + case 0x21: { /* SLA (IX+d),C */ + regC = sla(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regC); + break; + } + case 0x22: { /* SLA (IX+d),D */ + regD = sla(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regD); + break; + } + case 0x23: { /* SLA (IX+d),E */ + regE = sla(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regE); + break; + } + case 0x24: { /* SLA (IX+d),H */ + regH = sla(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regH); + break; + } + case 0x25: { /* SLA (IX+d),L */ + regL = sla(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regL); + break; + } + case 0x26: { /* SLA (IX+d) */ + int work8 = sla(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, work8); + break; + } + case 0x27: { /* SLA (IX+d),A */ + regA = sla(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regA); + break; + } + case 0x28: { /* SRA (IX+d),B */ + regB = sra(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regB); + break; + } + case 0x29: { /* SRA (IX+d),C */ + regC = sra(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regC); + break; + } + case 0x2A: { /* SRA (IX+d),D */ + regD = sra(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regD); + break; + } + case 0x2B: { /* SRA (IX+d),E */ + regE = sra(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regE); + break; + } + case 0x2C: { /* SRA (IX+d),H */ + regH = sra(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regH); + break; + } + case 0x2D: { /* SRA (IX+d),L */ + regL = sra(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regL); + break; + } + case 0x2E: { /* SRA (IX+d) */ + int work8 = sra(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, work8); + break; + } + case 0x2F: { /* SRA (IX+d),A */ + regA = sra(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regA); + break; + } + case 0x30: { /* SLL (IX+d),B */ + regB = sll(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regB); + break; + } + case 0x31: { /* SLL (IX+d),C */ + regC = sll(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regC); + break; + } + case 0x32: { /* SLL (IX+d),D */ + regD = sll(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regD); + break; + } + case 0x33: { /* SLL (IX+d),E */ + regE = sll(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regE); + break; + } + case 0x34: { /* SLL (IX+d),H */ + regH = sll(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regH); + break; + } + case 0x35: { /* SLL (IX+d),L */ + regL = sll(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regL); + break; + } + case 0x36: { /* SLL (IX+d) */ + int work8 = sll(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, work8); + break; + } + case 0x37: { /* SLL (IX+d),A */ + regA = sll(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regA); + break; + } + case 0x38: { /* SRL (IX+d),B */ + regB = srl(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regB); + break; + } + case 0x39: { /* SRL (IX+d),C */ + regC = srl(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regC); + break; + } + case 0x3A: { /* SRL (IX+d),D */ + regD = srl(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regD); + break; + } + case 0x3B: { /* SRL (IX+d),E */ + regE = srl(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regE); + break; + } + case 0x3C: { /* SRL (IX+d),H */ + regH = srl(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regH); + break; + } + case 0x3D: { /* SRL (IX+d),L */ + regL = srl(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regL); + break; + } + case 0x3E: { /* SRL (IX+d) */ + int work8 = srl(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, work8); + break; + } + case 0x3F: { /* SRL (IX+d),A */ + regA = srl(MemIoImpl.peek8(address)); + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regA); + break; + } + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: { /* BIT 0,(IX+d) */ + bit(0x01, MemIoImpl.peek8(address)); + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) + | ((address >>> 8) & FLAG_53_MASK); + MemIoImpl.addressOnBus(address, 1); + break; + } + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: { /* BIT 1,(IX+d) */ + bit(0x02, MemIoImpl.peek8(address)); + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) + | ((address >>> 8) & FLAG_53_MASK); + MemIoImpl.addressOnBus(address, 1); + break; + } + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: { /* BIT 2,(IX+d) */ + bit(0x04, MemIoImpl.peek8(address)); + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) + | ((address >>> 8) & FLAG_53_MASK); + MemIoImpl.addressOnBus(address, 1); + break; + } + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: { /* BIT 3,(IX+d) */ + bit(0x08, MemIoImpl.peek8(address)); + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) + | ((address >>> 8) & FLAG_53_MASK); + MemIoImpl.addressOnBus(address, 1); + break; + } + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: { /* BIT 4,(IX+d) */ + bit(0x10, MemIoImpl.peek8(address)); + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) + | ((address >>> 8) & FLAG_53_MASK); + MemIoImpl.addressOnBus(address, 1); + break; + } + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: { /* BIT 5,(IX+d) */ + bit(0x20, MemIoImpl.peek8(address)); + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) + | ((address >>> 8) & FLAG_53_MASK); + MemIoImpl.addressOnBus(address, 1); + break; + } + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: { /* BIT 6,(IX+d) */ + bit(0x40, MemIoImpl.peek8(address)); + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) + | ((address >>> 8) & FLAG_53_MASK); + MemIoImpl.addressOnBus(address, 1); + break; + } + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: { /* BIT 7,(IX+d) */ + bit(0x80, MemIoImpl.peek8(address)); + sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) + | ((address >>> 8) & FLAG_53_MASK); + MemIoImpl.addressOnBus(address, 1); + break; + } + } + } + + // Subconjunto de instrucciones 0xDDCB desde el código 0x80 hasta el 0xFF + private void decodeDDFDCBtoFF(int opCode, int address) { + + switch (opCode) { + case 0x80: { /* RES 0,(IX+d),B */ + regB = MemIoImpl.peek8(address) & 0xFE; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regB); + break; + } + case 0x81: { /* RES 0,(IX+d),C */ + regC = MemIoImpl.peek8(address) & 0xFE; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regC); + break; + } + case 0x82: { /* RES 0,(IX+d),D */ + regD = MemIoImpl.peek8(address) & 0xFE; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regD); + break; + } + case 0x83: { /* RES 0,(IX+d),E */ + regE = MemIoImpl.peek8(address) & 0xFE; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regE); + break; + } + case 0x84: { /* RES 0,(IX+d),H */ + regH = MemIoImpl.peek8(address) & 0xFE; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regH); + break; + } + case 0x85: { /* RES 0,(IX+d),L */ + regL = MemIoImpl.peek8(address) & 0xFE; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regL); + break; + } + case 0x86: { /* RES 0,(IX+d) */ + int work8 = MemIoImpl.peek8(address) & 0xFE; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, work8); + break; + } + case 0x87: { /* RES 0,(IX+d),A */ + regA = MemIoImpl.peek8(address) & 0xFE; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regA); + break; + } + case 0x88: { /* RES 1,(IX+d),B */ + regB = MemIoImpl.peek8(address) & 0xFD; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regB); + break; + } + case 0x89: { /* RES 1,(IX+d),C */ + regC = MemIoImpl.peek8(address) & 0xFD; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regC); + break; + } + case 0x8A: { /* RES 1,(IX+d),D */ + regD = MemIoImpl.peek8(address) & 0xFD; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regD); + break; + } + case 0x8B: { /* RES 1,(IX+d),E */ + regE = MemIoImpl.peek8(address) & 0xFD; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regE); + break; + } + case 0x8C: { /* RES 1,(IX+d),H */ + regH = MemIoImpl.peek8(address) & 0xFD; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regH); + break; + } + case 0x8D: { /* RES 1,(IX+d),L */ + regL = MemIoImpl.peek8(address) & 0xFD; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regL); + break; + } + case 0x8E: { /* RES 1,(IX+d) */ + int work8 = MemIoImpl.peek8(address) & 0xFD; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, work8); + break; + } + case 0x8F: { /* RES 1,(IX+d),A */ + regA = MemIoImpl.peek8(address) & 0xFD; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regA); + break; + } + case 0x90: { /* RES 2,(IX+d),B */ + regB = MemIoImpl.peek8(address) & 0xFB; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regB); + break; + } + case 0x91: { /* RES 2,(IX+d),C */ + regC = MemIoImpl.peek8(address) & 0xFB; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regC); + break; + } + case 0x92: { /* RES 2,(IX+d),D */ + regD = MemIoImpl.peek8(address) & 0xFB; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regD); + break; + } + case 0x93: { /* RES 2,(IX+d),E */ + regE = MemIoImpl.peek8(address) & 0xFB; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regE); + break; + } + case 0x94: { /* RES 2,(IX+d),H */ + regH = MemIoImpl.peek8(address) & 0xFB; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regH); + break; + } + case 0x95: { /* RES 2,(IX+d),L */ + regL = MemIoImpl.peek8(address) & 0xFB; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regL); + break; + } + case 0x96: { /* RES 2,(IX+d) */ + int work8 = MemIoImpl.peek8(address) & 0xFB; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, work8); + break; + } + case 0x97: { /* RES 2,(IX+d),A */ + regA = MemIoImpl.peek8(address) & 0xFB; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regA); + break; + } + case 0x98: { /* RES 3,(IX+d),B */ + regB = MemIoImpl.peek8(address) & 0xF7; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regB); + break; + } + case 0x99: { /* RES 3,(IX+d),C */ + regC = MemIoImpl.peek8(address) & 0xF7; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regC); + break; + } + case 0x9A: { /* RES 3,(IX+d),D */ + regD = MemIoImpl.peek8(address) & 0xF7; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regD); + break; + } + case 0x9B: { /* RES 3,(IX+d),E */ + regE = MemIoImpl.peek8(address) & 0xF7; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regE); + break; + } + case 0x9C: { /* RES 3,(IX+d),H */ + regH = MemIoImpl.peek8(address) & 0xF7; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regH); + break; + } + case 0x9D: { /* RES 3,(IX+d),L */ + regL = MemIoImpl.peek8(address) & 0xF7; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regL); + break; + } + case 0x9E: { /* RES 3,(IX+d) */ + int work8 = MemIoImpl.peek8(address) & 0xF7; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, work8); + break; + } + case 0x9F: { /* RES 3,(IX+d),A */ + regA = MemIoImpl.peek8(address) & 0xF7; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regA); + break; + } + case 0xA0: { /* RES 4,(IX+d),B */ + regB = MemIoImpl.peek8(address) & 0xEF; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regB); + break; + } + case 0xA1: { /* RES 4,(IX+d),C */ + regC = MemIoImpl.peek8(address) & 0xEF; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regC); + break; + } + case 0xA2: { /* RES 4,(IX+d),D */ + regD = MemIoImpl.peek8(address) & 0xEF; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regD); + break; + } + case 0xA3: { /* RES 4,(IX+d),E */ + regE = MemIoImpl.peek8(address) & 0xEF; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regE); + break; + } + case 0xA4: { /* RES 4,(IX+d),H */ + regH = MemIoImpl.peek8(address) & 0xEF; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regH); + break; + } + case 0xA5: { /* RES 4,(IX+d),L */ + regL = MemIoImpl.peek8(address) & 0xEF; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regL); + break; + } + case 0xA6: { /* RES 4,(IX+d) */ + int work8 = MemIoImpl.peek8(address) & 0xEF; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, work8); + break; + } + case 0xA7: { /* RES 4,(IX+d),A */ + regA = MemIoImpl.peek8(address) & 0xEF; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regA); + break; + } + case 0xA8: { /* RES 5,(IX+d),B */ + regB = MemIoImpl.peek8(address) & 0xDF; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regB); + break; + } + case 0xA9: { /* RES 5,(IX+d),C */ + regC = MemIoImpl.peek8(address) & 0xDF; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regC); + break; + } + case 0xAA: { /* RES 5,(IX+d),D */ + regD = MemIoImpl.peek8(address) & 0xDF; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regD); + break; + } + case 0xAB: { /* RES 5,(IX+d),E */ + regE = MemIoImpl.peek8(address) & 0xDF; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regE); + break; + } + case 0xAC: { /* RES 5,(IX+d),H */ + regH = MemIoImpl.peek8(address) & 0xDF; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regH); + break; + } + case 0xAD: { /* RES 5,(IX+d),L */ + regL = MemIoImpl.peek8(address) & 0xDF; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regL); + break; + } + case 0xAE: { /* RES 5,(IX+d) */ + int work8 = MemIoImpl.peek8(address) & 0xDF; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, work8); + break; + } + case 0xAF: { /* RES 5,(IX+d),A */ + regA = MemIoImpl.peek8(address) & 0xDF; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regA); + break; + } + case 0xB0: { /* RES 6,(IX+d),B */ + regB = MemIoImpl.peek8(address) & 0xBF; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regB); + break; + } + case 0xB1: { /* RES 6,(IX+d),C */ + regC = MemIoImpl.peek8(address) & 0xBF; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regC); + break; + } + case 0xB2: { /* RES 6,(IX+d),D */ + regD = MemIoImpl.peek8(address) & 0xBF; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regD); + break; + } + case 0xB3: { /* RES 6,(IX+d),E */ + regE = MemIoImpl.peek8(address) & 0xBF; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regE); + break; + } + case 0xB4: { /* RES 6,(IX+d),H */ + regH = MemIoImpl.peek8(address) & 0xBF; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regH); + break; + } + case 0xB5: { /* RES 6,(IX+d),L */ + regL = MemIoImpl.peek8(address) & 0xBF; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regL); + break; + } + case 0xB6: { /* RES 6,(IX+d) */ + int work8 = MemIoImpl.peek8(address) & 0xBF; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, work8); + break; + } + case 0xB7: { /* RES 6,(IX+d),A */ + regA = MemIoImpl.peek8(address) & 0xBF; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regA); + break; + } + case 0xB8: { /* RES 7,(IX+d),B */ + regB = MemIoImpl.peek8(address) & 0x7F; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regB); + break; + } + case 0xB9: { /* RES 7,(IX+d),C */ + regC = MemIoImpl.peek8(address) & 0x7F; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regC); + break; + } + case 0xBA: { /* RES 7,(IX+d),D */ + regD = MemIoImpl.peek8(address) & 0x7F; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regD); + break; + } + case 0xBB: { /* RES 7,(IX+d),E */ + regE = MemIoImpl.peek8(address) & 0x7F; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regE); + break; + } + case 0xBC: { /* RES 7,(IX+d),H */ + regH = MemIoImpl.peek8(address) & 0x7F; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regH); + break; + } + case 0xBD: { /* RES 7,(IX+d),L */ + regL = MemIoImpl.peek8(address) & 0x7F; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regL); + break; + } + case 0xBE: { /* RES 7,(IX+d) */ + int work8 = MemIoImpl.peek8(address) & 0x7F; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, work8); + break; + } + case 0xBF: { /* RES 7,(IX+d),A */ + regA = MemIoImpl.peek8(address) & 0x7F; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regA); + break; + } + case 0xC0: { /* SET 0,(IX+d),B */ + regB = MemIoImpl.peek8(address) | 0x01; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regB); + break; + } + case 0xC1: { /* SET 0,(IX+d),C */ + regC = MemIoImpl.peek8(address) | 0x01; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regC); + break; + } + case 0xC2: { /* SET 0,(IX+d),D */ + regD = MemIoImpl.peek8(address) | 0x01; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regD); + break; + } + case 0xC3: { /* SET 0,(IX+d),E */ + regE = MemIoImpl.peek8(address) | 0x01; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regE); + break; + } + case 0xC4: { /* SET 0,(IX+d),H */ + regH = MemIoImpl.peek8(address) | 0x01; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regH); + break; + } + case 0xC5: { /* SET 0,(IX+d),L */ + regL = MemIoImpl.peek8(address) | 0x01; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regL); + break; + } + case 0xC6: { /* SET 0,(IX+d) */ + int work8 = MemIoImpl.peek8(address) | 0x01; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, work8); + break; + } + case 0xC7: { /* SET 0,(IX+d),A */ + regA = MemIoImpl.peek8(address) | 0x01; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regA); + break; + } + case 0xC8: { /* SET 1,(IX+d),B */ + regB = MemIoImpl.peek8(address) | 0x02; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regB); + break; + } + case 0xC9: { /* SET 1,(IX+d),C */ + regC = MemIoImpl.peek8(address) | 0x02; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regC); + break; + } + case 0xCA: { /* SET 1,(IX+d),D */ + regD = MemIoImpl.peek8(address) | 0x02; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regD); + break; + } + case 0xCB: { /* SET 1,(IX+d),E */ + regE = MemIoImpl.peek8(address) | 0x02; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regE); + break; + } + case 0xCC: { /* SET 1,(IX+d),H */ + regH = MemIoImpl.peek8(address) | 0x02; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regH); + break; + } + case 0xCD: { /* SET 1,(IX+d),L */ + regL = MemIoImpl.peek8(address) | 0x02; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regL); + break; + } + case 0xCE: { /* SET 1,(IX+d) */ + int work8 = MemIoImpl.peek8(address) | 0x02; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, work8); + break; + } + case 0xCF: { /* SET 1,(IX+d),A */ + regA = MemIoImpl.peek8(address) | 0x02; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regA); + break; + } + case 0xD0: { /* SET 2,(IX+d),B */ + regB = MemIoImpl.peek8(address) | 0x04; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regB); + break; + } + case 0xD1: { /* SET 2,(IX+d),C */ + regC = MemIoImpl.peek8(address) | 0x04; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regC); + break; + } + case 0xD2: { /* SET 2,(IX+d),D */ + regD = MemIoImpl.peek8(address) | 0x04; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regD); + break; + } + case 0xD3: { /* SET 2,(IX+d),E */ + regE = MemIoImpl.peek8(address) | 0x04; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regE); + break; + } + case 0xD4: { /* SET 2,(IX+d),H */ + regH = MemIoImpl.peek8(address) | 0x04; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regH); + break; + } + case 0xD5: { /* SET 2,(IX+d),L */ + regL = MemIoImpl.peek8(address) | 0x04; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regL); + break; + } + case 0xD6: { /* SET 2,(IX+d) */ + int work8 = MemIoImpl.peek8(address) | 0x04; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, work8); + break; + } + case 0xD7: { /* SET 2,(IX+d),A */ + regA = MemIoImpl.peek8(address) | 0x04; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regA); + break; + } + case 0xD8: { /* SET 3,(IX+d),B */ + regB = MemIoImpl.peek8(address) | 0x08; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regB); + break; + } + case 0xD9: { /* SET 3,(IX+d),C */ + regC = MemIoImpl.peek8(address) | 0x08; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regC); + break; + } + case 0xDA: { /* SET 3,(IX+d),D */ + regD = MemIoImpl.peek8(address) | 0x08; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regD); + break; + } + case 0xDB: { /* SET 3,(IX+d),E */ + regE = MemIoImpl.peek8(address) | 0x08; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regE); + break; + } + case 0xDC: { /* SET 3,(IX+d),H */ + regH = MemIoImpl.peek8(address) | 0x08; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regH); + break; + } + case 0xDD: { /* SET 3,(IX+d),L */ + regL = MemIoImpl.peek8(address) | 0x08; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regL); + break; + } + case 0xDE: { /* SET 3,(IX+d) */ + int work8 = MemIoImpl.peek8(address) | 0x08; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, work8); + break; + } + case 0xDF: { /* SET 3,(IX+d),A */ + regA = MemIoImpl.peek8(address) | 0x08; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regA); + break; + } + case 0xE0: { /* SET 4,(IX+d),B */ + regB = MemIoImpl.peek8(address) | 0x10; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regB); + break; + } + case 0xE1: { /* SET 4,(IX+d),C */ + regC = MemIoImpl.peek8(address) | 0x10; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regC); + break; + } + case 0xE2: { /* SET 4,(IX+d),D */ + regD = MemIoImpl.peek8(address) | 0x10; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regD); + break; + } + case 0xE3: { /* SET 4,(IX+d),E */ + regE = MemIoImpl.peek8(address) | 0x10; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regE); + break; + } + case 0xE4: { /* SET 4,(IX+d),H */ + regH = MemIoImpl.peek8(address) | 0x10; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regH); + break; + } + case 0xE5: { /* SET 4,(IX+d),L */ + regL = MemIoImpl.peek8(address) | 0x10; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regL); + break; + } + case 0xE6: { /* SET 4,(IX+d) */ + int work8 = MemIoImpl.peek8(address) | 0x10; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, work8); + break; + } + case 0xE7: { /* SET 4,(IX+d),A */ + regA = MemIoImpl.peek8(address) | 0x10; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regA); + break; + } + case 0xE8: { /* SET 5,(IX+d),B */ + regB = MemIoImpl.peek8(address) | 0x20; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regB); + break; + } + case 0xE9: { /* SET 5,(IX+d),C */ + regC = MemIoImpl.peek8(address) | 0x20; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regC); + break; + } + case 0xEA: { /* SET 5,(IX+d),D */ + regD = MemIoImpl.peek8(address) | 0x20; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regD); + break; + } + case 0xEB: { /* SET 5,(IX+d),E */ + regE = MemIoImpl.peek8(address) | 0x20; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regE); + break; + } + case 0xEC: { /* SET 5,(IX+d),H */ + regH = MemIoImpl.peek8(address) | 0x20; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regH); + break; + } + case 0xED: { /* SET 5,(IX+d),L */ + regL = MemIoImpl.peek8(address) | 0x20; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regL); + break; + } + case 0xEE: { /* SET 5,(IX+d) */ + int work8 = MemIoImpl.peek8(address) | 0x20; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, work8); + break; + } + case 0xEF: { /* SET 5,(IX+d),A */ + regA = MemIoImpl.peek8(address) | 0x20; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regA); + break; + } + case 0xF0: { /* SET 6,(IX+d),B */ + regB = MemIoImpl.peek8(address) | 0x40; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regB); + break; + } + case 0xF1: { /* SET 6,(IX+d),C */ + regC = MemIoImpl.peek8(address) | 0x40; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regC); + break; + } + case 0xF2: { /* SET 6,(IX+d),D */ + regD = MemIoImpl.peek8(address) | 0x40; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regD); + break; + } + case 0xF3: { /* SET 6,(IX+d),E */ + regE = MemIoImpl.peek8(address) | 0x40; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regE); + break; + } + case 0xF4: { /* SET 6,(IX+d),H */ + regH = MemIoImpl.peek8(address) | 0x40; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regH); + break; + } + case 0xF5: { /* SET 6,(IX+d),L */ + regL = MemIoImpl.peek8(address) | 0x40; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regL); + break; + } + case 0xF6: { /* SET 6,(IX+d) */ + int work8 = MemIoImpl.peek8(address) | 0x40; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, work8); + break; + } + case 0xF7: { /* SET 6,(IX+d),A */ + regA = MemIoImpl.peek8(address) | 0x40; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regA); + break; + } + case 0xF8: { /* SET 7,(IX+d),B */ + regB = MemIoImpl.peek8(address) | 0x80; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regB); + break; + } + case 0xF9: { /* SET 7,(IX+d),C */ + regC = MemIoImpl.peek8(address) | 0x80; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regC); + break; + } + case 0xFA: { /* SET 7,(IX+d),D */ + regD = MemIoImpl.peek8(address) | 0x80; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regD); + break; + } + case 0xFB: { /* SET 7,(IX+d),E */ + regE = MemIoImpl.peek8(address) | 0x80; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regE); + break; + } + case 0xFC: { /* SET 7,(IX+d),H */ + regH = MemIoImpl.peek8(address) | 0x80; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regH); + break; + } + case 0xFD: { /* SET 7,(IX+d),L */ + regL = MemIoImpl.peek8(address) | 0x80; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regL); + break; + } + case 0xFE: { /* SET 7,(IX+d) */ + int work8 = MemIoImpl.peek8(address) | 0x80; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, work8); + break; + } + case 0xFF: { /* SET 7,(IX+d),A */ + regA = MemIoImpl.peek8(address) | 0x80; + MemIoImpl.addressOnBus(address, 1); + MemIoImpl.poke8(address, regA); + break; + } + } + } + + //Subconjunto de instrucciones 0xED + private void decodeED(int opCode) { + prefixOpcode = 0; + switch (opCode) { + case 0x40: { /* IN B,(C) */ + memptr = getRegBC(); + regB = MemIoImpl.inPort(memptr++); + sz5h3pnFlags = sz53pn_addTable[regB]; + flagQ = true; + break; + } + case 0x41: { /* OUT (C),B */ + memptr = getRegBC(); + MemIoImpl.outPort(memptr++, regB); + break; + } + case 0x42: { /* SBC HL,BC */ + MemIoImpl.addressOnBus(getPairIR(), 7); + sbc16(getRegBC()); + break; + } + case 0x43: { /* LD (nn),BC */ + memptr = MemIoImpl.peek16(regPC); + MemIoImpl.poke16(memptr++, getRegBC()); + regPC = (regPC + 2) & 0xffff; + break; + } + case 0x44: + case 0x4C: + case 0x54: + case 0x5C: + case 0x64: + case 0x6C: + case 0x74: + case 0x7C: { /* NEG */ + int aux = regA; + regA = 0; + sub(aux); + break; + } + case 0x45: + case 0x4D: /* RETI */ + case 0x55: + case 0x5D: + case 0x65: + case 0x6D: + case 0x75: + case 0x7D: { /* RETN */ + ffIFF1 = ffIFF2; + regPC = memptr = pop(); + break; + } + case 0x46: + case 0x4E: + case 0x66: + case 0x6E: { /* IM 0 */ + setIM(IntMode.IM0); + break; + } + case 0x47: { /* LD I,A */ + /* + * El contended-tstate se produce con el contenido de I *antes* + * de ser copiado el del registro A. Detalle importante. + */ + MemIoImpl.addressOnBus(getPairIR(), 1); + regI = regA; + break; + } + case 0x48: { /* IN C,(C) */ + memptr = getRegBC(); + regC = MemIoImpl.inPort(memptr++); + sz5h3pnFlags = sz53pn_addTable[regC]; + flagQ = true; + break; + } + case 0x49: { /* OUT (C),C */ + memptr = getRegBC(); + MemIoImpl.outPort(memptr++, regC); + break; + } + case 0x4A: { /* ADC HL,BC */ + MemIoImpl.addressOnBus(getPairIR(), 7); + adc16(getRegBC()); + break; + } + case 0x4B: { /* LD BC,(nn) */ + memptr = MemIoImpl.peek16(regPC); + setRegBC(MemIoImpl.peek16(memptr++)); + regPC = (regPC + 2) & 0xffff; + break; + } + case 0x4F: { /* LD R,A */ + MemIoImpl.addressOnBus(getPairIR(), 1); + setRegR(regA); + break; + } + case 0x50: { /* IN D,(C) */ + memptr = getRegBC(); + regD = MemIoImpl.inPort(memptr++); + sz5h3pnFlags = sz53pn_addTable[regD]; + flagQ = true; + break; + } + case 0x51: { /* OUT (C),D */ + memptr = getRegBC(); + MemIoImpl.outPort(memptr++, regD); + break; + } + case 0x52: { /* SBC HL,DE */ + MemIoImpl.addressOnBus(getPairIR(), 7); + sbc16(getRegDE()); + break; + } + case 0x53: { /* LD (nn),DE */ + memptr = MemIoImpl.peek16(regPC); + MemIoImpl.poke16(memptr++, getRegDE()); + regPC = (regPC + 2) & 0xffff; + break; + } + case 0x56: + case 0x76: { /* IM 1 */ + setIM(IntMode.IM1); + break; + } + case 0x57: { /* LD A,I */ + MemIoImpl.addressOnBus(getPairIR(), 1); + regA = regI; + sz5h3pnFlags = sz53n_addTable[regA]; + if (ffIFF2 && !MemIoImpl.isActiveINT()) { + sz5h3pnFlags |= PARITY_MASK; + } + flagQ = true; + break; + } + case 0x58: { /* IN E,(C) */ + memptr = getRegBC(); + regE = MemIoImpl.inPort(memptr++); + sz5h3pnFlags = sz53pn_addTable[regE]; + flagQ = true; + break; + } + case 0x59: { /* OUT (C),E */ + memptr = getRegBC(); + MemIoImpl.outPort(memptr++, regE); + break; + } + case 0x5A: { /* ADC HL,DE */ + MemIoImpl.addressOnBus(getPairIR(), 7); + adc16(getRegDE()); + break; + } + case 0x5B: { /* LD DE,(nn) */ + memptr = MemIoImpl.peek16(regPC); + setRegDE(MemIoImpl.peek16(memptr++)); + regPC = (regPC + 2) & 0xffff; + break; + } + case 0x5E: + case 0x7E: { /* IM 2 */ + setIM(IntMode.IM2); + break; + } + case 0x5F: { /* LD A,R */ + MemIoImpl.addressOnBus(getPairIR(), 1); + regA = getRegR(); + sz5h3pnFlags = sz53n_addTable[regA]; + if (ffIFF2 && !MemIoImpl.isActiveINT()) { + sz5h3pnFlags |= PARITY_MASK; + } + flagQ = true; + break; + } + case 0x60: { /* IN H,(C) */ + memptr = getRegBC(); + regH = MemIoImpl.inPort(memptr++); + sz5h3pnFlags = sz53pn_addTable[regH]; + flagQ = true; + break; + } + case 0x61: { /* OUT (C),H */ + memptr = getRegBC(); + MemIoImpl.outPort(memptr++, regH); + break; + } + case 0x62: { /* SBC HL,HL */ + MemIoImpl.addressOnBus(getPairIR(), 7); + sbc16(getRegHL()); + break; + } + case 0x63: { /* LD (nn),HL */ + memptr = MemIoImpl.peek16(regPC); + MemIoImpl.poke16(memptr++, getRegHL()); + regPC = (regPC + 2) & 0xffff; + break; + } + case 0x67: { /* RRD */ + rrd(); + break; + } + case 0x68: { /* IN L,(C) */ + memptr = getRegBC(); + regL = MemIoImpl.inPort(memptr++); + sz5h3pnFlags = sz53pn_addTable[regL]; + flagQ = true; + break; + } + case 0x69: { /* OUT (C),L */ + memptr = getRegBC(); + MemIoImpl.outPort(memptr++, regL); + break; + } + case 0x6A: { /* ADC HL,HL */ + MemIoImpl.addressOnBus(getPairIR(), 7); + adc16(getRegHL()); + break; + } + case 0x6B: { /* LD HL,(nn) */ + memptr = MemIoImpl.peek16(regPC); + setRegHL(MemIoImpl.peek16(memptr++)); + regPC = (regPC + 2) & 0xffff; + break; + } + case 0x6F: { /* RLD */ + rld(); + break; + } + case 0x70: { /* IN (C) */ + memptr = getRegBC(); + int inPort = MemIoImpl.inPort(memptr++); + sz5h3pnFlags = sz53pn_addTable[inPort]; + flagQ = true; + break; + } + case 0x71: { /* OUT (C),0 */ + memptr = getRegBC(); + MemIoImpl.outPort(memptr++, 0x00); + break; + } + case 0x72: { /* SBC HL,SP */ + MemIoImpl.addressOnBus(getPairIR(), 7); + sbc16(regSP); + break; + } + case 0x73: { /* LD (nn),SP */ + memptr = MemIoImpl.peek16(regPC); + MemIoImpl.poke16(memptr++, regSP); + regPC = (regPC + 2) & 0xffff; + break; + } + case 0x78: { /* IN A,(C) */ + memptr = getRegBC(); + regA = MemIoImpl.inPort(memptr++); + sz5h3pnFlags = sz53pn_addTable[regA]; + flagQ = true; + break; + } + case 0x79: { /* OUT (C),A */ + memptr = getRegBC(); + MemIoImpl.outPort(memptr++, regA); + break; + } + case 0x7A: { /* ADC HL,SP */ + MemIoImpl.addressOnBus(getPairIR(), 7); + adc16(regSP); + break; + } + case 0x7B: { /* LD SP,(nn) */ + memptr = MemIoImpl.peek16(regPC); + regSP = MemIoImpl.peek16(memptr++); + regPC = (regPC + 2) & 0xffff; + break; + } + case 0xA0: { /* LDI */ + ldi(); + break; + } + case 0xA1: { /* CPI */ + cpi(); + break; + } + case 0xA2: { /* INI */ + ini(); + break; + } + case 0xA3: { /* OUTI */ + outi(); + break; + } + case 0xA8: { /* LDD */ + ldd(); + break; + } + case 0xA9: { /* CPD */ + cpd(); + break; + } + case 0xAA: { /* IND */ + ind(); + break; + } + case 0xAB: { /* OUTD */ + outd(); + break; + } + case 0xB0: { /* LDIR */ + ldi(); + if ((sz5h3pnFlags & PARITY_MASK) == PARITY_MASK) { + regPC = (regPC - 2) & 0xffff; + memptr = regPC + 1; + MemIoImpl.addressOnBus((getRegDE() - 1) & 0xffff, 5); + } + break; + } + case 0xB1: { /* CPIR */ + cpi(); + if ((sz5h3pnFlags & PARITY_MASK) == PARITY_MASK + && (sz5h3pnFlags & ZERO_MASK) == 0) { + regPC = (regPC - 2) & 0xffff; + memptr = regPC + 1; + MemIoImpl.addressOnBus((getRegHL() - 1) & 0xffff, 5); + } + break; + } + case 0xB2: { /* INIR */ + ini(); + if (regB != 0) { + regPC = (regPC - 2) & 0xffff; + MemIoImpl.addressOnBus((getRegHL() - 1) & 0xffff, 5); + } + break; + } + case 0xB3: { /* OTIR */ + outi(); + if (regB != 0) { + regPC = (regPC - 2) & 0xffff; + MemIoImpl.addressOnBus(getRegBC(), 5); + } + break; + } + case 0xB8: { /* LDDR */ + ldd(); + if ((sz5h3pnFlags & PARITY_MASK) == PARITY_MASK) { + regPC = (regPC - 2) & 0xffff; + memptr = regPC + 1; + MemIoImpl.addressOnBus((getRegDE() + 1) & 0xffff, 5); + } + break; + } + case 0xB9: { /* CPDR */ + cpd(); + if ((sz5h3pnFlags & PARITY_MASK) == PARITY_MASK + && (sz5h3pnFlags & ZERO_MASK) == 0) { + regPC = (regPC - 2) & 0xffff; + memptr = regPC + 1; + MemIoImpl.addressOnBus((getRegHL() + 1) & 0xffff, 5); + } + break; + } + case 0xBA: { /* INDR */ + ind(); + if (regB != 0) { + regPC = (regPC - 2) & 0xffff; + MemIoImpl.addressOnBus((getRegHL() + 1) & 0xffff, 5); + } + break; + } + case 0xBB: { /* OTDR */ + outd(); + if (regB != 0) { + regPC = (regPC - 2) & 0xffff; + MemIoImpl.addressOnBus(getRegBC(), 5); + } + break; + } + case 0xDD: + prefixOpcode = 0xDD; + break; + case 0xED: + prefixOpcode = 0xED; + break; + case 0xFD: + prefixOpcode = 0xFD; + break; + default: { +// System.out.println("Error instrucción ED " + Integer.toHexString(opCode)); + break; + } + } + } +} \ No newline at end of file diff --git a/src/z80core/Z80State.java b/src/z80core/Z80State.java new file mode 100644 index 0000000..464e63c --- /dev/null +++ b/src/z80core/Z80State.java @@ -0,0 +1,418 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package z80core; + +import z80core.Z80.IntMode; + +/** + * + * @author jsanchez + */ +public class Z80State { + // Acumulador y resto de registros de 8 bits + private int regA, regB, regC, regD, regE, regH, regL; + // Flags sIGN, zERO, 5, hALFCARRY, 3, pARITY y ADDSUB (n), carryFlag + private int regF; + // La última instrucción modificó los flags + private boolean flagQ; + // Acumulador alternativo y flags -- 8 bits + private int regAx; + private int regFx; + // Registros alternativos + private int regBx, regCx, regDx, regEx, regHx, regLx; + // Registros de propósito específico + // *PC -- Program Counter -- 16 bits* + private int regPC; + // *IX -- Registro de índice -- 16 bits* + private int regIX; + // *IY -- Registro de índice -- 16 bits* + private int regIY; + // *SP -- Stack Pointer -- 16 bits* + private int regSP; + // *I -- Vector de interrupción -- 8 bits* + private int regI; + // *R -- Refresco de memoria -- 7 bits* + private int regR; + //Flip-flops de interrupción + private boolean ffIFF1 = false; + private boolean ffIFF2 = false; + // EI solo habilita las interrupciones DESPUES de ejecutar la + // siguiente instrucción (excepto si la siguiente instrucción es un EI...) + private boolean pendingEI = false; + // Estado de la línea NMI + private boolean activeNMI = false; + // Si está activa la línea INT + // En el 48 la línea INT se activa durante 32 ciclos de reloj + // En el 128 y superiores, se activa 36 ciclos de reloj + private boolean activeINT = false; + // Modos de interrupción + private IntMode modeINT = IntMode.IM0; + // halted == true cuando la CPU está ejecutando un HALT (28/03/2010) + private boolean halted = false; + /** + * Registro interno que usa la CPU de la siguiente forma + * + * ADD HL,xx = Valor del registro H antes de la suma + * LD r,(IX/IY+d) = Byte superior de la suma de IX/IY+d + * JR d = Byte superior de la dirección de destino del salto + * + * 04/12/2008 No se vayan todavía, aún hay más. Con lo que se ha + * implementado hasta ahora parece que funciona. El resto de + * la historia está contada en: + * http://zx.pk.ru/attachment.php?attachmentid=2989 + * + * 25/09/2009 Se ha completado la emulación de MEMPTR. A señalar que + * no se puede comprobar si MEMPTR se ha emulado bien hasta + * que no se emula el comportamiento del registro en las + * instrucciones CPI y CPD. Sin ello, todos los tests de + * z80tests.tap fallarán aunque se haya emulado bien al + * registro en TODAS las otras instrucciones. + * Shit yourself, little parrot. + */ + private int memptr; + + public Z80State() { + } + + // Acceso a registros de 8 bits + public final int getRegA() { + return regA; + } + + public final void setRegA(int value) { + regA = value & 0xff; + } + + public final int getRegF() { + return regF; + } + + public final void setRegF(int value) { + regF = value & 0xff; + } + + public final int getRegB() { + return regB; + } + + public final void setRegB(int value) { + regB = value & 0xff; + } + + public final int getRegC() { + return regC; + } + + public final void setRegC(int value) { + regC = value & 0xff; + } + + public final int getRegD() { + return regD; + } + + public final void setRegD(int value) { + regD = value & 0xff; + } + + public final int getRegE() { + return regE; + } + + public final void setRegE(int value) { + regE = value & 0xff; + } + + public final int getRegH() { + return regH; + } + + public final void setRegH(int value) { + regH = value & 0xff; + } + + public final int getRegL() { + return regL; + } + + public final void setRegL(int value) { + regL = value & 0xff; + } + + // Acceso a registros alternativos de 8 bits + public final int getRegAx() { + return regAx; + } + + public final void setRegAx(int value) { + regAx = value & 0xff; + } + + public final int getRegFx() { + return regFx; + } + + public final void setRegFx(int value) { + regFx = value & 0xff; + } + + public final int getRegBx() { + return regBx; + } + + public final void setRegBx(int value) { + regBx = value & 0xff; + } + + public final int getRegCx() { + return regCx; + } + + public final void setRegCx(int value) { + regCx = value & 0xff; + } + + public final int getRegDx() { + return regDx; + } + + public final void setRegDx(int value) { + regDx = value & 0xff; + } + + public final int getRegEx() { + return regEx; + } + + public final void setRegEx(int value) { + regEx = value & 0xff; + } + + public final int getRegHx() { + return regHx; + } + + public final void setRegHx(int value) { + regHx = value & 0xff; + } + + public final int getRegLx() { + return regLx; + } + + public final void setRegLx(int value) { + regLx = value & 0xff; + } + + // Acceso a registros de 16 bits + public final int getRegAF() { + return (regA << 8) | regF; + } + + public final void setRegAF(int word) { + regA = (word >>> 8) & 0xff; + + regF = word & 0xff; + } + + public final int getRegAFx() { + return (regAx << 8) | regFx; + } + + public final void setRegAFx(int word) { + regAx = (word >>> 8) & 0xff; + regFx = word & 0xff; + } + + public final int getRegBC() { + return (regB << 8) | regC; + } + + public final void setRegBC(int word) { + regB = (word >>> 8) & 0xff; + regC = word & 0xff; + } + + public final int getRegBCx() { + return (regBx << 8) | regCx; + } + + public final void setRegBCx(int word) { + regBx = (word >>> 8) & 0xff; + regCx = word & 0xff; + } + + public final int getRegDE() { + return (regD << 8) | regE; + } + + public final void setRegDE(int word) { + regD = (word >>> 8) & 0xff; + regE = word & 0xff; + } + + public final int getRegDEx() { + return (regDx << 8) | regEx; + } + + public final void setRegDEx(int word) { + regDx = (word >>> 8) & 0xff; + regEx = word & 0xff; + } + + public final int getRegHL() { + return (regH << 8) | regL; + } + + public final void setRegHL(int word) { + regH = (word >>> 8) & 0xff; + regL = word & 0xff; + } + + public final int getRegHLx() { + return (regHx << 8) | regLx; + } + + public final void setRegHLx(int word) { + regHx = (word >>> 8) & 0xff; + regLx = word & 0xff; + } + + // Acceso a registros de propósito específico + public final int getRegPC() { + return regPC; + } + + public final void setRegPC(int address) { + regPC = address & 0xffff; + } + + public final int getRegSP() { + return regSP; + } + + public final void setRegSP(int word) { + regSP = word & 0xffff; + } + + public final int getRegIX() { + return regIX; + } + + public final void setRegIX(int word) { + regIX = word & 0xffff; + } + + public final int getRegIY() { + return regIY; + } + + public final void setRegIY(int word) { + regIY = word & 0xffff; + } + + public final int getRegI() { + return regI; + } + + public final void setRegI(int value) { + regI = value & 0xff; + } + + public final int getRegR() { + return regR; + } + + public final void setRegR(int value) { + regR = value & 0xff; + } + + // Acceso al registro oculto MEMPTR + public final int getMemPtr() { + return memptr; + } + + public final void setMemPtr(int word) { + memptr = word & 0xffff; + } + + // Acceso a los flip-flops de interrupción + public final boolean isIFF1() { + return ffIFF1; + } + + public final void setIFF1(boolean state) { + ffIFF1 = state; + } + + public final boolean isIFF2() { + return ffIFF2; + } + + public final void setIFF2(boolean state) { + ffIFF2 = state; + } + + public final boolean isNMI() { + return activeNMI; + } + + public final void setNMI(boolean nmi) { + activeNMI = nmi; + } + + // La línea de NMI se activa por impulso, no por nivel + public final void triggerNMI() { + activeNMI = true; + } + + // La línea INT se activa por nivel + public final boolean isINTLine() { + return activeINT; + } + + public final void setINTLine(boolean intLine) { + activeINT = intLine; + } + + //Acceso al modo de interrupción + public final IntMode getIM() { + return modeINT; + } + + public final void setIM(IntMode mode) { + modeINT = mode; + } + + public final boolean isHalted() { + return halted; + } + + public void setHalted(boolean state) { + halted = state; + } + + public final boolean isPendingEI() { + return pendingEI; + } + + public final void setPendingEI(boolean state) { + pendingEI = state; + } + + /** + * @return the flagQ + */ + public boolean isFlagQ() { + return flagQ; + } + + /** + * @param flagQ the flagQ to set + */ + public void setFlagQ(boolean flagQ) { + this.flagQ = flagQ; + } +}