From e3b535450243241c78af54678de8c1cee5e86b1c Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Sat, 14 Jul 2012 10:58:39 +0300 Subject: [PATCH] Gambatte core support --- COPYING.GPL | 340 + COPYING.GPL3 | 674 -- Makefile | 32 +- VERSION | 2 +- .../v084/0001-Make-libsnes-compile.patch | 82 - ...n-number-in-libsnes-to-be-v084-not-v.patch | 25 - ...03-Don-t-use-time-in-emulating-chips.patch | 84 - ...ve-controller-state-when-savestating.patch | 345 - ...ialization-of-64-bit-signed-integers.patch | 25 - ...ontend-to-control-random-number-seed.patch | 53 - .../v084/0007-Fix-mouse-polling.patch | 60 - .../v085/0001-Make-libsnes-compile.patch | 82 - ...n-number-in-libsnes-to-be-v085-not-v.patch | 25 - ...03-Don-t-use-time-in-emulating-chips.patch | 84 - ...ve-controller-state-when-savestating.patch | 346 - ...ialization-of-64-bit-signed-integers.patch | 25 - ...ontend-to-control-random-number-seed.patch | 53 - .../v085/0007-Fix-mouse-polling.patch | 60 - ...01-Don-t-use-time-in-emulating-chips.patch | 84 - ...ve-controller-state-when-savestating.patch | 346 - ...ontend-to-control-random-number-seed.patch | 53 - .../v086/0004-Fix-mouse-polling.patch | 60 - ...01-Don-t-use-time-in-emulating-chips.patch | 84 - ...ve-controller-state-when-savestating.patch | 346 - ...ontend-to-control-random-number-seed.patch | 53 - .../v087/0004-Fix-mouse-polling.patch | 60 - ...ake-libgambatte-rerecording-friendly.patch | 5970 +++++++++++++++++ src/Makefile | 4 +- src/core/bsnes-legacy.cpp | 946 --- src/core/gambatte.cpp | 487 ++ 30 files changed, 6807 insertions(+), 4083 deletions(-) create mode 100644 COPYING.GPL delete mode 100644 COPYING.GPL3 delete mode 100644 bsnes-patches/v084/0001-Make-libsnes-compile.patch delete mode 100644 bsnes-patches/v084/0002-Fix-bsnes-version-number-in-libsnes-to-be-v084-not-v.patch delete mode 100644 bsnes-patches/v084/0003-Don-t-use-time-in-emulating-chips.patch delete mode 100644 bsnes-patches/v084/0004-Save-controller-state-when-savestating.patch delete mode 100644 bsnes-patches/v084/0005-Fix-unserialization-of-64-bit-signed-integers.patch delete mode 100644 bsnes-patches/v084/0006-Allow-frontend-to-control-random-number-seed.patch delete mode 100644 bsnes-patches/v084/0007-Fix-mouse-polling.patch delete mode 100644 bsnes-patches/v085/0001-Make-libsnes-compile.patch delete mode 100644 bsnes-patches/v085/0002-Fix-bsnes-version-number-in-libsnes-to-be-v085-not-v.patch delete mode 100644 bsnes-patches/v085/0003-Don-t-use-time-in-emulating-chips.patch delete mode 100644 bsnes-patches/v085/0004-Save-controller-state-when-savestating.patch delete mode 100644 bsnes-patches/v085/0005-Fix-unserialization-of-64-bit-signed-integers.patch delete mode 100644 bsnes-patches/v085/0006-Allow-frontend-to-control-random-number-seed.patch delete mode 100644 bsnes-patches/v085/0007-Fix-mouse-polling.patch delete mode 100644 bsnes-patches/v086/0001-Don-t-use-time-in-emulating-chips.patch delete mode 100644 bsnes-patches/v086/0002-Save-controller-state-when-savestating.patch delete mode 100644 bsnes-patches/v086/0003-Allow-frontend-to-control-random-number-seed.patch delete mode 100644 bsnes-patches/v086/0004-Fix-mouse-polling.patch delete mode 100644 bsnes-patches/v087/0001-Don-t-use-time-in-emulating-chips.patch delete mode 100644 bsnes-patches/v087/0002-Save-controller-state-when-savestating.patch delete mode 100644 bsnes-patches/v087/0003-Allow-frontend-to-control-random-number-seed.patch delete mode 100644 bsnes-patches/v087/0004-Fix-mouse-polling.patch create mode 100644 libgambatte-patches/svn320/0001-Changes-to-make-libgambatte-rerecording-friendly.patch delete mode 100644 src/core/bsnes-legacy.cpp create mode 100644 src/core/gambatte.cpp diff --git a/COPYING.GPL b/COPYING.GPL new file mode 100644 index 00000000..d60c31a9 --- /dev/null +++ b/COPYING.GPL @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/COPYING.GPL3 b/COPYING.GPL3 deleted file mode 100644 index 94a9ed02..00000000 --- a/COPYING.GPL3 +++ /dev/null @@ -1,674 +0,0 @@ - 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/Makefile b/Makefile index c9195840..144b257a 100644 --- a/Makefile +++ b/Makefile @@ -7,11 +7,11 @@ REALCC = $(CROSS_PREFIX)$(CC) REALLD = $(CROSS_PREFIX)$(LD) REALRANLIB = $(CROSS_PREFIX)$(RANLIB) -BSNES_PATH=$(shell pwd)/bsnes +GAMBATTE_PATH=$(shell pwd)/gambatte #Flags. HOSTCCFLAGS = -std=gnu++0x -CFLAGS = -I$(BSNES_PATH) -std=gnu++0x $(USER_CFLAGS) +CFLAGS = -I$(GAMBATTE_PATH) -std=gnu++0x $(USER_CFLAGS) ifdef BOOST_NEEDS_MT BOOST_LIB_POSTFIX=-mt else @@ -31,35 +31,17 @@ $(error "Bad value for THREADS (expected NATIVE or BOOST)") endif endif -ifdef BSNES_IS_COMPAT -CFLAGS += -DBSNES_IS_COMPAT -endif - export all: src/__all_files__ -ifeq ($(BSNES_VERSION), 087) -BSNES_TARGET_STRING=target=libsnes -else -BSNES_TARGET_STRING=ui=ui-libsnes -endif +gambatte_compiler=$(subst ++,cc,$(REALCC)) -CFLAGS += -DBSNES_V${BSNES_VERSION} - -ifdef BSNES_IS_COMPAT -BSNES_PROFILE_STRING=profile=compatibility -else -BSNES_PROFILE_STRING=profile=accuracy -endif - -bsnes_compiler=$(subst ++,cc,$(REALCC)) - -bsnes/out/libsnes.$(ARCHIVE_SUFFIX): bsnes/snes/snes.hpp forcelook - $(MAKE) -C bsnes options=debugger $(BSNES_PROFILE_STRING) $(BSNES_TARGET_STRING) compiler=$(bsnes_compiler) +gambatte/libgambatte/libgambatte.$(ARCHIVE_SUFFIX): forcelook + $(MAKE) -C gambatte compiler=$(gambatte_compiler) $(REALRANLIB) $@ -src/__all_files__: src/core/version.cpp forcelook bsnes/out/libsnes.$(ARCHIVE_SUFFIX) +src/__all_files__: src/core/version.cpp forcelook gambatte/libgambatte/libgambatte.$(ARCHIVE_SUFFIX) $(MAKE) -C src precheck $(MAKE) -C src cp src/lsnes$(DOT_EXECUTABLE_SUFFIX) . @@ -71,7 +53,7 @@ src/core/version.cpp: buildaux/version.exe forcelook clean: - $(MAKE) -C bsnes clean + $(MAKE) -C gambatte clean $(MAKE) -C src clean forcelook: diff --git a/VERSION b/VERSION index b417d03e..5909c276 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1-Δ10ε1 \ No newline at end of file +1-Δ10ε1-gambatte \ No newline at end of file diff --git a/bsnes-patches/v084/0001-Make-libsnes-compile.patch b/bsnes-patches/v084/0001-Make-libsnes-compile.patch deleted file mode 100644 index 2c40cd70..00000000 --- a/bsnes-patches/v084/0001-Make-libsnes-compile.patch +++ /dev/null @@ -1,82 +0,0 @@ -From df75db4512ef7e6ad70f8cee8c7d7071132168f0 Mon Sep 17 00:00:00 2001 -From: Ilari Liusvaara -Date: Wed, 9 Nov 2011 00:30:36 +0200 -Subject: [PATCH 1/7] Make libsnes compile - -Changes between v083 and v084 had broken libsnes. Fix it so it at least -compiles. ---- - ui-libsnes/libsnes.cpp | 37 +++++++++++++++++++++++++++++++++++-- - 1 files changed, 35 insertions(+), 2 deletions(-) - -diff --git a/ui-libsnes/libsnes.cpp b/ui-libsnes/libsnes.cpp -index fbb4482..5f5ded6 100755 ---- a/ui-libsnes/libsnes.cpp -+++ b/ui-libsnes/libsnes.cpp -@@ -1,5 +1,6 @@ - #include "libsnes.hpp" - #include -+#include - - #include - #include -@@ -46,6 +47,38 @@ struct Interface : public SNES::Interface { - print(text, "\n"); - } - -+ void setCheats(const lstring &list = lstring{}) { -+ if(SNES::cartridge.mode() == SNES::Cartridge::Mode::SuperGameBoy) { -+ GameBoy::cheat.reset(); -+ for(auto &code : list) { -+ lstring codelist; -+ codelist.split("+", code); -+ for(auto &part : codelist) { -+ unsigned addr, data, comp; -+ if(GameBoy::Cheat::decode(part, addr, data, comp)) { -+ GameBoy::cheat.append({ addr, data, comp }); -+ } -+ } -+ } -+ GameBoy::cheat.synchronize(); -+ return; -+ } -+ -+ SNES::cheat.reset(); -+ for(auto &code : list) { -+ lstring codelist; -+ codelist.split("+", code); -+ for(auto &part : codelist) { -+ unsigned addr, data; -+ if(SNES::Cheat::decode(part, addr, data)) { -+ SNES::cheat.append({ addr, data }); -+ } -+ } -+ } -+ SNES::cheat.synchronize(); -+ } -+ -+ - string path(SNES::Cartridge::Slot slot, const string &hint) { - return { basename, hint }; - } -@@ -115,7 +148,7 @@ void snes_set_cartridge_basename(const char *basename) { - } - - void snes_init(void) { -- interface.initialize(&interface); -+ SNES::system.init(); - SNES::input.connect(SNES::Controller::Port1, SNES::Input::Device::Joypad); - SNES::input.connect(SNES::Controller::Port2, SNES::Input::Device::Joypad); - } -@@ -244,7 +277,7 @@ bool snes_load_cartridge_super_game_boy( - uint8_t *data = new uint8_t[dmg_size]; - memcpy(data, dmg_data, dmg_size); - string xmldmg = (dmg_xml && *dmg_xml) ? string(dmg_xml) : GameBoyCartridge(data, dmg_size).markup; -- GameBoy::cartridge.load(xmldmg, data, dmg_size); -+ GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy, xmldmg, data, dmg_size); - delete[] data; - } - SNES::cartridge.load(SNES::Cartridge::Mode::SuperGameBoy, xmlrom); --- -1.7.9.48.g85da4d - diff --git a/bsnes-patches/v084/0002-Fix-bsnes-version-number-in-libsnes-to-be-v084-not-v.patch b/bsnes-patches/v084/0002-Fix-bsnes-version-number-in-libsnes-to-be-v084-not-v.patch deleted file mode 100644 index 90f75acd..00000000 --- a/bsnes-patches/v084/0002-Fix-bsnes-version-number-in-libsnes-to-be-v084-not-v.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 637952f6b97bef882ca3870be8d434c31aeacf77 Mon Sep 17 00:00:00 2001 -From: Ilari Liusvaara -Date: Wed, 9 Nov 2011 00:31:59 +0200 -Subject: [PATCH 2/7] Fix bsnes version number in libsnes to be v084, not v083 - ---- - ui-libsnes/libsnes.cpp | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/ui-libsnes/libsnes.cpp b/ui-libsnes/libsnes.cpp -index 5f5ded6..6b4ef12 100755 ---- a/ui-libsnes/libsnes.cpp -+++ b/ui-libsnes/libsnes.cpp -@@ -112,7 +112,7 @@ struct Interface : public SNES::Interface { - static Interface interface; - - const char* snes_library_id(void) { -- return "bsnes v083"; -+ return "bsnes v084"; - } - - unsigned snes_library_revision_major(void) { --- -1.7.9.48.g85da4d - diff --git a/bsnes-patches/v084/0003-Don-t-use-time-in-emulating-chips.patch b/bsnes-patches/v084/0003-Don-t-use-time-in-emulating-chips.patch deleted file mode 100644 index 2b96339f..00000000 --- a/bsnes-patches/v084/0003-Don-t-use-time-in-emulating-chips.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 308ba2d96d3dc0e49821c9db9902882e3919e372 Mon Sep 17 00:00:00 2001 -From: Ilari Liusvaara -Date: Wed, 9 Nov 2011 00:37:44 +0200 -Subject: [PATCH 3/7] Don't use time() in emulating chips - -Instead of using time() in chip emulation, create new interface method -currentTime(), defaulting to time(0). This way frontend can cleanly -override the current time bsnes is using. ---- - snes/chip/bsx/satellaview/satellaview.cpp | 2 +- - snes/chip/spc7110/spc7110.cpp | 2 +- - snes/chip/srtc/srtc.cpp | 2 +- - snes/interface/interface.cpp | 5 +++++ - snes/interface/interface.hpp | 1 + - 5 files changed, 9 insertions(+), 3 deletions(-) - -diff --git a/snes/chip/bsx/satellaview/satellaview.cpp b/snes/chip/bsx/satellaview/satellaview.cpp -index 7bfd13f..b2565ea 100755 ---- a/snes/chip/bsx/satellaview/satellaview.cpp -+++ b/snes/chip/bsx/satellaview/satellaview.cpp -@@ -39,7 +39,7 @@ uint8 BSXSatellaview::mmio_read(unsigned addr) { - - if(counter == 0) { - time_t rawtime; -- time(&rawtime); -+ rawtime = SNES::interface->currentTime(); - tm *t = localtime(&rawtime); - - regs.r2192_hour = t->tm_hour; -diff --git a/snes/chip/spc7110/spc7110.cpp b/snes/chip/spc7110/spc7110.cpp -index 835ddbb..f5463e5 100755 ---- a/snes/chip/spc7110/spc7110.cpp -+++ b/snes/chip/spc7110/spc7110.cpp -@@ -102,7 +102,7 @@ void SPC7110::set_data_adjust(unsigned addr) { r4814 = addr; r4815 = addr >> 8; - - void SPC7110::update_time(int offset) { - time_t rtc_time = (rtc[16] << 0) | (rtc[17] << 8) | (rtc[18] << 16) | (rtc[19] << 24); -- time_t current_time = time(0) - offset; -+ time_t current_time = SNES::interface->currentTime() - offset; - - //sizeof(time_t) is platform-dependent; though rtc[] needs to be platform-agnostic. - //yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by -diff --git a/snes/chip/srtc/srtc.cpp b/snes/chip/srtc/srtc.cpp -index 1dd8f86..b11b756 100755 ---- a/snes/chip/srtc/srtc.cpp -+++ b/snes/chip/srtc/srtc.cpp -@@ -32,7 +32,7 @@ void SRTC::reset() { - - void SRTC::update_time() { - time_t rtc_time = (rtc[16] << 0) | (rtc[17] << 8) | (rtc[18] << 16) | (rtc[19] << 24); -- time_t current_time = time(0); -+ time_t current_time = SNES::interface->currentTime(); - - //sizeof(time_t) is platform-dependent; though rtc[] needs to be platform-agnostic. - //yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by -diff --git a/snes/interface/interface.cpp b/snes/interface/interface.cpp -index a0e3a81..b3017c9 100755 ---- a/snes/interface/interface.cpp -+++ b/snes/interface/interface.cpp -@@ -18,4 +18,9 @@ void Interface::message(const string &text) { - print(text, "\n"); - } - -+time_t Interface::currentTime() -+{ -+ return time(0); -+} -+ - } -diff --git a/snes/interface/interface.hpp b/snes/interface/interface.hpp -index f1a48c0..df975e8 100755 ---- a/snes/interface/interface.hpp -+++ b/snes/interface/interface.hpp -@@ -5,6 +5,7 @@ struct Interface { - - virtual string path(Cartridge::Slot slot, const string &hint) = 0; - virtual void message(const string &text); -+ virtual time_t currentTime(); - }; - - extern Interface *interface; --- -1.7.9.48.g85da4d - diff --git a/bsnes-patches/v084/0004-Save-controller-state-when-savestating.patch b/bsnes-patches/v084/0004-Save-controller-state-when-savestating.patch deleted file mode 100644 index 2f4bd375..00000000 --- a/bsnes-patches/v084/0004-Save-controller-state-when-savestating.patch +++ /dev/null @@ -1,345 +0,0 @@ -From 8d990991d97eb7742c4daa461b158d1aa9f6dce4 Mon Sep 17 00:00:00 2001 -From: Ilari Liusvaara -Date: Wed, 9 Nov 2011 01:52:08 +0200 -Subject: [PATCH 4/7] Save controller state when savestating - -When savestating, save the controller state and restore it upon loadstate. -Prevents libsnes from mixing up buttons. ---- - snes/controller/controller.cpp | 8 ++++++ - snes/controller/controller.hpp | 2 + - snes/controller/gamepad/gamepad.cpp | 13 ++++++++++ - snes/controller/gamepad/gamepad.hpp | 2 +- - snes/controller/justifier/justifier.cpp | 36 +++++++++++++++++++++++++++++ - snes/controller/justifier/justifier.hpp | 1 + - snes/controller/mouse/mouse.cpp | 13 ++++++++++ - snes/controller/mouse/mouse.hpp | 2 +- - snes/controller/multitap/multitap.cpp | 16 +++++++++++++ - snes/controller/multitap/multitap.hpp | 2 +- - snes/controller/superscope/superscope.cpp | 31 +++++++++++++++++++++++++ - snes/controller/superscope/superscope.hpp | 1 + - snes/input/input.cpp | 15 ++++++++++++ - snes/input/input.hpp | 1 + - snes/system/serialization.cpp | 1 + - 15 files changed, 141 insertions(+), 3 deletions(-) - -diff --git a/snes/controller/controller.cpp b/snes/controller/controller.cpp -index 9091b21..f254bed 100755 ---- a/snes/controller/controller.cpp -+++ b/snes/controller/controller.cpp -@@ -46,8 +46,16 @@ void Controller::iobit(bool data) { - } - } - -+void Controller::serialize(serializer& s) { -+ Processor::serialize(s); -+ //Save a zero block. -+ unsigned char blockzeroes[SaveSize] = {0}; -+ s.array(blockzeroes, SaveSize); -+} -+ - Controller::Controller(bool port) : port(port) { - if(!thread) create(Controller::Enter, 1); - } - -+ - } -diff --git a/snes/controller/controller.hpp b/snes/controller/controller.hpp -index 7332712..827b2eb 100755 ---- a/snes/controller/controller.hpp -+++ b/snes/controller/controller.hpp -@@ -13,12 +13,14 @@ - - struct Controller : Processor { - enum : bool { Port1 = 0, Port2 = 1 }; -+ enum { SaveSize = 16 }; - const bool port; - - static void Enter(); - virtual void enter(); - void step(unsigned clocks); - void synchronize_cpu(); -+ virtual void serialize(serializer& s); - - bool iobit(); - void iobit(bool data); -diff --git a/snes/controller/gamepad/gamepad.cpp b/snes/controller/gamepad/gamepad.cpp -index 594020d..4fa1c99 100755 ---- a/snes/controller/gamepad/gamepad.cpp -+++ b/snes/controller/gamepad/gamepad.cpp -@@ -13,6 +13,19 @@ void Gamepad::latch(bool data) { - counter = 0; - } - -+void Gamepad::serialize(serializer& s) { -+ Processor::serialize(s); -+ //Save block. -+ unsigned char block[Controller::SaveSize] = {0}; -+ block[0] = latched ? 1 : 0; -+ block[1] = counter; -+ s.array(block, Controller::SaveSize); -+ if(s.mode() == nall::serializer::Load) { -+ latched = (block[0] != 0); -+ counter = block[1]; -+ } -+} -+ - Gamepad::Gamepad(bool port) : Controller(port) { - latched = 0; - counter = 0; -diff --git a/snes/controller/gamepad/gamepad.hpp b/snes/controller/gamepad/gamepad.hpp -index c5ca69c..a2392d1 100755 ---- a/snes/controller/gamepad/gamepad.hpp -+++ b/snes/controller/gamepad/gamepad.hpp -@@ -2,7 +2,7 @@ struct Gamepad : Controller { - uint2 data(); - void latch(bool data); - Gamepad(bool port); -- -+ void serialize(serializer& s); - private: - bool latched; - unsigned counter; -diff --git a/snes/controller/justifier/justifier.cpp b/snes/controller/justifier/justifier.cpp -index 8b2d3ee..4b8eca8 100755 ---- a/snes/controller/justifier/justifier.cpp -+++ b/snes/controller/justifier/justifier.cpp -@@ -103,6 +103,42 @@ void Justifier::latch(bool data) { - if(latched == 0) active = !active; //toggle between both controllers, even when unchained - } - -+void Justifier::serialize(serializer& s) { -+ Processor::serialize(s); -+ //Save block. -+ unsigned char block[Controller::SaveSize] = {0}; -+ block[0] = latched ? 1 : 0; -+ block[1] = counter; -+ block[2] = active ? 1 : 0; -+ block[3] = trigger1 ? 1 : 0; -+ block[4] = trigger2 ? 1 : 0; -+ block[5] = start1 ? 1 : 0; -+ block[6] = start2 ? 1 : 0; -+ block[7] = (unsigned short)x1 >> 8; -+ block[8] = (unsigned short)x1; -+ block[9] = (unsigned short)x2 >> 8; -+ block[10] = (unsigned short)x2; -+ block[11] = (unsigned short)y1 >> 8; -+ block[12] = (unsigned short)y1; -+ block[13] = (unsigned short)y2 >> 8; -+ block[14] = (unsigned short)y2; -+ s.array(block, Controller::SaveSize); -+ if(s.mode() == nall::serializer::Load) { -+ latched = (block[0] != 0); -+ counter = block[1]; -+ active = (block[2] != 0); -+ trigger1 = (block[3] != 0); -+ trigger2 = (block[4] != 0); -+ start1 = (block[5] != 0); -+ start2 = (block[6] != 0); -+ x1 = (short)(((unsigned short)block[7] << 8) | (unsigned short)block[8]); -+ x2 = (short)(((unsigned short)block[9] << 8) | (unsigned short)block[10]); -+ y1 = (short)(((unsigned short)block[11] << 8) | (unsigned short)block[12]); -+ y2 = (short)(((unsigned short)block[13] << 8) | (unsigned short)block[14]); -+ } -+} -+ -+ - Justifier::Justifier(bool port, bool chained) : Controller(port), chained(chained) { - create(Controller::Enter, 21477272); - latched = 0; -diff --git a/snes/controller/justifier/justifier.hpp b/snes/controller/justifier/justifier.hpp -index 8259147..96e09dc 100755 ---- a/snes/controller/justifier/justifier.hpp -+++ b/snes/controller/justifier/justifier.hpp -@@ -2,6 +2,7 @@ struct Justifier : Controller { - void enter(); - uint2 data(); - void latch(bool data); -+ void serialize(serializer& s); - Justifier(bool port, bool chained); - - //private: -diff --git a/snes/controller/mouse/mouse.cpp b/snes/controller/mouse/mouse.cpp -index c9f5d16..6b26fae 100755 ---- a/snes/controller/mouse/mouse.cpp -+++ b/snes/controller/mouse/mouse.cpp -@@ -61,6 +61,19 @@ void Mouse::latch(bool data) { - counter = 0; - } - -+void Mouse::serialize(serializer& s) { -+ Processor::serialize(s); -+ //Save block. -+ unsigned char block[Controller::SaveSize] = {0}; -+ block[0] = latched ? 1 : 0; -+ block[1] = counter; -+ s.array(block, Controller::SaveSize); -+ if(s.mode() == nall::serializer::Load) { -+ latched = (block[0] != 0); -+ counter = block[1]; -+ } -+} -+ - Mouse::Mouse(bool port) : Controller(port) { - latched = 0; - counter = 0; -diff --git a/snes/controller/mouse/mouse.hpp b/snes/controller/mouse/mouse.hpp -index 95e24b6..b66ea51 100755 ---- a/snes/controller/mouse/mouse.hpp -+++ b/snes/controller/mouse/mouse.hpp -@@ -2,7 +2,7 @@ struct Mouse : Controller { - uint2 data(); - void latch(bool data); - Mouse(bool port); -- -+ void serialize(serializer& s); - private: - bool latched; - unsigned counter; -diff --git a/snes/controller/multitap/multitap.cpp b/snes/controller/multitap/multitap.cpp -index 3a6eb72..146c41d 100755 ---- a/snes/controller/multitap/multitap.cpp -+++ b/snes/controller/multitap/multitap.cpp -@@ -30,6 +30,22 @@ void Multitap::latch(bool data) { - counter2 = 0; - } - -+void Multitap::serialize(serializer& s) { -+ Processor::serialize(s); -+ //Save block. -+ unsigned char block[Controller::SaveSize] = {0}; -+ block[0] = latched ? 1 : 0; -+ block[1] = counter1; -+ block[2] = counter2; -+ s.array(block, Controller::SaveSize); -+ if(s.mode() == nall::serializer::Load) { -+ latched = (block[0] != 0); -+ counter1 = block[1]; -+ counter2 = block[2]; -+ } -+} -+ -+ - Multitap::Multitap(bool port) : Controller(port) { - latched = 0; - counter1 = 0; -diff --git a/snes/controller/multitap/multitap.hpp b/snes/controller/multitap/multitap.hpp -index 0540af7..e6324ac 100755 ---- a/snes/controller/multitap/multitap.hpp -+++ b/snes/controller/multitap/multitap.hpp -@@ -2,7 +2,7 @@ struct Multitap : Controller { - uint2 data(); - void latch(bool data); - Multitap(bool port); -- -+ void serialize(serializer& s); - private: - bool latched; - unsigned counter1; -diff --git a/snes/controller/superscope/superscope.cpp b/snes/controller/superscope/superscope.cpp -index e97a2ff..bb260b9 100755 ---- a/snes/controller/superscope/superscope.cpp -+++ b/snes/controller/superscope/superscope.cpp -@@ -104,6 +104,37 @@ void SuperScope::latch(bool data) { - counter = 0; - } - -+void SuperScope::serialize(serializer& s) { -+ Processor::serialize(s); -+ //Save block. -+ unsigned char block[Controller::SaveSize] = {0}; -+ block[0] = latched ? 1 : 0; -+ block[1] = counter; -+ block[2] = trigger ? 1 : 0; -+ block[3] = cursor ? 1 : 0; -+ block[4] = turbo ? 1 : 0; -+ block[5] = pause ? 1 : 0; -+ block[6] = offscreen ? 1 : 0; -+ block[7] = (unsigned short)x >> 8; -+ block[8] = (unsigned short)x; -+ block[9] = (unsigned short)y >> 8; -+ block[10] = (unsigned short)y; -+ -+ s.array(block, Controller::SaveSize); -+ if(s.mode() == nall::serializer::Load) { -+ latched = (block[0] != 0); -+ counter = block[1]; -+ trigger = (block[2] != 0); -+ cursor = (block[3] != 0); -+ turbo = (block[4] != 0); -+ pause = (block[5] != 0); -+ offscreen = (block[6] != 0); -+ x = (short)(((unsigned short)block[7] << 8) | (unsigned short)block[8]); -+ y = (short)(((unsigned short)block[9] << 8) | (unsigned short)block[10]); -+ } -+} -+ -+ - SuperScope::SuperScope(bool port) : Controller(port) { - create(Controller::Enter, 21477272); - latched = 0; -diff --git a/snes/controller/superscope/superscope.hpp b/snes/controller/superscope/superscope.hpp -index a7a90b7..93509d7 100755 ---- a/snes/controller/superscope/superscope.hpp -+++ b/snes/controller/superscope/superscope.hpp -@@ -2,6 +2,7 @@ struct SuperScope : Controller { - void enter(); - uint2 data(); - void latch(bool data); -+ void serialize(serializer& s); - SuperScope(bool port); - - //private: -diff --git a/snes/input/input.cpp b/snes/input/input.cpp -index 9050310..7030495 100755 ---- a/snes/input/input.cpp -+++ b/snes/input/input.cpp -@@ -26,6 +26,21 @@ void Input::connect(bool port, Input::Device id) { - } - } - -+void Input::serialize(serializer &s) -+{ -+ int p1, p2; -+ p1 = (int)config.controller_port1; -+ p2 = (int)config.controller_port2; -+ s.integer(p1); -+ s.integer(p2); -+ if(s.mode() == nall::serializer::Load) { -+ connect(Controller::Port1, (Device)p1); -+ connect(Controller::Port2, (Device)p2); -+ } -+ port1->serialize(s); -+ port2->serialize(s); -+} -+ - Input::Input() : port1(nullptr), port2(nullptr) { - connect(Controller::Port1, Input::Device::Joypad); - connect(Controller::Port2, Input::Device::Joypad); -diff --git a/snes/input/input.hpp b/snes/input/input.hpp -index 13ef46e..6832e82 100755 ---- a/snes/input/input.hpp -+++ b/snes/input/input.hpp -@@ -31,6 +31,7 @@ struct Input { - Controller *port1; - Controller *port2; - -+ void serialize(serializer &s); - void connect(bool port, Input::Device id); - Input(); - ~Input(); -diff --git a/snes/system/serialization.cpp b/snes/system/serialization.cpp -index f7d6f3b..08e7051 100755 ---- a/snes/system/serialization.cpp -+++ b/snes/system/serialization.cpp -@@ -56,6 +56,7 @@ void System::serialize_all(serializer &s) { - smp.serialize(s); - ppu.serialize(s); - dsp.serialize(s); -+ input.serialize(s); - - if(cartridge.mode() == Cartridge::Mode::SufamiTurbo) sufamiturbo.serialize(s); - if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.serialize(s); --- -1.7.9.48.g85da4d - diff --git a/bsnes-patches/v084/0005-Fix-unserialization-of-64-bit-signed-integers.patch b/bsnes-patches/v084/0005-Fix-unserialization-of-64-bit-signed-integers.patch deleted file mode 100644 index 5c049a1a..00000000 --- a/bsnes-patches/v084/0005-Fix-unserialization-of-64-bit-signed-integers.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0520c04455b9e96e6caa54009d4ef7c300146c67 Mon Sep 17 00:00:00 2001 -From: Ilari Liusvaara -Date: Fri, 11 Nov 2011 03:05:48 +0200 -Subject: [PATCH 5/7] Fix unserialization of 64-bit signed integers - ---- - nall/serializer.hpp | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/nall/serializer.hpp b/nall/serializer.hpp -index ff2337a..e6bc8fa 100755 ---- a/nall/serializer.hpp -+++ b/nall/serializer.hpp -@@ -58,7 +58,7 @@ namespace nall { - for(unsigned n = 0; n < size; n++) idata[isize++] = value >> (n << 3); - } else if(imode == Load) { - value = 0; -- for(unsigned n = 0; n < size; n++) value |= idata[isize++] << (n << 3); -+ for(unsigned n = 0; n < size; n++) value |= (unsigned long long)idata[isize++] << (n << 3); - } else if(imode == Size) { - isize += size; - } --- -1.7.9.48.g85da4d - diff --git a/bsnes-patches/v084/0006-Allow-frontend-to-control-random-number-seed.patch b/bsnes-patches/v084/0006-Allow-frontend-to-control-random-number-seed.patch deleted file mode 100644 index afb0a191..00000000 --- a/bsnes-patches/v084/0006-Allow-frontend-to-control-random-number-seed.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 723b5884d53db9d5e24b8cd300e97b1bb12fba29 Mon Sep 17 00:00:00 2001 -From: Ilari Liusvaara -Date: Fri, 11 Nov 2011 19:49:46 +0200 -Subject: [PATCH 6/7] Allow frontend to control random number seed - ---- - snes/interface/interface.cpp | 5 +++++ - snes/interface/interface.hpp | 1 + - snes/system/system.cpp | 2 +- - 3 files changed, 7 insertions(+), 1 deletions(-) - -diff --git a/snes/interface/interface.cpp b/snes/interface/interface.cpp -index b3017c9..0a21a13 100755 ---- a/snes/interface/interface.cpp -+++ b/snes/interface/interface.cpp -@@ -23,4 +23,9 @@ time_t Interface::currentTime() - return time(0); - } - -+time_t Interface::randomSeed() -+{ -+ return time(0); -+} -+ - } -diff --git a/snes/interface/interface.hpp b/snes/interface/interface.hpp -index df975e8..30ee7fd 100755 ---- a/snes/interface/interface.hpp -+++ b/snes/interface/interface.hpp -@@ -6,6 +6,7 @@ struct Interface { - virtual string path(Cartridge::Slot slot, const string &hint) = 0; - virtual void message(const string &text); - virtual time_t currentTime(); -+ virtual time_t randomSeed(); - }; - - extern Interface *interface; -diff --git a/snes/system/system.cpp b/snes/system/system.cpp -index 6881810..8583595 100755 ---- a/snes/system/system.cpp -+++ b/snes/system/system.cpp -@@ -147,7 +147,7 @@ void System::unload() { - } - - void System::power() { -- random.seed((unsigned)time(0)); -+ random.seed((unsigned)interface->randomSeed()); - - region = config.region; - expansion = config.expansion_port; --- -1.7.9.48.g85da4d - diff --git a/bsnes-patches/v084/0007-Fix-mouse-polling.patch b/bsnes-patches/v084/0007-Fix-mouse-polling.patch deleted file mode 100644 index e56f7995..00000000 --- a/bsnes-patches/v084/0007-Fix-mouse-polling.patch +++ /dev/null @@ -1,60 +0,0 @@ -From eea50468e8d7e7a034b05c819aef11a032f972eb Mon Sep 17 00:00:00 2001 -From: Ilari Liusvaara -Date: Wed, 7 Mar 2012 16:57:18 +0200 -Subject: [PATCH 7/7] Fix mouse polling - -Don't poll for mouse motion excessive number of times (no need to poll it for -each bit!) ---- - snes/controller/mouse/mouse.cpp | 12 ++++++++++-- - snes/controller/mouse/mouse.hpp | 2 ++ - 2 files changed, 12 insertions(+), 2 deletions(-) - -diff --git a/snes/controller/mouse/mouse.cpp b/snes/controller/mouse/mouse.cpp -index 6b26fae..824ecd3 100755 ---- a/snes/controller/mouse/mouse.cpp -+++ b/snes/controller/mouse/mouse.cpp -@@ -3,8 +3,10 @@ - uint2 Mouse::data() { - if(counter >= 32) return 1; - -- int position_x = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right -- int position_y = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down -+ if(counter == 0) { -+ position_x = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right -+ position_y = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down -+ } - - bool direction_x = position_x < 0; //0 = right, 1 = left - bool direction_y = position_y < 0; //0 = down, 1 = up -@@ -67,10 +69,16 @@ void Mouse::serialize(serializer& s) { - unsigned char block[Controller::SaveSize] = {0}; - block[0] = latched ? 1 : 0; - block[1] = counter; -+ block[2] = (unsigned short)position_x >> 8; -+ block[3] = (unsigned short)position_x; -+ block[4] = (unsigned short)position_y >> 8; -+ block[5] = (unsigned short)position_y; - s.array(block, Controller::SaveSize); - if(s.mode() == nall::serializer::Load) { - latched = (block[0] != 0); - counter = block[1]; -+ position_x = (short)(((unsigned short)block[2] << 8) | (unsigned short)block[3]); -+ position_y = (short)(((unsigned short)block[4] << 8) | (unsigned short)block[5]); - } - } - -diff --git a/snes/controller/mouse/mouse.hpp b/snes/controller/mouse/mouse.hpp -index b66ea51..6074f34 100755 ---- a/snes/controller/mouse/mouse.hpp -+++ b/snes/controller/mouse/mouse.hpp -@@ -6,4 +6,6 @@ struct Mouse : Controller { - private: - bool latched; - unsigned counter; -+ int position_x; -+ int position_y; - }; --- -1.7.9.48.g85da4d - diff --git a/bsnes-patches/v085/0001-Make-libsnes-compile.patch b/bsnes-patches/v085/0001-Make-libsnes-compile.patch deleted file mode 100644 index 548011b0..00000000 --- a/bsnes-patches/v085/0001-Make-libsnes-compile.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 7c8d537a7be0f9c5883393e0d4a0df76d69bf19c Mon Sep 17 00:00:00 2001 -From: Ilari Liusvaara -Date: Wed, 9 Nov 2011 00:30:36 +0200 -Subject: [PATCH 1/7] Make libsnes compile - -Changes between v083 and v084 had broken libsnes. Fix it so it at least -compiles. ---- - ui-libsnes/libsnes.cpp | 37 +++++++++++++++++++++++++++++++++++-- - 1 files changed, 35 insertions(+), 2 deletions(-) - -diff --git a/ui-libsnes/libsnes.cpp b/ui-libsnes/libsnes.cpp -index fbb4482..5f5ded6 100755 ---- a/ui-libsnes/libsnes.cpp -+++ b/ui-libsnes/libsnes.cpp -@@ -1,5 +1,6 @@ - #include "libsnes.hpp" - #include -+#include - - #include - #include -@@ -46,6 +47,38 @@ struct Interface : public SNES::Interface { - print(text, "\n"); - } - -+ void setCheats(const lstring &list = lstring{}) { -+ if(SNES::cartridge.mode() == SNES::Cartridge::Mode::SuperGameBoy) { -+ GameBoy::cheat.reset(); -+ for(auto &code : list) { -+ lstring codelist; -+ codelist.split("+", code); -+ for(auto &part : codelist) { -+ unsigned addr, data, comp; -+ if(GameBoy::Cheat::decode(part, addr, data, comp)) { -+ GameBoy::cheat.append({ addr, data, comp }); -+ } -+ } -+ } -+ GameBoy::cheat.synchronize(); -+ return; -+ } -+ -+ SNES::cheat.reset(); -+ for(auto &code : list) { -+ lstring codelist; -+ codelist.split("+", code); -+ for(auto &part : codelist) { -+ unsigned addr, data; -+ if(SNES::Cheat::decode(part, addr, data)) { -+ SNES::cheat.append({ addr, data }); -+ } -+ } -+ } -+ SNES::cheat.synchronize(); -+ } -+ -+ - string path(SNES::Cartridge::Slot slot, const string &hint) { - return { basename, hint }; - } -@@ -115,7 +148,7 @@ void snes_set_cartridge_basename(const char *basename) { - } - - void snes_init(void) { -- interface.initialize(&interface); -+ SNES::system.init(); - SNES::input.connect(SNES::Controller::Port1, SNES::Input::Device::Joypad); - SNES::input.connect(SNES::Controller::Port2, SNES::Input::Device::Joypad); - } -@@ -244,7 +277,7 @@ bool snes_load_cartridge_super_game_boy( - uint8_t *data = new uint8_t[dmg_size]; - memcpy(data, dmg_data, dmg_size); - string xmldmg = (dmg_xml && *dmg_xml) ? string(dmg_xml) : GameBoyCartridge(data, dmg_size).markup; -- GameBoy::cartridge.load(xmldmg, data, dmg_size); -+ GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy, xmldmg, data, dmg_size); - delete[] data; - } - SNES::cartridge.load(SNES::Cartridge::Mode::SuperGameBoy, xmlrom); --- -1.7.9.48.g85da4d - diff --git a/bsnes-patches/v085/0002-Fix-bsnes-version-number-in-libsnes-to-be-v085-not-v.patch b/bsnes-patches/v085/0002-Fix-bsnes-version-number-in-libsnes-to-be-v085-not-v.patch deleted file mode 100644 index 793f0408..00000000 --- a/bsnes-patches/v085/0002-Fix-bsnes-version-number-in-libsnes-to-be-v085-not-v.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 5f9f74b1334cb05d8636d71c2cfc0a48685a7347 Mon Sep 17 00:00:00 2001 -From: Ilari Liusvaara -Date: Wed, 9 Nov 2011 00:31:59 +0200 -Subject: [PATCH 2/7] Fix bsnes version number in libsnes to be v085, not v083 - ---- - ui-libsnes/libsnes.cpp | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/ui-libsnes/libsnes.cpp b/ui-libsnes/libsnes.cpp -index 5f5ded6..0e63075 100755 ---- a/ui-libsnes/libsnes.cpp -+++ b/ui-libsnes/libsnes.cpp -@@ -112,7 +112,7 @@ struct Interface : public SNES::Interface { - static Interface interface; - - const char* snes_library_id(void) { -- return "bsnes v083"; -+ return "bsnes v085"; - } - - unsigned snes_library_revision_major(void) { --- -1.7.9.48.g85da4d - diff --git a/bsnes-patches/v085/0003-Don-t-use-time-in-emulating-chips.patch b/bsnes-patches/v085/0003-Don-t-use-time-in-emulating-chips.patch deleted file mode 100644 index 5191f654..00000000 --- a/bsnes-patches/v085/0003-Don-t-use-time-in-emulating-chips.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 773d0a3f71fca2df375a8e75c081d1f28c3b817b Mon Sep 17 00:00:00 2001 -From: Ilari Liusvaara -Date: Wed, 9 Nov 2011 00:37:44 +0200 -Subject: [PATCH 3/7] Don't use time() in emulating chips - -Instead of using time() in chip emulation, create new interface method -currentTime(), defaulting to time(0). This way frontend can cleanly -override the current time bsnes is using. ---- - snes/chip/bsx/satellaview/satellaview.cpp | 2 +- - snes/chip/spc7110/spc7110.cpp | 2 +- - snes/chip/srtc/srtc.cpp | 2 +- - snes/interface/interface.cpp | 5 +++++ - snes/interface/interface.hpp | 1 + - 5 files changed, 9 insertions(+), 3 deletions(-) - -diff --git a/snes/chip/bsx/satellaview/satellaview.cpp b/snes/chip/bsx/satellaview/satellaview.cpp -index 386fb62..3c98019 100755 ---- a/snes/chip/bsx/satellaview/satellaview.cpp -+++ b/snes/chip/bsx/satellaview/satellaview.cpp -@@ -38,7 +38,7 @@ uint8 BSXSatellaview::mmio_read(unsigned addr) { - - if(counter == 0) { - time_t rawtime; -- time(&rawtime); -+ rawtime = SNES::interface->currentTime(); - tm *t = localtime(&rawtime); - - regs.r2192_hour = t->tm_hour; -diff --git a/snes/chip/spc7110/spc7110.cpp b/snes/chip/spc7110/spc7110.cpp -index d2dc640..74a817a 100755 ---- a/snes/chip/spc7110/spc7110.cpp -+++ b/snes/chip/spc7110/spc7110.cpp -@@ -101,7 +101,7 @@ void SPC7110::set_data_adjust(unsigned addr) { r4814 = addr; r4815 = addr >> 8; - - void SPC7110::update_time(int offset) { - time_t rtc_time = (rtc[16] << 0) | (rtc[17] << 8) | (rtc[18] << 16) | (rtc[19] << 24); -- time_t current_time = time(0) - offset; -+ time_t current_time = SNES::interface->currentTime() - offset; - - //sizeof(time_t) is platform-dependent; though rtc[] needs to be platform-agnostic. - //yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by -diff --git a/snes/chip/srtc/srtc.cpp b/snes/chip/srtc/srtc.cpp -index 1b2fd2a..78fc4c1 100755 ---- a/snes/chip/srtc/srtc.cpp -+++ b/snes/chip/srtc/srtc.cpp -@@ -31,7 +31,7 @@ void SRTC::reset() { - - void SRTC::update_time() { - time_t rtc_time = (rtc[16] << 0) | (rtc[17] << 8) | (rtc[18] << 16) | (rtc[19] << 24); -- time_t current_time = time(0); -+ time_t current_time = SNES::interface->currentTime(); - - //sizeof(time_t) is platform-dependent; though rtc[] needs to be platform-agnostic. - //yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by -diff --git a/snes/interface/interface.cpp b/snes/interface/interface.cpp -index a0e3a81..b3017c9 100755 ---- a/snes/interface/interface.cpp -+++ b/snes/interface/interface.cpp -@@ -18,4 +18,9 @@ void Interface::message(const string &text) { - print(text, "\n"); - } - -+time_t Interface::currentTime() -+{ -+ return time(0); -+} -+ - } -diff --git a/snes/interface/interface.hpp b/snes/interface/interface.hpp -index f1a48c0..df975e8 100755 ---- a/snes/interface/interface.hpp -+++ b/snes/interface/interface.hpp -@@ -5,6 +5,7 @@ struct Interface { - - virtual string path(Cartridge::Slot slot, const string &hint) = 0; - virtual void message(const string &text); -+ virtual time_t currentTime(); - }; - - extern Interface *interface; --- -1.7.9.48.g85da4d - diff --git a/bsnes-patches/v085/0004-Save-controller-state-when-savestating.patch b/bsnes-patches/v085/0004-Save-controller-state-when-savestating.patch deleted file mode 100644 index ef396980..00000000 --- a/bsnes-patches/v085/0004-Save-controller-state-when-savestating.patch +++ /dev/null @@ -1,346 +0,0 @@ -From c7bf497a7016c9be3a1e2fff46973a555f9ad555 Mon Sep 17 00:00:00 2001 -From: Ilari Liusvaara -Date: Wed, 9 Nov 2011 01:52:08 +0200 -Subject: [PATCH 4/7] Save controller state when savestating - -When savestating, save the controller state and restore it upon loadstate. -Prevents libsnes from mixing up buttons. ---- - snes/controller/controller.cpp | 8 ++++++ - snes/controller/controller.hpp | 2 + - snes/controller/gamepad/gamepad.cpp | 13 ++++++++++ - snes/controller/gamepad/gamepad.hpp | 2 +- - snes/controller/justifier/justifier.cpp | 36 +++++++++++++++++++++++++++++ - snes/controller/justifier/justifier.hpp | 1 + - snes/controller/mouse/mouse.cpp | 13 ++++++++++ - snes/controller/mouse/mouse.hpp | 2 +- - snes/controller/multitap/multitap.cpp | 16 +++++++++++++ - snes/controller/multitap/multitap.hpp | 2 +- - snes/controller/superscope/superscope.cpp | 31 +++++++++++++++++++++++++ - snes/controller/superscope/superscope.hpp | 1 + - snes/system/input.cpp | 16 +++++++++++++ - snes/system/input.hpp | 1 + - snes/system/serialization.cpp | 1 + - 15 files changed, 142 insertions(+), 3 deletions(-) - -diff --git a/snes/controller/controller.cpp b/snes/controller/controller.cpp -index 9091b21..f254bed 100755 ---- a/snes/controller/controller.cpp -+++ b/snes/controller/controller.cpp -@@ -46,8 +46,16 @@ void Controller::iobit(bool data) { - } - } - -+void Controller::serialize(serializer& s) { -+ Processor::serialize(s); -+ //Save a zero block. -+ unsigned char blockzeroes[SaveSize] = {0}; -+ s.array(blockzeroes, SaveSize); -+} -+ - Controller::Controller(bool port) : port(port) { - if(!thread) create(Controller::Enter, 1); - } - -+ - } -diff --git a/snes/controller/controller.hpp b/snes/controller/controller.hpp -index 7332712..827b2eb 100755 ---- a/snes/controller/controller.hpp -+++ b/snes/controller/controller.hpp -@@ -13,12 +13,14 @@ - - struct Controller : Processor { - enum : bool { Port1 = 0, Port2 = 1 }; -+ enum { SaveSize = 16 }; - const bool port; - - static void Enter(); - virtual void enter(); - void step(unsigned clocks); - void synchronize_cpu(); -+ virtual void serialize(serializer& s); - - bool iobit(); - void iobit(bool data); -diff --git a/snes/controller/gamepad/gamepad.cpp b/snes/controller/gamepad/gamepad.cpp -index 594020d..4fa1c99 100755 ---- a/snes/controller/gamepad/gamepad.cpp -+++ b/snes/controller/gamepad/gamepad.cpp -@@ -13,6 +13,19 @@ void Gamepad::latch(bool data) { - counter = 0; - } - -+void Gamepad::serialize(serializer& s) { -+ Processor::serialize(s); -+ //Save block. -+ unsigned char block[Controller::SaveSize] = {0}; -+ block[0] = latched ? 1 : 0; -+ block[1] = counter; -+ s.array(block, Controller::SaveSize); -+ if(s.mode() == nall::serializer::Load) { -+ latched = (block[0] != 0); -+ counter = block[1]; -+ } -+} -+ - Gamepad::Gamepad(bool port) : Controller(port) { - latched = 0; - counter = 0; -diff --git a/snes/controller/gamepad/gamepad.hpp b/snes/controller/gamepad/gamepad.hpp -index c5ca69c..a2392d1 100755 ---- a/snes/controller/gamepad/gamepad.hpp -+++ b/snes/controller/gamepad/gamepad.hpp -@@ -2,7 +2,7 @@ struct Gamepad : Controller { - uint2 data(); - void latch(bool data); - Gamepad(bool port); -- -+ void serialize(serializer& s); - private: - bool latched; - unsigned counter; -diff --git a/snes/controller/justifier/justifier.cpp b/snes/controller/justifier/justifier.cpp -index 6207916..ad13a9b 100755 ---- a/snes/controller/justifier/justifier.cpp -+++ b/snes/controller/justifier/justifier.cpp -@@ -100,6 +100,42 @@ void Justifier::latch(bool data) { - if(latched == 0) active = !active; //toggle between both controllers, even when unchained - } - -+void Justifier::serialize(serializer& s) { -+ Processor::serialize(s); -+ //Save block. -+ unsigned char block[Controller::SaveSize] = {0}; -+ block[0] = latched ? 1 : 0; -+ block[1] = counter; -+ block[2] = active ? 1 : 0; -+ block[3] = player1.trigger ? 1 : 0; -+ block[4] = player2.trigger ? 1 : 0; -+ block[5] = player1.start ? 1 : 0; -+ block[6] = player2.start ? 1 : 0; -+ block[7] = (unsigned short)player1.x >> 8; -+ block[8] = (unsigned short)player1.x; -+ block[9] = (unsigned short)player2.x >> 8; -+ block[10] = (unsigned short)player2.x; -+ block[11] = (unsigned short)player1.y >> 8; -+ block[12] = (unsigned short)player1.y; -+ block[13] = (unsigned short)player2.y >> 8; -+ block[14] = (unsigned short)player2.y; -+ s.array(block, Controller::SaveSize); -+ if(s.mode() == nall::serializer::Load) { -+ latched = (block[0] != 0); -+ counter = block[1]; -+ active = (block[2] != 0); -+ player1.trigger = (block[3] != 0); -+ player2.trigger = (block[4] != 0); -+ player1.start = (block[5] != 0); -+ player2.start = (block[6] != 0); -+ player1.x = (short)(((unsigned short)block[7] << 8) | (unsigned short)block[8]); -+ player2.x = (short)(((unsigned short)block[9] << 8) | (unsigned short)block[10]); -+ player1.y = (short)(((unsigned short)block[11] << 8) | (unsigned short)block[12]); -+ player2.y = (short)(((unsigned short)block[13] << 8) | (unsigned short)block[14]); -+ } -+} -+ -+ - Justifier::Justifier(bool port, bool chained) : Controller(port), chained(chained) { - create(Controller::Enter, 21477272); - latched = 0; -diff --git a/snes/controller/justifier/justifier.hpp b/snes/controller/justifier/justifier.hpp -index f927acf..6b7bba0 100755 ---- a/snes/controller/justifier/justifier.hpp -+++ b/snes/controller/justifier/justifier.hpp -@@ -2,6 +2,7 @@ struct Justifier : Controller { - void enter(); - uint2 data(); - void latch(bool data); -+ void serialize(serializer& s); - Justifier(bool port, bool chained); - - //private: -diff --git a/snes/controller/mouse/mouse.cpp b/snes/controller/mouse/mouse.cpp -index c9f5d16..6b26fae 100755 ---- a/snes/controller/mouse/mouse.cpp -+++ b/snes/controller/mouse/mouse.cpp -@@ -61,6 +61,19 @@ void Mouse::latch(bool data) { - counter = 0; - } - -+void Mouse::serialize(serializer& s) { -+ Processor::serialize(s); -+ //Save block. -+ unsigned char block[Controller::SaveSize] = {0}; -+ block[0] = latched ? 1 : 0; -+ block[1] = counter; -+ s.array(block, Controller::SaveSize); -+ if(s.mode() == nall::serializer::Load) { -+ latched = (block[0] != 0); -+ counter = block[1]; -+ } -+} -+ - Mouse::Mouse(bool port) : Controller(port) { - latched = 0; - counter = 0; -diff --git a/snes/controller/mouse/mouse.hpp b/snes/controller/mouse/mouse.hpp -index 95e24b6..b66ea51 100755 ---- a/snes/controller/mouse/mouse.hpp -+++ b/snes/controller/mouse/mouse.hpp -@@ -2,7 +2,7 @@ struct Mouse : Controller { - uint2 data(); - void latch(bool data); - Mouse(bool port); -- -+ void serialize(serializer& s); - private: - bool latched; - unsigned counter; -diff --git a/snes/controller/multitap/multitap.cpp b/snes/controller/multitap/multitap.cpp -index 3a6eb72..146c41d 100755 ---- a/snes/controller/multitap/multitap.cpp -+++ b/snes/controller/multitap/multitap.cpp -@@ -30,6 +30,22 @@ void Multitap::latch(bool data) { - counter2 = 0; - } - -+void Multitap::serialize(serializer& s) { -+ Processor::serialize(s); -+ //Save block. -+ unsigned char block[Controller::SaveSize] = {0}; -+ block[0] = latched ? 1 : 0; -+ block[1] = counter1; -+ block[2] = counter2; -+ s.array(block, Controller::SaveSize); -+ if(s.mode() == nall::serializer::Load) { -+ latched = (block[0] != 0); -+ counter1 = block[1]; -+ counter2 = block[2]; -+ } -+} -+ -+ - Multitap::Multitap(bool port) : Controller(port) { - latched = 0; - counter1 = 0; -diff --git a/snes/controller/multitap/multitap.hpp b/snes/controller/multitap/multitap.hpp -index 0540af7..e6324ac 100755 ---- a/snes/controller/multitap/multitap.hpp -+++ b/snes/controller/multitap/multitap.hpp -@@ -2,7 +2,7 @@ struct Multitap : Controller { - uint2 data(); - void latch(bool data); - Multitap(bool port); -- -+ void serialize(serializer& s); - private: - bool latched; - unsigned counter1; -diff --git a/snes/controller/superscope/superscope.cpp b/snes/controller/superscope/superscope.cpp -index 12068f0..1a1dfbf 100755 ---- a/snes/controller/superscope/superscope.cpp -+++ b/snes/controller/superscope/superscope.cpp -@@ -100,6 +100,37 @@ void SuperScope::latch(bool data) { - counter = 0; - } - -+void SuperScope::serialize(serializer& s) { -+ Processor::serialize(s); -+ //Save block. -+ unsigned char block[Controller::SaveSize] = {0}; -+ block[0] = latched ? 1 : 0; -+ block[1] = counter; -+ block[2] = trigger ? 1 : 0; -+ block[3] = cursor ? 1 : 0; -+ block[4] = turbo ? 1 : 0; -+ block[5] = pause ? 1 : 0; -+ block[6] = offscreen ? 1 : 0; -+ block[7] = (unsigned short)x >> 8; -+ block[8] = (unsigned short)x; -+ block[9] = (unsigned short)y >> 8; -+ block[10] = (unsigned short)y; -+ -+ s.array(block, Controller::SaveSize); -+ if(s.mode() == nall::serializer::Load) { -+ latched = (block[0] != 0); -+ counter = block[1]; -+ trigger = (block[2] != 0); -+ cursor = (block[3] != 0); -+ turbo = (block[4] != 0); -+ pause = (block[5] != 0); -+ offscreen = (block[6] != 0); -+ x = (short)(((unsigned short)block[7] << 8) | (unsigned short)block[8]); -+ y = (short)(((unsigned short)block[9] << 8) | (unsigned short)block[10]); -+ } -+} -+ -+ - SuperScope::SuperScope(bool port) : Controller(port) { - create(Controller::Enter, 21477272); - latched = 0; -diff --git a/snes/controller/superscope/superscope.hpp b/snes/controller/superscope/superscope.hpp -index a7a90b7..93509d7 100755 ---- a/snes/controller/superscope/superscope.hpp -+++ b/snes/controller/superscope/superscope.hpp -@@ -2,6 +2,7 @@ struct SuperScope : Controller { - void enter(); - uint2 data(); - void latch(bool data); -+ void serialize(serializer& s); - SuperScope(bool port); - - //private: -diff --git a/snes/system/input.cpp b/snes/system/input.cpp -index 9050310..ec5559d 100755 ---- a/snes/system/input.cpp -+++ b/snes/system/input.cpp -@@ -26,6 +26,22 @@ void Input::connect(bool port, Input::Device id) { - } - } - -+void Input::serialize(serializer &s) -+{ -+ int p1, p2; -+ p1 = (int)config.controller_port1; -+ p2 = (int)config.controller_port2; -+ s.integer(p1); -+ s.integer(p2); -+ if(s.mode() == nall::serializer::Load) { -+ connect(Controller::Port1, (Device)p1); -+ connect(Controller::Port2, (Device)p2); -+ } -+ port1->serialize(s); -+ port2->serialize(s); -+} -+ -+ - Input::Input() : port1(nullptr), port2(nullptr) { - connect(Controller::Port1, Input::Device::Joypad); - connect(Controller::Port2, Input::Device::Joypad); -diff --git a/snes/system/input.hpp b/snes/system/input.hpp -index 13ef46e..6832e82 100755 ---- a/snes/system/input.hpp -+++ b/snes/system/input.hpp -@@ -31,6 +31,7 @@ struct Input { - Controller *port1; - Controller *port2; - -+ void serialize(serializer &s); - void connect(bool port, Input::Device id); - Input(); - ~Input(); -diff --git a/snes/system/serialization.cpp b/snes/system/serialization.cpp -index f7d6f3b..08e7051 100755 ---- a/snes/system/serialization.cpp -+++ b/snes/system/serialization.cpp -@@ -56,6 +56,7 @@ void System::serialize_all(serializer &s) { - smp.serialize(s); - ppu.serialize(s); - dsp.serialize(s); -+ input.serialize(s); - - if(cartridge.mode() == Cartridge::Mode::SufamiTurbo) sufamiturbo.serialize(s); - if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.serialize(s); --- -1.7.9.48.g85da4d - diff --git a/bsnes-patches/v085/0005-Fix-unserialization-of-64-bit-signed-integers.patch b/bsnes-patches/v085/0005-Fix-unserialization-of-64-bit-signed-integers.patch deleted file mode 100644 index 8ea09b13..00000000 --- a/bsnes-patches/v085/0005-Fix-unserialization-of-64-bit-signed-integers.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 18812e5cc5bd4cdc7cc7ef87a18bce78adbb4b13 Mon Sep 17 00:00:00 2001 -From: Ilari Liusvaara -Date: Fri, 11 Nov 2011 03:05:48 +0200 -Subject: [PATCH 5/7] Fix unserialization of 64-bit signed integers - ---- - nall/serializer.hpp | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/nall/serializer.hpp b/nall/serializer.hpp -index ff2337a..e6bc8fa 100755 ---- a/nall/serializer.hpp -+++ b/nall/serializer.hpp -@@ -58,7 +58,7 @@ namespace nall { - for(unsigned n = 0; n < size; n++) idata[isize++] = value >> (n << 3); - } else if(imode == Load) { - value = 0; -- for(unsigned n = 0; n < size; n++) value |= idata[isize++] << (n << 3); -+ for(unsigned n = 0; n < size; n++) value |= (unsigned long long)idata[isize++] << (n << 3); - } else if(imode == Size) { - isize += size; - } --- -1.7.9.48.g85da4d - diff --git a/bsnes-patches/v085/0006-Allow-frontend-to-control-random-number-seed.patch b/bsnes-patches/v085/0006-Allow-frontend-to-control-random-number-seed.patch deleted file mode 100644 index ef86e42a..00000000 --- a/bsnes-patches/v085/0006-Allow-frontend-to-control-random-number-seed.patch +++ /dev/null @@ -1,53 +0,0 @@ -From efe643e986ac15028ac7c7842532d8a8fb33963b Mon Sep 17 00:00:00 2001 -From: Ilari Liusvaara -Date: Fri, 11 Nov 2011 19:49:46 +0200 -Subject: [PATCH 6/7] Allow frontend to control random number seed - ---- - snes/interface/interface.cpp | 5 +++++ - snes/interface/interface.hpp | 1 + - snes/system/system.cpp | 2 +- - 3 files changed, 7 insertions(+), 1 deletions(-) - -diff --git a/snes/interface/interface.cpp b/snes/interface/interface.cpp -index b3017c9..0a21a13 100755 ---- a/snes/interface/interface.cpp -+++ b/snes/interface/interface.cpp -@@ -23,4 +23,9 @@ time_t Interface::currentTime() - return time(0); - } - -+time_t Interface::randomSeed() -+{ -+ return time(0); -+} -+ - } -diff --git a/snes/interface/interface.hpp b/snes/interface/interface.hpp -index df975e8..30ee7fd 100755 ---- a/snes/interface/interface.hpp -+++ b/snes/interface/interface.hpp -@@ -6,6 +6,7 @@ struct Interface { - virtual string path(Cartridge::Slot slot, const string &hint) = 0; - virtual void message(const string &text); - virtual time_t currentTime(); -+ virtual time_t randomSeed(); - }; - - extern Interface *interface; -diff --git a/snes/system/system.cpp b/snes/system/system.cpp -index c19a7c5..dbd912d 100755 ---- a/snes/system/system.cpp -+++ b/snes/system/system.cpp -@@ -146,7 +146,7 @@ void System::unload() { - } - - void System::power() { -- random.seed((unsigned)time(0)); -+ random.seed((unsigned)interface->randomSeed()); - - region = config.region; - expansion = config.expansion_port; --- -1.7.9.48.g85da4d - diff --git a/bsnes-patches/v085/0007-Fix-mouse-polling.patch b/bsnes-patches/v085/0007-Fix-mouse-polling.patch deleted file mode 100644 index 02a2faa4..00000000 --- a/bsnes-patches/v085/0007-Fix-mouse-polling.patch +++ /dev/null @@ -1,60 +0,0 @@ -From ce95700dc34ffdc5370aa699992bd8275e21c5c2 Mon Sep 17 00:00:00 2001 -From: Ilari Liusvaara -Date: Wed, 7 Mar 2012 16:57:18 +0200 -Subject: [PATCH 7/7] Fix mouse polling - -Don't poll for mouse motion excessive number of times (no need to poll it for -each bit!) ---- - snes/controller/mouse/mouse.cpp | 12 ++++++++++-- - snes/controller/mouse/mouse.hpp | 2 ++ - 2 files changed, 12 insertions(+), 2 deletions(-) - -diff --git a/snes/controller/mouse/mouse.cpp b/snes/controller/mouse/mouse.cpp -index 6b26fae..824ecd3 100755 ---- a/snes/controller/mouse/mouse.cpp -+++ b/snes/controller/mouse/mouse.cpp -@@ -3,8 +3,10 @@ - uint2 Mouse::data() { - if(counter >= 32) return 1; - -- int position_x = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right -- int position_y = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down -+ if(counter == 0) { -+ position_x = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right -+ position_y = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down -+ } - - bool direction_x = position_x < 0; //0 = right, 1 = left - bool direction_y = position_y < 0; //0 = down, 1 = up -@@ -67,10 +69,16 @@ void Mouse::serialize(serializer& s) { - unsigned char block[Controller::SaveSize] = {0}; - block[0] = latched ? 1 : 0; - block[1] = counter; -+ block[2] = (unsigned short)position_x >> 8; -+ block[3] = (unsigned short)position_x; -+ block[4] = (unsigned short)position_y >> 8; -+ block[5] = (unsigned short)position_y; - s.array(block, Controller::SaveSize); - if(s.mode() == nall::serializer::Load) { - latched = (block[0] != 0); - counter = block[1]; -+ position_x = (short)(((unsigned short)block[2] << 8) | (unsigned short)block[3]); -+ position_y = (short)(((unsigned short)block[4] << 8) | (unsigned short)block[5]); - } - } - -diff --git a/snes/controller/mouse/mouse.hpp b/snes/controller/mouse/mouse.hpp -index b66ea51..6074f34 100755 ---- a/snes/controller/mouse/mouse.hpp -+++ b/snes/controller/mouse/mouse.hpp -@@ -6,4 +6,6 @@ struct Mouse : Controller { - private: - bool latched; - unsigned counter; -+ int position_x; -+ int position_y; - }; --- -1.7.9.48.g85da4d - diff --git a/bsnes-patches/v086/0001-Don-t-use-time-in-emulating-chips.patch b/bsnes-patches/v086/0001-Don-t-use-time-in-emulating-chips.patch deleted file mode 100644 index bef995f3..00000000 --- a/bsnes-patches/v086/0001-Don-t-use-time-in-emulating-chips.patch +++ /dev/null @@ -1,84 +0,0 @@ -From f66f4b9ecfcccb22b113acc6e5e92c93ed8890a9 Mon Sep 17 00:00:00 2001 -From: Ilari Liusvaara -Date: Wed, 9 Nov 2011 00:37:44 +0200 -Subject: [PATCH 1/4] Don't use time() in emulating chips - -Instead of using time() in chip emulation, create new interface method -currentTime(), defaulting to time(0). This way frontend can cleanly -override the current time bsnes is using. ---- - snes/chip/bsx/satellaview/satellaview.cpp | 2 +- - snes/chip/spc7110/spc7110.cpp | 2 +- - snes/chip/srtc/srtc.cpp | 2 +- - snes/interface/interface.cpp | 5 +++++ - snes/interface/interface.hpp | 1 + - 5 files changed, 9 insertions(+), 3 deletions(-) - -diff --git a/snes/chip/bsx/satellaview/satellaview.cpp b/snes/chip/bsx/satellaview/satellaview.cpp -index 386fb62..3c98019 100755 ---- a/snes/chip/bsx/satellaview/satellaview.cpp -+++ b/snes/chip/bsx/satellaview/satellaview.cpp -@@ -38,7 +38,7 @@ uint8 BSXSatellaview::mmio_read(unsigned addr) { - - if(counter == 0) { - time_t rawtime; -- time(&rawtime); -+ rawtime = SNES::interface->currentTime(); - tm *t = localtime(&rawtime); - - regs.r2192_hour = t->tm_hour; -diff --git a/snes/chip/spc7110/spc7110.cpp b/snes/chip/spc7110/spc7110.cpp -index d2dc640..74a817a 100755 ---- a/snes/chip/spc7110/spc7110.cpp -+++ b/snes/chip/spc7110/spc7110.cpp -@@ -101,7 +101,7 @@ void SPC7110::set_data_adjust(unsigned addr) { r4814 = addr; r4815 = addr >> 8; - - void SPC7110::update_time(int offset) { - time_t rtc_time = (rtc[16] << 0) | (rtc[17] << 8) | (rtc[18] << 16) | (rtc[19] << 24); -- time_t current_time = time(0) - offset; -+ time_t current_time = SNES::interface->currentTime() - offset; - - //sizeof(time_t) is platform-dependent; though rtc[] needs to be platform-agnostic. - //yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by -diff --git a/snes/chip/srtc/srtc.cpp b/snes/chip/srtc/srtc.cpp -index 1b2fd2a..78fc4c1 100755 ---- a/snes/chip/srtc/srtc.cpp -+++ b/snes/chip/srtc/srtc.cpp -@@ -31,7 +31,7 @@ void SRTC::reset() { - - void SRTC::update_time() { - time_t rtc_time = (rtc[16] << 0) | (rtc[17] << 8) | (rtc[18] << 16) | (rtc[19] << 24); -- time_t current_time = time(0); -+ time_t current_time = SNES::interface->currentTime(); - - //sizeof(time_t) is platform-dependent; though rtc[] needs to be platform-agnostic. - //yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by -diff --git a/snes/interface/interface.cpp b/snes/interface/interface.cpp -index a0e3a81..b3017c9 100755 ---- a/snes/interface/interface.cpp -+++ b/snes/interface/interface.cpp -@@ -18,4 +18,9 @@ void Interface::message(const string &text) { - print(text, "\n"); - } - -+time_t Interface::currentTime() -+{ -+ return time(0); -+} -+ - } -diff --git a/snes/interface/interface.hpp b/snes/interface/interface.hpp -index f1a48c0..df975e8 100755 ---- a/snes/interface/interface.hpp -+++ b/snes/interface/interface.hpp -@@ -5,6 +5,7 @@ struct Interface { - - virtual string path(Cartridge::Slot slot, const string &hint) = 0; - virtual void message(const string &text); -+ virtual time_t currentTime(); - }; - - extern Interface *interface; --- -1.7.9.48.g85da4d - diff --git a/bsnes-patches/v086/0002-Save-controller-state-when-savestating.patch b/bsnes-patches/v086/0002-Save-controller-state-when-savestating.patch deleted file mode 100644 index dfd6fb52..00000000 --- a/bsnes-patches/v086/0002-Save-controller-state-when-savestating.patch +++ /dev/null @@ -1,346 +0,0 @@ -From b02a77dd57546588a44b70bec3d6772e8ed5c11d Mon Sep 17 00:00:00 2001 -From: Ilari Liusvaara -Date: Wed, 9 Nov 2011 01:52:08 +0200 -Subject: [PATCH 2/4] Save controller state when savestating - -When savestating, save the controller state and restore it upon loadstate. -Prevents libsnes from mixing up buttons. ---- - snes/controller/controller.cpp | 8 ++++++ - snes/controller/controller.hpp | 2 + - snes/controller/gamepad/gamepad.cpp | 13 ++++++++++ - snes/controller/gamepad/gamepad.hpp | 2 +- - snes/controller/justifier/justifier.cpp | 36 +++++++++++++++++++++++++++++ - snes/controller/justifier/justifier.hpp | 1 + - snes/controller/mouse/mouse.cpp | 13 ++++++++++ - snes/controller/mouse/mouse.hpp | 2 +- - snes/controller/multitap/multitap.cpp | 16 +++++++++++++ - snes/controller/multitap/multitap.hpp | 2 +- - snes/controller/superscope/superscope.cpp | 31 +++++++++++++++++++++++++ - snes/controller/superscope/superscope.hpp | 1 + - snes/system/input.cpp | 16 +++++++++++++ - snes/system/input.hpp | 1 + - snes/system/serialization.cpp | 1 + - 15 files changed, 142 insertions(+), 3 deletions(-) - -diff --git a/snes/controller/controller.cpp b/snes/controller/controller.cpp -index 9091b21..f254bed 100755 ---- a/snes/controller/controller.cpp -+++ b/snes/controller/controller.cpp -@@ -46,8 +46,16 @@ void Controller::iobit(bool data) { - } - } - -+void Controller::serialize(serializer& s) { -+ Processor::serialize(s); -+ //Save a zero block. -+ unsigned char blockzeroes[SaveSize] = {0}; -+ s.array(blockzeroes, SaveSize); -+} -+ - Controller::Controller(bool port) : port(port) { - if(!thread) create(Controller::Enter, 1); - } - -+ - } -diff --git a/snes/controller/controller.hpp b/snes/controller/controller.hpp -index 7332712..827b2eb 100755 ---- a/snes/controller/controller.hpp -+++ b/snes/controller/controller.hpp -@@ -13,12 +13,14 @@ - - struct Controller : Processor { - enum : bool { Port1 = 0, Port2 = 1 }; -+ enum { SaveSize = 16 }; - const bool port; - - static void Enter(); - virtual void enter(); - void step(unsigned clocks); - void synchronize_cpu(); -+ virtual void serialize(serializer& s); - - bool iobit(); - void iobit(bool data); -diff --git a/snes/controller/gamepad/gamepad.cpp b/snes/controller/gamepad/gamepad.cpp -index 594020d..4fa1c99 100755 ---- a/snes/controller/gamepad/gamepad.cpp -+++ b/snes/controller/gamepad/gamepad.cpp -@@ -13,6 +13,19 @@ void Gamepad::latch(bool data) { - counter = 0; - } - -+void Gamepad::serialize(serializer& s) { -+ Processor::serialize(s); -+ //Save block. -+ unsigned char block[Controller::SaveSize] = {0}; -+ block[0] = latched ? 1 : 0; -+ block[1] = counter; -+ s.array(block, Controller::SaveSize); -+ if(s.mode() == nall::serializer::Load) { -+ latched = (block[0] != 0); -+ counter = block[1]; -+ } -+} -+ - Gamepad::Gamepad(bool port) : Controller(port) { - latched = 0; - counter = 0; -diff --git a/snes/controller/gamepad/gamepad.hpp b/snes/controller/gamepad/gamepad.hpp -index c5ca69c..a2392d1 100755 ---- a/snes/controller/gamepad/gamepad.hpp -+++ b/snes/controller/gamepad/gamepad.hpp -@@ -2,7 +2,7 @@ struct Gamepad : Controller { - uint2 data(); - void latch(bool data); - Gamepad(bool port); -- -+ void serialize(serializer& s); - private: - bool latched; - unsigned counter; -diff --git a/snes/controller/justifier/justifier.cpp b/snes/controller/justifier/justifier.cpp -index 6207916..ad13a9b 100755 ---- a/snes/controller/justifier/justifier.cpp -+++ b/snes/controller/justifier/justifier.cpp -@@ -100,6 +100,42 @@ void Justifier::latch(bool data) { - if(latched == 0) active = !active; //toggle between both controllers, even when unchained - } - -+void Justifier::serialize(serializer& s) { -+ Processor::serialize(s); -+ //Save block. -+ unsigned char block[Controller::SaveSize] = {0}; -+ block[0] = latched ? 1 : 0; -+ block[1] = counter; -+ block[2] = active ? 1 : 0; -+ block[3] = player1.trigger ? 1 : 0; -+ block[4] = player2.trigger ? 1 : 0; -+ block[5] = player1.start ? 1 : 0; -+ block[6] = player2.start ? 1 : 0; -+ block[7] = (unsigned short)player1.x >> 8; -+ block[8] = (unsigned short)player1.x; -+ block[9] = (unsigned short)player2.x >> 8; -+ block[10] = (unsigned short)player2.x; -+ block[11] = (unsigned short)player1.y >> 8; -+ block[12] = (unsigned short)player1.y; -+ block[13] = (unsigned short)player2.y >> 8; -+ block[14] = (unsigned short)player2.y; -+ s.array(block, Controller::SaveSize); -+ if(s.mode() == nall::serializer::Load) { -+ latched = (block[0] != 0); -+ counter = block[1]; -+ active = (block[2] != 0); -+ player1.trigger = (block[3] != 0); -+ player2.trigger = (block[4] != 0); -+ player1.start = (block[5] != 0); -+ player2.start = (block[6] != 0); -+ player1.x = (short)(((unsigned short)block[7] << 8) | (unsigned short)block[8]); -+ player2.x = (short)(((unsigned short)block[9] << 8) | (unsigned short)block[10]); -+ player1.y = (short)(((unsigned short)block[11] << 8) | (unsigned short)block[12]); -+ player2.y = (short)(((unsigned short)block[13] << 8) | (unsigned short)block[14]); -+ } -+} -+ -+ - Justifier::Justifier(bool port, bool chained) : Controller(port), chained(chained) { - create(Controller::Enter, 21477272); - latched = 0; -diff --git a/snes/controller/justifier/justifier.hpp b/snes/controller/justifier/justifier.hpp -index f927acf..6b7bba0 100755 ---- a/snes/controller/justifier/justifier.hpp -+++ b/snes/controller/justifier/justifier.hpp -@@ -2,6 +2,7 @@ struct Justifier : Controller { - void enter(); - uint2 data(); - void latch(bool data); -+ void serialize(serializer& s); - Justifier(bool port, bool chained); - - //private: -diff --git a/snes/controller/mouse/mouse.cpp b/snes/controller/mouse/mouse.cpp -index c9f5d16..6b26fae 100755 ---- a/snes/controller/mouse/mouse.cpp -+++ b/snes/controller/mouse/mouse.cpp -@@ -61,6 +61,19 @@ void Mouse::latch(bool data) { - counter = 0; - } - -+void Mouse::serialize(serializer& s) { -+ Processor::serialize(s); -+ //Save block. -+ unsigned char block[Controller::SaveSize] = {0}; -+ block[0] = latched ? 1 : 0; -+ block[1] = counter; -+ s.array(block, Controller::SaveSize); -+ if(s.mode() == nall::serializer::Load) { -+ latched = (block[0] != 0); -+ counter = block[1]; -+ } -+} -+ - Mouse::Mouse(bool port) : Controller(port) { - latched = 0; - counter = 0; -diff --git a/snes/controller/mouse/mouse.hpp b/snes/controller/mouse/mouse.hpp -index 95e24b6..b66ea51 100755 ---- a/snes/controller/mouse/mouse.hpp -+++ b/snes/controller/mouse/mouse.hpp -@@ -2,7 +2,7 @@ struct Mouse : Controller { - uint2 data(); - void latch(bool data); - Mouse(bool port); -- -+ void serialize(serializer& s); - private: - bool latched; - unsigned counter; -diff --git a/snes/controller/multitap/multitap.cpp b/snes/controller/multitap/multitap.cpp -index 3a6eb72..146c41d 100755 ---- a/snes/controller/multitap/multitap.cpp -+++ b/snes/controller/multitap/multitap.cpp -@@ -30,6 +30,22 @@ void Multitap::latch(bool data) { - counter2 = 0; - } - -+void Multitap::serialize(serializer& s) { -+ Processor::serialize(s); -+ //Save block. -+ unsigned char block[Controller::SaveSize] = {0}; -+ block[0] = latched ? 1 : 0; -+ block[1] = counter1; -+ block[2] = counter2; -+ s.array(block, Controller::SaveSize); -+ if(s.mode() == nall::serializer::Load) { -+ latched = (block[0] != 0); -+ counter1 = block[1]; -+ counter2 = block[2]; -+ } -+} -+ -+ - Multitap::Multitap(bool port) : Controller(port) { - latched = 0; - counter1 = 0; -diff --git a/snes/controller/multitap/multitap.hpp b/snes/controller/multitap/multitap.hpp -index 0540af7..e6324ac 100755 ---- a/snes/controller/multitap/multitap.hpp -+++ b/snes/controller/multitap/multitap.hpp -@@ -2,7 +2,7 @@ struct Multitap : Controller { - uint2 data(); - void latch(bool data); - Multitap(bool port); -- -+ void serialize(serializer& s); - private: - bool latched; - unsigned counter1; -diff --git a/snes/controller/superscope/superscope.cpp b/snes/controller/superscope/superscope.cpp -index 12068f0..1a1dfbf 100755 ---- a/snes/controller/superscope/superscope.cpp -+++ b/snes/controller/superscope/superscope.cpp -@@ -100,6 +100,37 @@ void SuperScope::latch(bool data) { - counter = 0; - } - -+void SuperScope::serialize(serializer& s) { -+ Processor::serialize(s); -+ //Save block. -+ unsigned char block[Controller::SaveSize] = {0}; -+ block[0] = latched ? 1 : 0; -+ block[1] = counter; -+ block[2] = trigger ? 1 : 0; -+ block[3] = cursor ? 1 : 0; -+ block[4] = turbo ? 1 : 0; -+ block[5] = pause ? 1 : 0; -+ block[6] = offscreen ? 1 : 0; -+ block[7] = (unsigned short)x >> 8; -+ block[8] = (unsigned short)x; -+ block[9] = (unsigned short)y >> 8; -+ block[10] = (unsigned short)y; -+ -+ s.array(block, Controller::SaveSize); -+ if(s.mode() == nall::serializer::Load) { -+ latched = (block[0] != 0); -+ counter = block[1]; -+ trigger = (block[2] != 0); -+ cursor = (block[3] != 0); -+ turbo = (block[4] != 0); -+ pause = (block[5] != 0); -+ offscreen = (block[6] != 0); -+ x = (short)(((unsigned short)block[7] << 8) | (unsigned short)block[8]); -+ y = (short)(((unsigned short)block[9] << 8) | (unsigned short)block[10]); -+ } -+} -+ -+ - SuperScope::SuperScope(bool port) : Controller(port) { - create(Controller::Enter, 21477272); - latched = 0; -diff --git a/snes/controller/superscope/superscope.hpp b/snes/controller/superscope/superscope.hpp -index a7a90b7..93509d7 100755 ---- a/snes/controller/superscope/superscope.hpp -+++ b/snes/controller/superscope/superscope.hpp -@@ -2,6 +2,7 @@ struct SuperScope : Controller { - void enter(); - uint2 data(); - void latch(bool data); -+ void serialize(serializer& s); - SuperScope(bool port); - - //private: -diff --git a/snes/system/input.cpp b/snes/system/input.cpp -index 9050310..ec5559d 100755 ---- a/snes/system/input.cpp -+++ b/snes/system/input.cpp -@@ -26,6 +26,22 @@ void Input::connect(bool port, Input::Device id) { - } - } - -+void Input::serialize(serializer &s) -+{ -+ int p1, p2; -+ p1 = (int)config.controller_port1; -+ p2 = (int)config.controller_port2; -+ s.integer(p1); -+ s.integer(p2); -+ if(s.mode() == nall::serializer::Load) { -+ connect(Controller::Port1, (Device)p1); -+ connect(Controller::Port2, (Device)p2); -+ } -+ port1->serialize(s); -+ port2->serialize(s); -+} -+ -+ - Input::Input() : port1(nullptr), port2(nullptr) { - connect(Controller::Port1, Input::Device::Joypad); - connect(Controller::Port2, Input::Device::Joypad); -diff --git a/snes/system/input.hpp b/snes/system/input.hpp -index 13ef46e..6832e82 100755 ---- a/snes/system/input.hpp -+++ b/snes/system/input.hpp -@@ -31,6 +31,7 @@ struct Input { - Controller *port1; - Controller *port2; - -+ void serialize(serializer &s); - void connect(bool port, Input::Device id); - Input(); - ~Input(); -diff --git a/snes/system/serialization.cpp b/snes/system/serialization.cpp -index 9f5273d..005e731 100755 ---- a/snes/system/serialization.cpp -+++ b/snes/system/serialization.cpp -@@ -56,6 +56,7 @@ void System::serialize_all(serializer &s) { - smp.serialize(s); - ppu.serialize(s); - dsp.serialize(s); -+ input.serialize(s); - - if(cartridge.mode() == Cartridge::Mode::SufamiTurbo) sufamiturbo.serialize(s); - #if defined(GAMEBOY) --- -1.7.9.48.g85da4d - diff --git a/bsnes-patches/v086/0003-Allow-frontend-to-control-random-number-seed.patch b/bsnes-patches/v086/0003-Allow-frontend-to-control-random-number-seed.patch deleted file mode 100644 index 018b7c9b..00000000 --- a/bsnes-patches/v086/0003-Allow-frontend-to-control-random-number-seed.patch +++ /dev/null @@ -1,53 +0,0 @@ -From a47431385fedf705a3c9c1b820c116c230632943 Mon Sep 17 00:00:00 2001 -From: Ilari Liusvaara -Date: Fri, 11 Nov 2011 19:49:46 +0200 -Subject: [PATCH 3/4] Allow frontend to control random number seed - ---- - snes/interface/interface.cpp | 5 +++++ - snes/interface/interface.hpp | 1 + - snes/system/system.cpp | 2 +- - 3 files changed, 7 insertions(+), 1 deletions(-) - -diff --git a/snes/interface/interface.cpp b/snes/interface/interface.cpp -index b3017c9..0a21a13 100755 ---- a/snes/interface/interface.cpp -+++ b/snes/interface/interface.cpp -@@ -23,4 +23,9 @@ time_t Interface::currentTime() - return time(0); - } - -+time_t Interface::randomSeed() -+{ -+ return time(0); -+} -+ - } -diff --git a/snes/interface/interface.hpp b/snes/interface/interface.hpp -index df975e8..30ee7fd 100755 ---- a/snes/interface/interface.hpp -+++ b/snes/interface/interface.hpp -@@ -6,6 +6,7 @@ struct Interface { - virtual string path(Cartridge::Slot slot, const string &hint) = 0; - virtual void message(const string &text); - virtual time_t currentTime(); -+ virtual time_t randomSeed(); - }; - - extern Interface *interface; -diff --git a/snes/system/system.cpp b/snes/system/system.cpp -index 284e389..99901ff 100755 ---- a/snes/system/system.cpp -+++ b/snes/system/system.cpp -@@ -151,7 +151,7 @@ void System::unload() { - } - - void System::power() { -- random.seed((unsigned)time(0)); -+ random.seed((unsigned)interface->randomSeed()); - - region = config.region; - expansion = config.expansion_port; --- -1.7.9.48.g85da4d - diff --git a/bsnes-patches/v086/0004-Fix-mouse-polling.patch b/bsnes-patches/v086/0004-Fix-mouse-polling.patch deleted file mode 100644 index 7484c29c..00000000 --- a/bsnes-patches/v086/0004-Fix-mouse-polling.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 395130ad02c50c329c0290b675086ff104839943 Mon Sep 17 00:00:00 2001 -From: Ilari Liusvaara -Date: Wed, 7 Mar 2012 16:57:18 +0200 -Subject: [PATCH 4/4] Fix mouse polling - -Don't poll for mouse motion excessive number of times (no need to poll it for -each bit!) ---- - snes/controller/mouse/mouse.cpp | 12 ++++++++++-- - snes/controller/mouse/mouse.hpp | 2 ++ - 2 files changed, 12 insertions(+), 2 deletions(-) - -diff --git a/snes/controller/mouse/mouse.cpp b/snes/controller/mouse/mouse.cpp -index 6b26fae..824ecd3 100755 ---- a/snes/controller/mouse/mouse.cpp -+++ b/snes/controller/mouse/mouse.cpp -@@ -3,8 +3,10 @@ - uint2 Mouse::data() { - if(counter >= 32) return 1; - -- int position_x = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right -- int position_y = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down -+ if(counter == 0) { -+ position_x = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right -+ position_y = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down -+ } - - bool direction_x = position_x < 0; //0 = right, 1 = left - bool direction_y = position_y < 0; //0 = down, 1 = up -@@ -67,10 +69,16 @@ void Mouse::serialize(serializer& s) { - unsigned char block[Controller::SaveSize] = {0}; - block[0] = latched ? 1 : 0; - block[1] = counter; -+ block[2] = (unsigned short)position_x >> 8; -+ block[3] = (unsigned short)position_x; -+ block[4] = (unsigned short)position_y >> 8; -+ block[5] = (unsigned short)position_y; - s.array(block, Controller::SaveSize); - if(s.mode() == nall::serializer::Load) { - latched = (block[0] != 0); - counter = block[1]; -+ position_x = (short)(((unsigned short)block[2] << 8) | (unsigned short)block[3]); -+ position_y = (short)(((unsigned short)block[4] << 8) | (unsigned short)block[5]); - } - } - -diff --git a/snes/controller/mouse/mouse.hpp b/snes/controller/mouse/mouse.hpp -index b66ea51..6074f34 100755 ---- a/snes/controller/mouse/mouse.hpp -+++ b/snes/controller/mouse/mouse.hpp -@@ -6,4 +6,6 @@ struct Mouse : Controller { - private: - bool latched; - unsigned counter; -+ int position_x; -+ int position_y; - }; --- -1.7.9.48.g85da4d - diff --git a/bsnes-patches/v087/0001-Don-t-use-time-in-emulating-chips.patch b/bsnes-patches/v087/0001-Don-t-use-time-in-emulating-chips.patch deleted file mode 100644 index 115ef5d9..00000000 --- a/bsnes-patches/v087/0001-Don-t-use-time-in-emulating-chips.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 22205d4d339cfa11f6d53e644eae1c859a56d349 Mon Sep 17 00:00:00 2001 -From: Ilari Liusvaara -Date: Wed, 9 Nov 2011 00:37:44 +0200 -Subject: [PATCH 1/4] Don't use time() in emulating chips - -Instead of using time() in chip emulation, create new interface method -currentTime(), defaulting to time(0). This way frontend can cleanly -override the current time bsnes is using. ---- - snes/chip/bsx/satellaview/satellaview.cpp | 2 +- - snes/chip/spc7110/spc7110.cpp | 2 +- - snes/chip/srtc/srtc.cpp | 2 +- - snes/interface/interface.cpp | 5 +++++ - snes/interface/interface.hpp | 1 + - 5 files changed, 9 insertions(+), 3 deletions(-) - -diff --git a/snes/chip/bsx/satellaview/satellaview.cpp b/snes/chip/bsx/satellaview/satellaview.cpp -index 386fb62..3c98019 100755 ---- a/snes/chip/bsx/satellaview/satellaview.cpp -+++ b/snes/chip/bsx/satellaview/satellaview.cpp -@@ -38,7 +38,7 @@ uint8 BSXSatellaview::mmio_read(unsigned addr) { - - if(counter == 0) { - time_t rawtime; -- time(&rawtime); -+ rawtime = SNES::interface->currentTime(); - tm *t = localtime(&rawtime); - - regs.r2192_hour = t->tm_hour; -diff --git a/snes/chip/spc7110/spc7110.cpp b/snes/chip/spc7110/spc7110.cpp -index 27b8b77..061aa5e 100755 ---- a/snes/chip/spc7110/spc7110.cpp -+++ b/snes/chip/spc7110/spc7110.cpp -@@ -101,7 +101,7 @@ void SPC7110::set_data_adjust(unsigned addr) { r4814 = addr; r4815 = addr >> 8; - - void SPC7110::update_time(int offset) { - time_t rtc_time = (rtc[16] << 0) | (rtc[17] << 8) | (rtc[18] << 16) | (rtc[19] << 24); -- time_t current_time = time(0) - offset; -+ time_t current_time = SNES::interface->currentTime() - offset; - - //sizeof(time_t) is platform-dependent; though rtc[] needs to be platform-agnostic. - //yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by -diff --git a/snes/chip/srtc/srtc.cpp b/snes/chip/srtc/srtc.cpp -index 0044113..725e891 100755 ---- a/snes/chip/srtc/srtc.cpp -+++ b/snes/chip/srtc/srtc.cpp -@@ -31,7 +31,7 @@ void SRTC::reset() { - - void SRTC::update_time() { - time_t rtc_time = (rtc[16] << 0) | (rtc[17] << 8) | (rtc[18] << 16) | (rtc[19] << 24); -- time_t current_time = time(0); -+ time_t current_time = SNES::interface->currentTime(); - - //sizeof(time_t) is platform-dependent; though rtc[] needs to be platform-agnostic. - //yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by -diff --git a/snes/interface/interface.cpp b/snes/interface/interface.cpp -index a0e3a81..b3017c9 100755 ---- a/snes/interface/interface.cpp -+++ b/snes/interface/interface.cpp -@@ -18,4 +18,9 @@ void Interface::message(const string &text) { - print(text, "\n"); - } - -+time_t Interface::currentTime() -+{ -+ return time(0); -+} -+ - } -diff --git a/snes/interface/interface.hpp b/snes/interface/interface.hpp -index f1a48c0..df975e8 100755 ---- a/snes/interface/interface.hpp -+++ b/snes/interface/interface.hpp -@@ -5,6 +5,7 @@ struct Interface { - - virtual string path(Cartridge::Slot slot, const string &hint) = 0; - virtual void message(const string &text); -+ virtual time_t currentTime(); - }; - - extern Interface *interface; --- -1.7.9.48.g85da4d - diff --git a/bsnes-patches/v087/0002-Save-controller-state-when-savestating.patch b/bsnes-patches/v087/0002-Save-controller-state-when-savestating.patch deleted file mode 100644 index 61207d86..00000000 --- a/bsnes-patches/v087/0002-Save-controller-state-when-savestating.patch +++ /dev/null @@ -1,346 +0,0 @@ -From fe11984ad18561506a7cc874cb7c0421f1e21ad1 Mon Sep 17 00:00:00 2001 -From: Ilari Liusvaara -Date: Wed, 9 Nov 2011 01:52:08 +0200 -Subject: [PATCH 2/4] Save controller state when savestating - -When savestating, save the controller state and restore it upon loadstate. -Prevents libsnes from mixing up buttons. ---- - snes/controller/controller.cpp | 8 ++++++ - snes/controller/controller.hpp | 2 + - snes/controller/gamepad/gamepad.cpp | 13 ++++++++++ - snes/controller/gamepad/gamepad.hpp | 2 +- - snes/controller/justifier/justifier.cpp | 36 +++++++++++++++++++++++++++++ - snes/controller/justifier/justifier.hpp | 1 + - snes/controller/mouse/mouse.cpp | 13 ++++++++++ - snes/controller/mouse/mouse.hpp | 2 +- - snes/controller/multitap/multitap.cpp | 16 +++++++++++++ - snes/controller/multitap/multitap.hpp | 2 +- - snes/controller/superscope/superscope.cpp | 31 +++++++++++++++++++++++++ - snes/controller/superscope/superscope.hpp | 1 + - snes/system/input.cpp | 16 +++++++++++++ - snes/system/input.hpp | 1 + - snes/system/serialization.cpp | 1 + - 15 files changed, 142 insertions(+), 3 deletions(-) - -diff --git a/snes/controller/controller.cpp b/snes/controller/controller.cpp -index fa8e07d..5f37849 100755 ---- a/snes/controller/controller.cpp -+++ b/snes/controller/controller.cpp -@@ -46,8 +46,16 @@ void Controller::iobit(bool data) { - } - } - -+void Controller::serialize(serializer& s) { -+ Processor::serialize(s); -+ //Save a zero block. -+ unsigned char blockzeroes[SaveSize] = {0}; -+ s.array(blockzeroes, SaveSize); -+} -+ - Controller::Controller(bool port) : port(port) { - if(!thread) create(Controller::Enter, 1); - } - -+ - } -diff --git a/snes/controller/controller.hpp b/snes/controller/controller.hpp -index dd748a1..46095a8 100755 ---- a/snes/controller/controller.hpp -+++ b/snes/controller/controller.hpp -@@ -13,12 +13,14 @@ - - struct Controller : Processor { - enum : bool { Port1 = 0, Port2 = 1 }; -+ enum { SaveSize = 16 }; - const bool port; - - static void Enter(); - virtual void enter(); - void step(unsigned clocks); - void synchronize_cpu(); -+ virtual void serialize(serializer& s); - - bool iobit(); - void iobit(bool data); -diff --git a/snes/controller/gamepad/gamepad.cpp b/snes/controller/gamepad/gamepad.cpp -index 594020d..4fa1c99 100755 ---- a/snes/controller/gamepad/gamepad.cpp -+++ b/snes/controller/gamepad/gamepad.cpp -@@ -13,6 +13,19 @@ void Gamepad::latch(bool data) { - counter = 0; - } - -+void Gamepad::serialize(serializer& s) { -+ Processor::serialize(s); -+ //Save block. -+ unsigned char block[Controller::SaveSize] = {0}; -+ block[0] = latched ? 1 : 0; -+ block[1] = counter; -+ s.array(block, Controller::SaveSize); -+ if(s.mode() == nall::serializer::Load) { -+ latched = (block[0] != 0); -+ counter = block[1]; -+ } -+} -+ - Gamepad::Gamepad(bool port) : Controller(port) { - latched = 0; - counter = 0; -diff --git a/snes/controller/gamepad/gamepad.hpp b/snes/controller/gamepad/gamepad.hpp -index c5ca69c..a2392d1 100755 ---- a/snes/controller/gamepad/gamepad.hpp -+++ b/snes/controller/gamepad/gamepad.hpp -@@ -2,7 +2,7 @@ struct Gamepad : Controller { - uint2 data(); - void latch(bool data); - Gamepad(bool port); -- -+ void serialize(serializer& s); - private: - bool latched; - unsigned counter; -diff --git a/snes/controller/justifier/justifier.cpp b/snes/controller/justifier/justifier.cpp -index 6207916..ad13a9b 100755 ---- a/snes/controller/justifier/justifier.cpp -+++ b/snes/controller/justifier/justifier.cpp -@@ -100,6 +100,42 @@ void Justifier::latch(bool data) { - if(latched == 0) active = !active; //toggle between both controllers, even when unchained - } - -+void Justifier::serialize(serializer& s) { -+ Processor::serialize(s); -+ //Save block. -+ unsigned char block[Controller::SaveSize] = {0}; -+ block[0] = latched ? 1 : 0; -+ block[1] = counter; -+ block[2] = active ? 1 : 0; -+ block[3] = player1.trigger ? 1 : 0; -+ block[4] = player2.trigger ? 1 : 0; -+ block[5] = player1.start ? 1 : 0; -+ block[6] = player2.start ? 1 : 0; -+ block[7] = (unsigned short)player1.x >> 8; -+ block[8] = (unsigned short)player1.x; -+ block[9] = (unsigned short)player2.x >> 8; -+ block[10] = (unsigned short)player2.x; -+ block[11] = (unsigned short)player1.y >> 8; -+ block[12] = (unsigned short)player1.y; -+ block[13] = (unsigned short)player2.y >> 8; -+ block[14] = (unsigned short)player2.y; -+ s.array(block, Controller::SaveSize); -+ if(s.mode() == nall::serializer::Load) { -+ latched = (block[0] != 0); -+ counter = block[1]; -+ active = (block[2] != 0); -+ player1.trigger = (block[3] != 0); -+ player2.trigger = (block[4] != 0); -+ player1.start = (block[5] != 0); -+ player2.start = (block[6] != 0); -+ player1.x = (short)(((unsigned short)block[7] << 8) | (unsigned short)block[8]); -+ player2.x = (short)(((unsigned short)block[9] << 8) | (unsigned short)block[10]); -+ player1.y = (short)(((unsigned short)block[11] << 8) | (unsigned short)block[12]); -+ player2.y = (short)(((unsigned short)block[13] << 8) | (unsigned short)block[14]); -+ } -+} -+ -+ - Justifier::Justifier(bool port, bool chained) : Controller(port), chained(chained) { - create(Controller::Enter, 21477272); - latched = 0; -diff --git a/snes/controller/justifier/justifier.hpp b/snes/controller/justifier/justifier.hpp -index f927acf..6b7bba0 100755 ---- a/snes/controller/justifier/justifier.hpp -+++ b/snes/controller/justifier/justifier.hpp -@@ -2,6 +2,7 @@ struct Justifier : Controller { - void enter(); - uint2 data(); - void latch(bool data); -+ void serialize(serializer& s); - Justifier(bool port, bool chained); - - //private: -diff --git a/snes/controller/mouse/mouse.cpp b/snes/controller/mouse/mouse.cpp -index c9f5d16..6b26fae 100755 ---- a/snes/controller/mouse/mouse.cpp -+++ b/snes/controller/mouse/mouse.cpp -@@ -61,6 +61,19 @@ void Mouse::latch(bool data) { - counter = 0; - } - -+void Mouse::serialize(serializer& s) { -+ Processor::serialize(s); -+ //Save block. -+ unsigned char block[Controller::SaveSize] = {0}; -+ block[0] = latched ? 1 : 0; -+ block[1] = counter; -+ s.array(block, Controller::SaveSize); -+ if(s.mode() == nall::serializer::Load) { -+ latched = (block[0] != 0); -+ counter = block[1]; -+ } -+} -+ - Mouse::Mouse(bool port) : Controller(port) { - latched = 0; - counter = 0; -diff --git a/snes/controller/mouse/mouse.hpp b/snes/controller/mouse/mouse.hpp -index 95e24b6..b66ea51 100755 ---- a/snes/controller/mouse/mouse.hpp -+++ b/snes/controller/mouse/mouse.hpp -@@ -2,7 +2,7 @@ struct Mouse : Controller { - uint2 data(); - void latch(bool data); - Mouse(bool port); -- -+ void serialize(serializer& s); - private: - bool latched; - unsigned counter; -diff --git a/snes/controller/multitap/multitap.cpp b/snes/controller/multitap/multitap.cpp -index 3a6eb72..146c41d 100755 ---- a/snes/controller/multitap/multitap.cpp -+++ b/snes/controller/multitap/multitap.cpp -@@ -30,6 +30,22 @@ void Multitap::latch(bool data) { - counter2 = 0; - } - -+void Multitap::serialize(serializer& s) { -+ Processor::serialize(s); -+ //Save block. -+ unsigned char block[Controller::SaveSize] = {0}; -+ block[0] = latched ? 1 : 0; -+ block[1] = counter1; -+ block[2] = counter2; -+ s.array(block, Controller::SaveSize); -+ if(s.mode() == nall::serializer::Load) { -+ latched = (block[0] != 0); -+ counter1 = block[1]; -+ counter2 = block[2]; -+ } -+} -+ -+ - Multitap::Multitap(bool port) : Controller(port) { - latched = 0; - counter1 = 0; -diff --git a/snes/controller/multitap/multitap.hpp b/snes/controller/multitap/multitap.hpp -index 0540af7..e6324ac 100755 ---- a/snes/controller/multitap/multitap.hpp -+++ b/snes/controller/multitap/multitap.hpp -@@ -2,7 +2,7 @@ struct Multitap : Controller { - uint2 data(); - void latch(bool data); - Multitap(bool port); -- -+ void serialize(serializer& s); - private: - bool latched; - unsigned counter1; -diff --git a/snes/controller/superscope/superscope.cpp b/snes/controller/superscope/superscope.cpp -index 12068f0..1a1dfbf 100755 ---- a/snes/controller/superscope/superscope.cpp -+++ b/snes/controller/superscope/superscope.cpp -@@ -100,6 +100,37 @@ void SuperScope::latch(bool data) { - counter = 0; - } - -+void SuperScope::serialize(serializer& s) { -+ Processor::serialize(s); -+ //Save block. -+ unsigned char block[Controller::SaveSize] = {0}; -+ block[0] = latched ? 1 : 0; -+ block[1] = counter; -+ block[2] = trigger ? 1 : 0; -+ block[3] = cursor ? 1 : 0; -+ block[4] = turbo ? 1 : 0; -+ block[5] = pause ? 1 : 0; -+ block[6] = offscreen ? 1 : 0; -+ block[7] = (unsigned short)x >> 8; -+ block[8] = (unsigned short)x; -+ block[9] = (unsigned short)y >> 8; -+ block[10] = (unsigned short)y; -+ -+ s.array(block, Controller::SaveSize); -+ if(s.mode() == nall::serializer::Load) { -+ latched = (block[0] != 0); -+ counter = block[1]; -+ trigger = (block[2] != 0); -+ cursor = (block[3] != 0); -+ turbo = (block[4] != 0); -+ pause = (block[5] != 0); -+ offscreen = (block[6] != 0); -+ x = (short)(((unsigned short)block[7] << 8) | (unsigned short)block[8]); -+ y = (short)(((unsigned short)block[9] << 8) | (unsigned short)block[10]); -+ } -+} -+ -+ - SuperScope::SuperScope(bool port) : Controller(port) { - create(Controller::Enter, 21477272); - latched = 0; -diff --git a/snes/controller/superscope/superscope.hpp b/snes/controller/superscope/superscope.hpp -index a7a90b7..93509d7 100755 ---- a/snes/controller/superscope/superscope.hpp -+++ b/snes/controller/superscope/superscope.hpp -@@ -2,6 +2,7 @@ struct SuperScope : Controller { - void enter(); - uint2 data(); - void latch(bool data); -+ void serialize(serializer& s); - SuperScope(bool port); - - //private: -diff --git a/snes/system/input.cpp b/snes/system/input.cpp -index 894de0e..4479acc 100755 ---- a/snes/system/input.cpp -+++ b/snes/system/input.cpp -@@ -26,6 +26,22 @@ void Input::connect(bool port, Input::Device id) { - } - } - -+void Input::serialize(serializer &s) -+{ -+ int p1, p2; -+ p1 = (int)config.controller_port1; -+ p2 = (int)config.controller_port2; -+ s.integer(p1); -+ s.integer(p2); -+ if(s.mode() == nall::serializer::Load) { -+ connect(Controller::Port1, (Device)p1); -+ connect(Controller::Port2, (Device)p2); -+ } -+ port1->serialize(s); -+ port2->serialize(s); -+} -+ -+ - Input::Input() : port1(nullptr), port2(nullptr) { - connect(Controller::Port1, Input::Device::Joypad); - connect(Controller::Port2, Input::Device::Joypad); -diff --git a/snes/system/input.hpp b/snes/system/input.hpp -index 7a6bd9e..d2f5fef 100755 ---- a/snes/system/input.hpp -+++ b/snes/system/input.hpp -@@ -31,6 +31,7 @@ struct Input { - Controller *port1; - Controller *port2; - -+ void serialize(serializer &s); - void connect(bool port, Input::Device id); - Input(); - ~Input(); -diff --git a/snes/system/serialization.cpp b/snes/system/serialization.cpp -index f746c3a..67e08a2 100755 ---- a/snes/system/serialization.cpp -+++ b/snes/system/serialization.cpp -@@ -56,6 +56,7 @@ void System::serialize_all(serializer &s) { - smp.serialize(s); - ppu.serialize(s); - dsp.serialize(s); -+ input.serialize(s); - - if(cartridge.mode() == Cartridge::Mode::SufamiTurbo) sufamiturbo.serialize(s); - #if defined(GAMEBOY) --- -1.7.9.48.g85da4d - diff --git a/bsnes-patches/v087/0003-Allow-frontend-to-control-random-number-seed.patch b/bsnes-patches/v087/0003-Allow-frontend-to-control-random-number-seed.patch deleted file mode 100644 index b0f5ad17..00000000 --- a/bsnes-patches/v087/0003-Allow-frontend-to-control-random-number-seed.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 5f76449a70c9a546e18c2fdebe7588bbe90b56d2 Mon Sep 17 00:00:00 2001 -From: Ilari Liusvaara -Date: Fri, 11 Nov 2011 19:49:46 +0200 -Subject: [PATCH 3/4] Allow frontend to control random number seed - ---- - snes/interface/interface.cpp | 5 +++++ - snes/interface/interface.hpp | 1 + - snes/system/system.cpp | 2 +- - 3 files changed, 7 insertions(+), 1 deletions(-) - -diff --git a/snes/interface/interface.cpp b/snes/interface/interface.cpp -index b3017c9..0a21a13 100755 ---- a/snes/interface/interface.cpp -+++ b/snes/interface/interface.cpp -@@ -23,4 +23,9 @@ time_t Interface::currentTime() - return time(0); - } - -+time_t Interface::randomSeed() -+{ -+ return time(0); -+} -+ - } -diff --git a/snes/interface/interface.hpp b/snes/interface/interface.hpp -index df975e8..30ee7fd 100755 ---- a/snes/interface/interface.hpp -+++ b/snes/interface/interface.hpp -@@ -6,6 +6,7 @@ struct Interface { - virtual string path(Cartridge::Slot slot, const string &hint) = 0; - virtual void message(const string &text); - virtual time_t currentTime(); -+ virtual time_t randomSeed(); - }; - - extern Interface *interface; -diff --git a/snes/system/system.cpp b/snes/system/system.cpp -index 9b70bbf..cbd096c 100755 ---- a/snes/system/system.cpp -+++ b/snes/system/system.cpp -@@ -151,7 +151,7 @@ void System::unload() { - } - - void System::power() { -- random.seed((unsigned)time(0)); -+ random.seed((unsigned)interface->randomSeed()); - - region = config.region; - expansion = config.expansion_port; --- -1.7.9.48.g85da4d - diff --git a/bsnes-patches/v087/0004-Fix-mouse-polling.patch b/bsnes-patches/v087/0004-Fix-mouse-polling.patch deleted file mode 100644 index 5de1f170..00000000 --- a/bsnes-patches/v087/0004-Fix-mouse-polling.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 160dedf35571478781737ee35307b9321cfb41bb Mon Sep 17 00:00:00 2001 -From: Ilari Liusvaara -Date: Wed, 7 Mar 2012 16:57:18 +0200 -Subject: [PATCH 4/4] Fix mouse polling - -Don't poll for mouse motion excessive number of times (no need to poll it for -each bit!) ---- - snes/controller/mouse/mouse.cpp | 12 ++++++++++-- - snes/controller/mouse/mouse.hpp | 2 ++ - 2 files changed, 12 insertions(+), 2 deletions(-) - -diff --git a/snes/controller/mouse/mouse.cpp b/snes/controller/mouse/mouse.cpp -index 6b26fae..824ecd3 100755 ---- a/snes/controller/mouse/mouse.cpp -+++ b/snes/controller/mouse/mouse.cpp -@@ -3,8 +3,10 @@ - uint2 Mouse::data() { - if(counter >= 32) return 1; - -- int position_x = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right -- int position_y = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down -+ if(counter == 0) { -+ position_x = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right -+ position_y = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down -+ } - - bool direction_x = position_x < 0; //0 = right, 1 = left - bool direction_y = position_y < 0; //0 = down, 1 = up -@@ -67,10 +69,16 @@ void Mouse::serialize(serializer& s) { - unsigned char block[Controller::SaveSize] = {0}; - block[0] = latched ? 1 : 0; - block[1] = counter; -+ block[2] = (unsigned short)position_x >> 8; -+ block[3] = (unsigned short)position_x; -+ block[4] = (unsigned short)position_y >> 8; -+ block[5] = (unsigned short)position_y; - s.array(block, Controller::SaveSize); - if(s.mode() == nall::serializer::Load) { - latched = (block[0] != 0); - counter = block[1]; -+ position_x = (short)(((unsigned short)block[2] << 8) | (unsigned short)block[3]); -+ position_y = (short)(((unsigned short)block[4] << 8) | (unsigned short)block[5]); - } - } - -diff --git a/snes/controller/mouse/mouse.hpp b/snes/controller/mouse/mouse.hpp -index b66ea51..6074f34 100755 ---- a/snes/controller/mouse/mouse.hpp -+++ b/snes/controller/mouse/mouse.hpp -@@ -6,4 +6,6 @@ struct Mouse : Controller { - private: - bool latched; - unsigned counter; -+ int position_x; -+ int position_y; - }; --- -1.7.9.48.g85da4d - diff --git a/libgambatte-patches/svn320/0001-Changes-to-make-libgambatte-rerecording-friendly.patch b/libgambatte-patches/svn320/0001-Changes-to-make-libgambatte-rerecording-friendly.patch new file mode 100644 index 00000000..380d5cbf --- /dev/null +++ b/libgambatte-patches/svn320/0001-Changes-to-make-libgambatte-rerecording-friendly.patch @@ -0,0 +1,5970 @@ +From ae85d61305e367d7c657bc664c5a4e5638604377 Mon Sep 17 00:00:00 2001 +From: Ilari Liusvaara +Date: Thu, 12 Jul 2012 20:49:57 +0300 +Subject: [PATCH] Changes to make libgambatte rerecording-friendly + +--- + Makefile | 10 + + libgambatte/Makefile | 18 ++ + libgambatte/include/gambatte.h | 65 ++++++- + libgambatte/src/bitmap_font.cpp | 10 +- + libgambatte/src/bitmap_font.h | 6 +- + libgambatte/src/cpu.cpp | 45 ++++- + libgambatte/src/cpu.h | 31 +++- + libgambatte/src/file/file.cpp | 34 ++++ + libgambatte/src/file/file.h | 10 + + libgambatte/src/gambatte.cpp | 124 ++++++++++-- + libgambatte/src/initstate.cpp | 8 +- + libgambatte/src/initstate.h | 8 +- + libgambatte/src/interrupter.cpp | 17 ++- + libgambatte/src/interrupter.h | 18 ++- + libgambatte/src/interruptrequester.cpp | 23 ++- + libgambatte/src/interruptrequester.h | 27 ++- + libgambatte/src/loadsave.cpp | 266 ++++++++++++++++++++++++++ + libgambatte/src/loadsave.h | 160 ++++++++++++++++ + libgambatte/src/mem/cartridge.cpp | 155 +++++++++++++-- + libgambatte/src/mem/cartridge.h | 36 +++- + libgambatte/src/mem/memptrs.cpp | 32 +++- + libgambatte/src/mem/memptrs.h | 11 +- + libgambatte/src/mem/rtc.cpp | 57 +++++- + libgambatte/src/mem/rtc.h | 11 +- + libgambatte/src/memory.cpp | 110 +++++++---- + libgambatte/src/memory.h | 80 +++++--- + libgambatte/src/minkeeper.h | 30 ++- + libgambatte/src/savestate.h | 54 +++--- + libgambatte/src/sound.cpp | 36 +++- + libgambatte/src/sound.h | 17 ++- + libgambatte/src/sound/channel1.cpp | 44 ++++- + libgambatte/src/sound/channel1.h | 24 ++- + libgambatte/src/sound/channel2.cpp | 41 +++- + libgambatte/src/sound/channel2.h | 17 ++- + libgambatte/src/sound/channel3.cpp | 41 +++- + libgambatte/src/sound/channel3.h | 27 ++- + libgambatte/src/sound/channel4.cpp | 59 ++++-- + libgambatte/src/sound/channel4.h | 39 +++-- + libgambatte/src/sound/duty_unit.cpp | 34 +++- + libgambatte/src/sound/duty_unit.h | 29 ++- + libgambatte/src/sound/envelope_unit.cpp | 19 ++- + libgambatte/src/sound/envelope_unit.h | 12 +- + libgambatte/src/sound/length_counter.cpp | 19 ++- + libgambatte/src/sound/length_counter.h | 13 +- + libgambatte/src/sound/sound_unit.h | 15 ++- + libgambatte/src/sound/static_output_tester.h | 8 +- + libgambatte/src/state_osd_elements.cpp | 8 +- + libgambatte/src/statesaver.cpp | 111 +++++++---- + libgambatte/src/statesaver.h | 7 + + libgambatte/src/tima.cpp | 35 +++- + libgambatte/src/tima.h | 28 ++- + libgambatte/src/video.cpp | 120 +++++++----- + libgambatte/src/video.h | 118 +++++++----- + libgambatte/src/video/ly_counter.cpp | 14 +- + libgambatte/src/video/ly_counter.h | 26 ++- + libgambatte/src/video/lyc_irq.cpp | 14 +- + libgambatte/src/video/lyc_irq.h | 27 ++- + libgambatte/src/video/next_m0_time.h | 10 + + libgambatte/src/video/ppu.cpp | 123 +++++++++--- + libgambatte/src/video/ppu.h | 84 ++++++--- + libgambatte/src/video/sprite_mapper.cpp | 17 +- + libgambatte/src/video/sprite_mapper.h | 53 ++++-- + 62 files changed, 2142 insertions(+), 603 deletions(-) + create mode 100644 Makefile + create mode 100644 libgambatte/Makefile + create mode 100644 libgambatte/src/loadsave.cpp + create mode 100644 libgambatte/src/loadsave.h + +diff --git a/Makefile b/Makefile +new file mode 100644 +index 0000000..2714a5b +--- /dev/null ++++ b/Makefile +@@ -0,0 +1,10 @@ ++all: libgambatte/__all_files__ ++ ++libgambatte/__all_files__: forcelook ++ $(MAKE) -C libgambatte ++ ++clean: forcelook ++ $(MAKE) -C libgambatte clean ++ ++forcelook: ++ @true +diff --git a/libgambatte/Makefile b/libgambatte/Makefile +new file mode 100644 +index 0000000..7c3724e +--- /dev/null ++++ b/libgambatte/Makefile +@@ -0,0 +1,18 @@ ++all: libgambatte.$(ARCHIVE_SUFFIX) ++ ++REALAR=$(CROSS_PREFIX)ar ++ ++OBJECTS=$(patsubst %.cpp,%.$(OBJECT_SUFFIX),$(wildcard src/*.cpp src/video/*.cpp src/mem/*.cpp src/sound/*.cpp src/file/file.cpp)) ++ ++%.o: %.cpp ++ $(gambatte_compiler) $(CFLAGS) -Wno-deprecated-declarations -DHAVE_CSTDINT -I../common -Iinclude -Isrc -c -o $@ $< ++ ++libgambatte.$(ARCHIVE_SUFFIX): $(OBJECTS) ++ $(REALAR) crvs $@ $^ ++ $(REALRANLIB) $@ ++ ++clean: forcelook ++ rm -f $(OBJECTS) libgambatte.$(ARCHIVE_SUFFIX) ++ ++forcelook: ++ @true +\ No newline at end of file +diff --git a/libgambatte/include/gambatte.h b/libgambatte/include/gambatte.h +index b13e4be..8406a3c 100644 +--- a/libgambatte/include/gambatte.h ++++ b/libgambatte/include/gambatte.h +@@ -22,6 +22,11 @@ + #include "inputgetter.h" + #include "gbint.h" + #include ++#include ++ ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. + + namespace gambatte { + enum { BG_PALETTE = 0, SP1_PALETTE = 1, SP2_PALETTE = 2 }; +@@ -44,7 +49,15 @@ public: + * @return 0 on success, negative value on failure. + */ + int load(const std::string &romfile, unsigned flags = 0); +- ++ /** Load ROM image. ++ * ++ * @param image Raw ROM image data. ++ * @param isize Size of raw ROM image data. ++ * @param flags ORed combination of LoadFlags. ++ * @return 0 on success, negative value on failure. ++ */ ++ int load(const unsigned char* image, size_t isize, unsigned flags = 0); ++ + /** Emulates until at least 'samples' stereo sound samples are produced in the supplied buffer, + * or until a video frame has been drawn. + * +@@ -66,7 +79,7 @@ public: + * @param samples in: number of stereo samples to produce, out: actual number of samples produced + * @return sample number at which the video frame was produced. -1 means no frame was produced. + */ +- long runFor(gambatte::uint_least32_t *videoBuf, int pitch, ++ signed runFor(gambatte::uint_least32_t *videoBuf, int pitch, + gambatte::uint_least32_t *soundBuf, unsigned &samples); + + /** Reset to initial state. +@@ -113,7 +126,18 @@ public: + /** Loads emulator state from the file given by 'filepath'. + */ + void loadState(const std::string &filepath); +- ++ ++ /** Save savestate to given buffer. ++ */ ++ void saveState(std::vector& data, const std::vector& cmpdata); ++ /** Save savestate to given buffer. ++ */ ++ void saveState(std::vector& data); ++ /** Load savestate from given buffer. ++ */ ++ void loadState(const std::vector& data); ++ ++ + /** Selects which state slot to save state to or load state from. + * There are 10 such slots, numbered from 0 to 9 (periodically extended for all n). + */ +@@ -134,10 +158,43 @@ public: + * @param codes Game Shark codes in format 01HHHHHH;01HHHHHH;... where H is [0-9]|[A-F] + */ + void setGameShark(const std::string &codes); +- ++ ++ /** Set RTC base time. ++ */ ++ void setRtcBase(time_t time); ++ ++ /** Get RTC base time. ++ */ ++ time_t getRtcBase(); ++ ++ /** Get pointer and size to Work RAM. ++ * @return The pointer and size of Work RAM. ++ */ ++ std::pair getWorkRam(); ++ ++ /** Get pointer and size to Save RAM. ++ * @return The pointer and size of Save RAM. ++ */ ++ std::pair getSaveRam(); ++ ++ /** Get pointer and size to I/O RAM. ++ * @return The pointer and size of I/O RAM. ++ */ ++ std::pair getIoRam(); ++ ++ /** Get pointer and size to Video RAM. ++ * @return The pointer and size of Video RAM. ++ */ ++ std::pair getVideoRam(); ++ ++ /** Function to get wall time. */ ++ void set_walltime_fn(time_t (*_walltime)()); + private: ++ void preload_common(); ++ void postload_common(const unsigned flags); + struct Priv; + Priv *const p_; ++ time_t (*walltime)(); + + void loadState(const std::string &filepath, bool osdMessage); + GB(const GB &); +diff --git a/libgambatte/src/bitmap_font.cpp b/libgambatte/src/bitmap_font.cpp +index 7ef835f..0e40bc4 100644 +--- a/libgambatte/src/bitmap_font.cpp ++++ b/libgambatte/src/bitmap_font.cpp +@@ -68,6 +68,10 @@ + gnome dot org. + */ + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + #include "bitmap_font.h" + + static const unsigned char n0_bits[] = { 0x68, +@@ -285,10 +289,10 @@ unsigned getWidth(const char *chars) { + + namespace { + class Rgb32Fill { +- const unsigned long color; ++ const uint_least32_t color; + + public: +- explicit Rgb32Fill(unsigned long color) : color(color) {} ++ explicit Rgb32Fill(uint_least32_t color) : color(color) {} + + void operator()(gambatte::uint_least32_t *dest, unsigned /*pitch*/) const { + *dest = color; +@@ -296,7 +300,7 @@ public: + }; + } + +-void print(gambatte::uint_least32_t *dest, const unsigned pitch, const unsigned long color, const char *chars) { ++void print(gambatte::uint_least32_t *dest, const unsigned pitch, const uint_least32_t color, const char *chars) { + print(dest, pitch, Rgb32Fill(color), chars); + } + +diff --git a/libgambatte/src/bitmap_font.h b/libgambatte/src/bitmap_font.h +index 35b29fa..34e3f6b 100644 +--- a/libgambatte/src/bitmap_font.h ++++ b/libgambatte/src/bitmap_font.h +@@ -19,6 +19,10 @@ + #ifndef BITMAP_FONT_H + #define BITMAP_FONT_H + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + #include "gbint.h" + + namespace bitmapfont { +@@ -42,7 +46,7 @@ unsigned getWidth(const char *chars); + template + void print(RandomAccessIterator dest, unsigned pitch, Fill fill, const char *chars); + +-void print(gambatte::uint_least32_t *dest, unsigned pitch, unsigned long color, const char *chars); ++void print(gambatte::uint_least32_t *dest, unsigned pitch, uint_least32_t color, const char *chars); + void utoa(unsigned u, char *a); + + // --- INTERFACE END --- +diff --git a/libgambatte/src/cpu.cpp b/libgambatte/src/cpu.cpp +index 2b19eeb..9c63ddb 100644 +--- a/libgambatte/src/cpu.cpp ++++ b/libgambatte/src/cpu.cpp +@@ -20,10 +20,14 @@ + #include "memory.h" + #include "savestate.h" + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + namespace gambatte { + +-CPU::CPU() +-: memory(Interrupter(SP, PC_)), ++CPU::CPU(time_t (**_getCurrentTime)()) ++: memory(Interrupter(SP, PC_), _getCurrentTime), + cycleCounter_(0), + PC_(0x100), + SP(0xFFFE), +@@ -42,10 +46,10 @@ CPU::CPU() + { + } + +-long CPU::runFor(const unsigned long cycles) { ++signed CPU::runFor(const unsigned cycles) { + process(cycles/* << memory.isDoubleSpeed()*/); + +- const long csb = memory.cyclesSinceBlit(cycleCounter_); ++ const signed csb = memory.cyclesSinceBlit(cycleCounter_); + + if (cycleCounter_ & 0x80000000) + cycleCounter_ = memory.resetCounters(cycleCounter_); +@@ -124,6 +128,27 @@ void CPU::loadState(const SaveState &state) { + skip = state.cpu.skip; + } + ++void CPU::loadOrSave(loadsave& state) ++{ ++ memory.loadOrSave(state); ++ state(cycleCounter_); ++ state(PC_); ++ state(SP); ++ state(HF1); ++ state(HF2); ++ state(ZF); ++ state(CF); ++ state(A_); ++ state(B); ++ state(C); ++ state(D); ++ state(E); ++ state(H); ++ state(L); ++ state(skip); ++} ++ ++ + #define BC() ( B << 8 | C ) + #define DE() ( D << 8 | E ) + #define HL() ( H << 8 | L ) +@@ -503,18 +528,18 @@ void CPU::loadState(const SaveState &state) { + PC_MOD(ret_var_h << 8 | ret_var_l); \ + } while (0) + +-void CPU::process(const unsigned long cycles) { ++void CPU::process(const unsigned cycles) { + memory.setEndtime(cycleCounter_, cycles); + + unsigned char A = A_; +- unsigned long cycleCounter = cycleCounter_; ++ unsigned cycleCounter = cycleCounter_; + + while (memory.isActive()) { + unsigned short PC = PC_; +- ++ + if (memory.halted()) { + if (cycleCounter < memory.nextEventTime()) { +- const unsigned long cycles = memory.nextEventTime() - cycleCounter; ++ const unsigned cycles = memory.nextEventTime() - cycleCounter; + cycleCounter += cycles + (-cycles & 3); + } + } else while (cycleCounter < memory.nextEventTime()) { +@@ -612,7 +637,7 @@ void CPU::process(const unsigned long cycles) { + cycleCounter = memory.stop(cycleCounter); + + if (cycleCounter < memory.nextEventTime()) { +- const unsigned long cycles = memory.nextEventTime() - cycleCounter; ++ const unsigned cycles = memory.nextEventTime() - cycleCounter; + cycleCounter += cycles + (-cycles & 3); + } + +@@ -1140,7 +1165,7 @@ void CPU::process(const unsigned long cycles) { + memory.halt(); + + if (cycleCounter < memory.nextEventTime()) { +- const unsigned long cycles = memory.nextEventTime() - cycleCounter; ++ const unsigned cycles = memory.nextEventTime() - cycleCounter; + cycleCounter += cycles + (-cycles & 3); + } + } +diff --git a/libgambatte/src/cpu.h b/libgambatte/src/cpu.h +index 238e639..98f25c6 100644 +--- a/libgambatte/src/cpu.h ++++ b/libgambatte/src/cpu.h +@@ -19,14 +19,19 @@ + #ifndef CPU_H + #define CPU_H + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + #include "memory.h" ++#include "loadsave.h" + + namespace gambatte { + + class CPU { + Memory memory; + +- unsigned long cycleCounter_; ++ unsigned cycleCounter_; + + unsigned short PC_; + unsigned short SP; +@@ -37,20 +42,22 @@ class CPU { + + bool skip; + +- void process(unsigned long cycles); ++ void process(unsigned cycles); + + public: + +- CPU(); ++ CPU(time_t (**_getCurrentTime)()); + // void halt(); + + // unsigned interrupt(unsigned address, unsigned cycleCounter); + +- long runFor(unsigned long cycles); ++ signed runFor(unsigned cycles); + void setStatePtrs(SaveState &state); + void saveState(SaveState &state); + void loadState(const SaveState &state); +- ++ ++ void loadOrSave(loadsave& state); ++ + void loadSavedata() { memory.loadSavedata(); } + void saveSavedata() { memory.saveSavedata(); } + +@@ -77,7 +84,11 @@ public: + int load(const std::string &romfile, bool forceDmg, bool multicartCompat) { + return memory.loadROM(romfile, forceDmg, multicartCompat); + } +- ++ ++ int load(const unsigned char* image, size_t isize, bool forceDmg, bool multicartCompat) { ++ return memory.loadROM(image, isize, forceDmg, multicartCompat); ++ } ++ + bool loaded() const { return memory.loaded(); } + const char * romTitle() const { return memory.romTitle(); } + +@@ -92,6 +103,14 @@ public: + + void setGameGenie(const std::string &codes) { memory.setGameGenie(codes); } + void setGameShark(const std::string &codes) { memory.setGameShark(codes); } ++ ++ void setRtcBase(time_t time) { memory.setRtcBase(time); } ++ time_t getRtcBase() { return memory.getRtcBase(); } ++ std::pair getWorkRam() { return memory.getWorkRam(); } ++ std::pair getSaveRam() { return memory.getSaveRam(); } ++ std::pair getIoRam() { return memory.getIoRam(); } ++ std::pair getVideoRam() { return memory.getVideoRam(); }; ++ + }; + + } +diff --git a/libgambatte/src/file/file.cpp b/libgambatte/src/file/file.cpp +index fff66d2..5b5739e 100644 +--- a/libgambatte/src/file/file.cpp ++++ b/libgambatte/src/file/file.cpp +@@ -20,7 +20,41 @@ Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + ***************************************************************************/ + #include "stdfile.h" ++#include ++ ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. + + std::auto_ptr gambatte::newFileInstance(const std::string &filepath) { + return std::auto_ptr(new StdFile(filepath.c_str())); + } ++ ++namespace ++{ ++ struct MemoryFile : public gambatte::File ++ { ++ MemoryFile(const unsigned char* image, size_t isize) : buf(image), bufsize(isize), ++ ptr(0), xfail(false) {} ++ ~MemoryFile() {} ++ void rewind() { ptr = 0; xfail = false; } ++ std::size_t size() const { return bufsize; } ++ void read(char *buffer, std::size_t amount) { ++ if(amount > bufsize - ptr) { ++ memcpy(buffer, buf, bufsize - ptr); ++ xfail = true; ++ } else ++ memcpy(buffer, buf, amount); ++ } ++ bool fail() const { return xfail; } ++ private: ++ const unsigned char* buf; ++ size_t bufsize; ++ size_t ptr; ++ bool xfail; ++ }; ++} ++ ++std::auto_ptr gambatte::newFileInstance(const unsigned char* image, size_t isize) { ++ return std::auto_ptr(new MemoryFile(image, isize)); ++} +diff --git a/libgambatte/src/file/file.h b/libgambatte/src/file/file.h +index 23b23c0..1a95543 100644 +--- a/libgambatte/src/file/file.h ++++ b/libgambatte/src/file/file.h +@@ -22,9 +22,18 @@ Free Software Foundation, Inc., + #ifndef GAMBATTE_FILE_H + #define GAMBATTE_FILE_H + ++ ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + #include + #include + ++// ++// Modified 2012-07-10 by H. Ilari Liusvaara ++// - New API methods. ++ + namespace gambatte { + + class File { +@@ -37,6 +46,7 @@ public: + }; + + std::auto_ptr newFileInstance(const std::string &filepath); ++std::auto_ptr newFileInstance(const unsigned char* image, size_t isize); + + } + +diff --git a/libgambatte/src/gambatte.cpp b/libgambatte/src/gambatte.cpp +index d33b3f2..c6248b7 100644 +--- a/libgambatte/src/gambatte.cpp ++++ b/libgambatte/src/gambatte.cpp +@@ -25,6 +25,10 @@ + #include + #include + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + static const std::string itos(const int i) { + std::stringstream ss; + ss << i; +@@ -35,16 +39,24 @@ static const std::string statePath(const std::string &basePath, const int stateN + return basePath + "_" + itos(stateNo) + ".gqs"; + } + ++namespace ++{ ++ time_t default_walltime() ++ { ++ return time(0); ++ } ++} ++ + namespace gambatte { + struct GB::Priv { + CPU cpu; + int stateNo; + bool gbaCgbMode; + +- Priv() : stateNo(1), gbaCgbMode(false) {} ++ Priv(time_t (**_getCurrentTime)()) : stateNo(1), gbaCgbMode(false), cpu(_getCurrentTime) {} + }; + +-GB::GB() : p_(new Priv) {} ++GB::GB() : p_(new Priv(&walltime)), walltime(default_walltime) {} + + GB::~GB() { + if (p_->cpu.loaded()) +@@ -53,7 +65,7 @@ GB::~GB() { + delete p_; + } + +-long GB::runFor(gambatte::uint_least32_t *const videoBuf, const int pitch, ++signed GB::runFor(gambatte::uint_least32_t *const videoBuf, const int pitch, + gambatte::uint_least32_t *const soundBuf, unsigned &samples) { + if (!p_->cpu.loaded()) { + samples = 0; +@@ -62,10 +74,10 @@ long GB::runFor(gambatte::uint_least32_t *const videoBuf, const int pitch, + + p_->cpu.setVideoBuffer(videoBuf, pitch); + p_->cpu.setSoundBuffer(soundBuf); +- const long cyclesSinceBlit = p_->cpu.runFor(samples * 2); ++ const signed cyclesSinceBlit = p_->cpu.runFor(samples * 2); + samples = p_->cpu.fillSoundBuffer(); + +- return cyclesSinceBlit < 0 ? cyclesSinceBlit : static_cast(samples) - (cyclesSinceBlit >> 1); ++ return cyclesSinceBlit < 0 ? cyclesSinceBlit : static_cast(samples) - (cyclesSinceBlit >> 1); + } + + void GB::reset() { +@@ -74,7 +86,7 @@ void GB::reset() { + + SaveState state; + p_->cpu.setStatePtrs(state); +- setInitState(state, p_->cpu.isCgb(), p_->gbaCgbMode); ++ setInitState(state, p_->cpu.isCgb(), p_->gbaCgbMode, walltime()); + p_->cpu.loadState(state); + p_->cpu.loadSavedata(); + } +@@ -88,23 +100,43 @@ void GB::setSaveDir(const std::string &sdir) { + p_->cpu.setSaveDir(sdir); + } + +-int GB::load(const std::string &romfile, const unsigned flags) { ++void GB::preload_common() ++{ + if (p_->cpu.loaded()) + p_->cpu.saveSavedata(); +- ++} ++ ++void GB::postload_common(const unsigned flags) ++{ ++ SaveState state; ++ p_->cpu.setStatePtrs(state); ++ setInitState(state, p_->cpu.isCgb(), p_->gbaCgbMode = flags & GBA_CGB, walltime()); ++ p_->cpu.loadState(state); ++ p_->cpu.loadSavedata(); ++ ++ p_->stateNo = 1; ++ p_->cpu.setOsdElement(std::auto_ptr()); ++} ++ ++int GB::load(const std::string &romfile, const unsigned flags) { ++ preload_common(); ++ + const int failed = p_->cpu.load(romfile, flags & FORCE_DMG, flags & MULTICART_COMPAT); +- +- if (!failed) { +- SaveState state; +- p_->cpu.setStatePtrs(state); +- setInitState(state, p_->cpu.isCgb(), p_->gbaCgbMode = flags & GBA_CGB); +- p_->cpu.loadState(state); +- p_->cpu.loadSavedata(); +- +- p_->stateNo = 1; +- p_->cpu.setOsdElement(std::auto_ptr()); +- } +- ++ ++ if (!failed) ++ postload_common(flags); ++ ++ return failed; ++} ++ ++int GB::load(const unsigned char* image, size_t isize, unsigned flags) { ++ preload_common(); ++ ++ const int failed = p_->cpu.load(image, isize, flags & FORCE_DMG, flags & MULTICART_COMPAT); ++ ++ if (!failed) ++ postload_common(flags); ++ + return failed; + } + +@@ -160,6 +192,29 @@ void GB::loadState(const std::string &filepath) { + loadState(filepath, false); + } + ++void GB::saveState(std::vector& data, const std::vector& cmpdata) { ++ if (p_->cpu.loaded()) { ++ loadsave_save l(cmpdata); ++ p_->cpu.loadOrSave(l); ++ data = l.get(); ++ } ++} ++ ++void GB::saveState(std::vector& data) { ++ if (p_->cpu.loaded()) { ++ loadsave_save l; ++ p_->cpu.loadOrSave(l); ++ data = l.get(); ++ } ++} ++ ++void GB::loadState(const std::vector& data) { ++ if (p_->cpu.loaded()) { ++ loadsave_load l(data); ++ p_->cpu.loadOrSave(l); ++ } ++} ++ + void GB::selectState(int n) { + n -= (n / 10) * 10; + p_->stateNo = n < 0 ? n + 10 : n; +@@ -189,4 +244,33 @@ void GB::setGameShark(const std::string &codes) { + p_->cpu.setGameShark(codes); + } + ++void GB::setRtcBase(time_t time) { ++ p_->cpu.setRtcBase(time); ++} ++ ++time_t GB::getRtcBase() { ++ return p_->cpu.getRtcBase(); ++} ++ ++std::pair GB::getWorkRam() { ++ return p_->cpu.getWorkRam(); ++} ++ ++std::pair GB::getSaveRam() { ++ return p_->cpu.getSaveRam(); ++} ++ ++std::pair GB::getIoRam() { ++ return p_->cpu.getIoRam(); ++} ++ ++std::pair GB::getVideoRam() { ++ return p_->cpu.getVideoRam(); ++} ++ ++void GB::set_walltime_fn(time_t (*_walltime)()) ++{ ++ walltime = _walltime; ++} ++ + } +diff --git a/libgambatte/src/initstate.cpp b/libgambatte/src/initstate.cpp +index 0d61e66..fdad344 100644 +--- a/libgambatte/src/initstate.cpp ++++ b/libgambatte/src/initstate.cpp +@@ -24,6 +24,10 @@ + #include + #include + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + namespace { + + static void setInitialCgbWram(unsigned char *const wram) { +@@ -1147,7 +1151,7 @@ static void setInitialDmgIoamhram(unsigned char *const ioamhram) { + + } // anon namespace + +-void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbMode) { ++void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbMode, time_t starttime) { + static const unsigned char cgbObjpDump[0x40] = { + 0x00, 0x00, 0xF2, 0xAB, + 0x61, 0xC2, 0xD9, 0xBA, +@@ -1308,7 +1312,7 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM + state.spu.ch4.nr4 = 0; + state.spu.ch4.master = false; + +- state.rtc.baseTime = std::time(0); ++ state.rtc.baseTime = starttime; + state.rtc.haltTime = state.rtc.baseTime; + state.rtc.dataDh = 0; + state.rtc.dataDl = 0; +diff --git a/libgambatte/src/initstate.h b/libgambatte/src/initstate.h +index 0aba307..171b6d0 100644 +--- a/libgambatte/src/initstate.h ++++ b/libgambatte/src/initstate.h +@@ -19,8 +19,14 @@ + #ifndef INITSTATE_H + #define INITSTATE_H + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ ++#include ++ + namespace gambatte { +-void setInitState(struct SaveState &state, bool cgb, bool gbaCgbMode); ++void setInitState(struct SaveState &state, bool cgb, bool gbaCgbMode, time_t starttime); + } + + #endif +diff --git a/libgambatte/src/interrupter.cpp b/libgambatte/src/interrupter.cpp +index 66db0c7..230bdc2 100644 +--- a/libgambatte/src/interrupter.cpp ++++ b/libgambatte/src/interrupter.cpp +@@ -19,6 +19,10 @@ + #include "interrupter.h" + #include "memory.h" + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + namespace gambatte { + + Interrupter::Interrupter(unsigned short &SP_in, unsigned short &PC_in) : +@@ -26,7 +30,7 @@ Interrupter::Interrupter(unsigned short &SP_in, unsigned short &PC_in) : + PC(PC_in) + {} + +-unsigned long Interrupter::interrupt(const unsigned address, unsigned long cycleCounter, Memory &memory) { ++unsigned Interrupter::interrupt(const unsigned address, unsigned cycleCounter, Memory &memory) { + cycleCounter += 8; + SP = (SP - 1) & 0xFFFF; + memory.write(SP, PC >> 8, cycleCounter); +@@ -61,11 +65,20 @@ void Interrupter::setGameShark(const std::string &codes) { + } + } + +-void Interrupter::applyVblankCheats(const unsigned long cycleCounter, Memory &memory) { ++void Interrupter::applyVblankCheats(const unsigned cycleCounter, Memory &memory) { + for (std::size_t i = 0, size = gsCodes.size(); i < size; ++i) { + if (gsCodes[i].type == 0x01) + memory.write(gsCodes[i].address, gsCodes[i].value, cycleCounter); + } + } + ++void Interrupter::loadOrSave(loadsave& state) { ++ unsigned gssize = gsCodes.size(); ++ state(gssize); ++ if(!state.saving()) ++ gsCodes.resize(gssize); ++ for(unsigned i = 0; i < gssize; i++) ++ gsCodes[i].loadOrSave(state); ++} ++ + } +diff --git a/libgambatte/src/interrupter.h b/libgambatte/src/interrupter.h +index d8f2f10..e0619e3 100644 +--- a/libgambatte/src/interrupter.h ++++ b/libgambatte/src/interrupter.h +@@ -19,8 +19,14 @@ + #ifndef INTERRUPTER_H + #define INTERRUPTER_H + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + #include + #include ++#include "loadsave.h" ++ + + namespace gambatte { + +@@ -28,6 +34,12 @@ struct GsCode { + unsigned short address; + unsigned char value; + unsigned char type; ++ ++ void loadOrSave(loadsave& state) { ++ state(address); ++ state(value); ++ state(type); ++ } + }; + + class Interrupter { +@@ -35,11 +47,13 @@ class Interrupter { + unsigned short &PC; + std::vector gsCodes; + +- void applyVblankCheats(unsigned long cc, class Memory &mem); ++ void applyVblankCheats(unsigned cc, class Memory &mem); + public: + Interrupter(unsigned short &SP, unsigned short &PC); +- unsigned long interrupt(const unsigned address, unsigned long cycleCounter, class Memory &memory); ++ unsigned interrupt(const unsigned address, unsigned cycleCounter, class Memory &memory); + void setGameShark(const std::string &codes); ++ ++ void loadOrSave(loadsave& state); + }; + + } +diff --git a/libgambatte/src/interruptrequester.cpp b/libgambatte/src/interruptrequester.cpp +index 914f617..f63c0a1 100644 +--- a/libgambatte/src/interruptrequester.cpp ++++ b/libgambatte/src/interruptrequester.cpp +@@ -19,6 +19,10 @@ + #include "interruptrequester.h" + #include "savestate.h" + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + namespace gambatte { + + InterruptRequester::InterruptRequester() : minIntTime(0), ifreg_(0), iereg_(0) {} +@@ -35,17 +39,26 @@ void InterruptRequester::loadState(const SaveState &state) { + iereg_ = state.mem.ioamhram.get()[0x1FF] & 0x1F; + intFlags.set(state.mem.IME, state.mem.halted); + +- eventTimes.setValue(intFlags.imeOrHalted() && pendingIrqs() ? minIntTime : static_cast(DISABLED_TIME)); ++ eventTimes.setValue(intFlags.imeOrHalted() && pendingIrqs() ? minIntTime : static_cast(DISABLED_TIME)); ++} ++ ++void InterruptRequester::loadOrSave(loadsave& state) ++{ ++ eventTimes.loadOrSave(state); ++ state(minIntTime); ++ state(ifreg_); ++ state(iereg_); ++ intFlags.loadOrSave(state); + } + +-void InterruptRequester::resetCc(const unsigned long oldCc, const unsigned long newCc) { ++void InterruptRequester::resetCc(const unsigned oldCc, const unsigned newCc) { + minIntTime = minIntTime < oldCc ? 0 : minIntTime - (oldCc - newCc); + + if (eventTimes.value(INTERRUPTS) != DISABLED_TIME) + eventTimes.setValue(minIntTime); + } + +-void InterruptRequester::ei(const unsigned long cc) { ++void InterruptRequester::ei(const unsigned cc) { + intFlags.setIme(); + minIntTime = cc + 1; + +@@ -90,14 +103,14 @@ void InterruptRequester::setIereg(const unsigned iereg) { + iereg_ = iereg & 0x1F; + + if (intFlags.imeOrHalted()) +- eventTimes.setValue(pendingIrqs() ? minIntTime : static_cast(DISABLED_TIME)); ++ eventTimes.setValue(pendingIrqs() ? minIntTime : static_cast(DISABLED_TIME)); + } + + void InterruptRequester::setIfreg(const unsigned ifreg) { + ifreg_ = ifreg; + + if (intFlags.imeOrHalted()) +- eventTimes.setValue(pendingIrqs() ? minIntTime : static_cast(DISABLED_TIME)); ++ eventTimes.setValue(pendingIrqs() ? minIntTime : static_cast(DISABLED_TIME)); + } + + } +diff --git a/libgambatte/src/interruptrequester.h b/libgambatte/src/interruptrequester.h +index 78c9d3f..61326fb 100644 +--- a/libgambatte/src/interruptrequester.h ++++ b/libgambatte/src/interruptrequester.h +@@ -19,8 +19,13 @@ + #ifndef INTERRUPT_REQUESTER_H + #define INTERRUPT_REQUESTER_H + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + #include "counterdef.h" + #include "minkeeper.h" ++#include "loadsave.h" + + namespace gambatte { + struct SaveState; +@@ -28,7 +33,7 @@ enum MemEventId { UNHALT, END, BLIT, SERIAL, OAM, DMA, TIMA, VIDEO, INTERRUPTS } + + class InterruptRequester { + MinKeeper eventTimes; +- unsigned long minIntTime; ++ unsigned minIntTime; + unsigned ifreg_; + unsigned iereg_; + +@@ -38,7 +43,9 @@ class InterruptRequester { + + public: + IntFlags() : flags_(0) {} +- ++ ++ void loadOrSave(loadsave& state) { state(flags_); } ++ + bool ime() const { return flags_ & IME_MASK; } + bool halted() const { return flags_ & HALTED_MASK; } + bool imeOrHalted() const { return flags_; } +@@ -57,15 +64,17 @@ public: + + void saveState(SaveState &) const; + void loadState(const SaveState &); +- +- void resetCc(unsigned long oldCc, unsigned long newCc); ++ ++ void loadOrSave(loadsave& state); ++ ++ void resetCc(unsigned oldCc, unsigned newCc); + + unsigned ifreg() const { return ifreg_; } + unsigned pendingIrqs() const { return ifreg_ & iereg_; } + bool ime() const { return intFlags.ime(); } + bool halted() const { return intFlags.halted(); } + +- void ei(unsigned long cc); ++ void ei(unsigned cc); + void di(); + void halt(); + void unhalt(); +@@ -75,10 +84,10 @@ public: + void setIfreg(unsigned ifreg); + + MemEventId minEventId() const { return static_cast(eventTimes.min()); } +- unsigned long minEventTime() const { return eventTimes.minValue(); } +- template void setEventTime(unsigned long value) { eventTimes.setValue(value); } +- void setEventTime(const MemEventId id, unsigned long value) { eventTimes.setValue(id, value); } +- unsigned long eventTime(MemEventId id) const { return eventTimes.value(id); } ++ unsigned minEventTime() const { return eventTimes.minValue(); } ++ template void setEventTime(unsigned value) { eventTimes.setValue(value); } ++ void setEventTime(const MemEventId id, unsigned value) { eventTimes.setValue(id, value); } ++ unsigned eventTime(MemEventId id) const { return eventTimes.value(id); } + }; + + inline void flagHdmaReq(InterruptRequester *const intreq) { intreq->setEventTime(0); } +diff --git a/libgambatte/src/loadsave.cpp b/libgambatte/src/loadsave.cpp +new file mode 100644 +index 0000000..37ea71a +--- /dev/null ++++ b/libgambatte/src/loadsave.cpp +@@ -0,0 +1,266 @@ ++/*************************************************************************** ++ * Copyright (C) 2012 by H. Ilari Liusvaara * ++ * ilari.liusvaara@elisanet.fi * ++ * * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License version 2 as * ++ * published by the Free Software Foundation. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License version 2 for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * version 2 along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ ***************************************************************************/ ++#include "loadsave.h" ++#include ++#include ++#include ++ ++namespace gambatte { ++ ++loadsave::~loadsave() throw() {} ++ ++loadsave_load::loadsave_load(const std::vector& _memory) ++ : memory(_memory) ++{ ++ ptr = 0; ++} ++ ++template void loadsave_load::do_op(T& x) ++{ ++ unsigned long long v = 0; ++ if(ptr + sizeof(T) > memory.size()) ++ throw std::runtime_error("Loadstate overflow"); ++ for(size_t i = 0; i < sizeof(T); i++) ++ v |= ((unsigned long long)(unsigned char)memory[ptr++] << (8 * (sizeof(T) - i - 1))); ++ x = (T)v; ++} ++ ++template void loadsave_load::do_op(T& x, unsigned char _tag) ++{ ++ if(ptr + 1 > memory.size()) ++ throw std::runtime_error("Loadstate overflow"); ++ unsigned char _rtag = memory[ptr++]; ++ if(_rtag != _tag) { ++ std::cerr << "Wrong type tag: expected=" << (int)_tag << ", got=" << (int)_rtag << std::endl; ++ throw std::runtime_error("Loadstate desynced"); ++ } ++ do_op(x); ++} ++ ++template void loadsave_load::do_op(T* x, size_t s, unsigned char _tag) ++{ ++ if(ptr + 1 > memory.size()) ++ throw std::runtime_error("Loadstate overflow"); ++ unsigned char _rtag = memory[ptr++]; ++ if(_rtag != _tag) { ++ std::cerr << "Wrong type tag: expected=" << (int)_tag << ", got=" << (int)_rtag << std::endl; ++ throw std::runtime_error("Loadstate desynced"); ++ } ++ unsigned size; ++ do_op(size); ++ if(size != s) { ++ std::cerr << "Wrong number of entries: expected=" << s << ", got=" << size << std::endl; ++ throw std::runtime_error("Loadstate desynced"); ++ } ++ for(size_t i = 0; i < s; i++) ++ do_op(x[i]); ++} ++ ++void loadsave_load::operator()(bool& x) ++{ ++ char c; ++ do_op(c, 0); ++ x = (c != 0); ++} ++ ++ ++loadsave_load::~loadsave_load() throw() {} ++void loadsave_load::operator()(signed char& x) { do_op(x, 1); } ++void loadsave_load::operator()(unsigned char& x) { do_op(x, 2); } ++void loadsave_load::operator()(signed short& x) { do_op(x, 3); } ++void loadsave_load::operator()(unsigned short& x) { do_op(x, 4); } ++void loadsave_load::operator()(signed int& x) { do_op(x, 5); } ++void loadsave_load::operator()(unsigned int& x) { do_op(x, 6); } ++void loadsave_load::operator()(signed long long& x) { do_op(x, 7); } ++void loadsave_load::operator()(unsigned long long& x) { do_op(x, 8); } ++void loadsave_load::operator()(signed char* x, size_t s) { do_op(x, s, 9); } ++void loadsave_load::operator()(unsigned char* x, size_t s) { do_op(x, s, 10); } ++void loadsave_load::operator()(signed short* x, size_t s) { do_op(x, s, 11); } ++void loadsave_load::operator()(unsigned short* x, size_t s) { do_op(x, s, 12); } ++void loadsave_load::operator()(signed int* x, size_t s) { do_op(x, s, 13); } ++void loadsave_load::operator()(unsigned int* x, size_t s) { do_op(x, s, 14); } ++void loadsave_load::operator()(signed long long* x, size_t s) { do_op(x, s, 15); } ++void loadsave_load::operator()(unsigned long long* x, size_t s) { do_op(x, s, 16); } ++ ++void loadsave_load::tag(unsigned short _tag) ++{ ++ unsigned short _rtag; ++ do_op(_rtag, 18); ++ if(_tag != _rtag) { ++ std::cerr << "Wrong inner tag: expected=" << (int)_tag << ", got=" << (int)_rtag << std::endl; ++ throw std::runtime_error("Loadstate desynced"); ++ } ++} ++ ++void loadsave_load::operator()(unsigned char*& ptr, unsigned char* abase) ++{ ++ char x; ++ do_op(x, 17); ++ if(!x) ++ ptr = NULL; ++ else { ++ unsigned y; ++ do_op(y); ++ ptr = abase + y; ++ } ++} ++ ++void loadsave_load::operator()(const unsigned char*& ptr, unsigned char* abase) ++{ ++ char x; ++ do_op(x, 19); ++ if(!x) ++ ptr = NULL; ++ else { ++ unsigned y; ++ do_op(y); ++ ptr = abase + y; ++ } ++} ++ ++ ++bool loadsave_load::saving() { return false; } ++ ++#define BLOCKBYTES 65500 ++ ++void loadsave_save::pushbytes(char* bytes, size_t amount) ++{ ++ if(!nextptr || memory[nextptr - 1].second + amount > BLOCKBYTES) { ++ memory.push_back(std::make_pair(new char[BLOCKBYTES], (size_t)0)); ++ nextptr++; ++ } ++ if(cmp.size()) ++ try { if(cmp.size() < used + amount || memcmp(&cmp[used], bytes, amount)) throw 42; } catch(...) {} ++ memcpy(memory[nextptr - 1].first + memory[nextptr - 1].second, bytes, amount); ++ memory[nextptr - 1].second += amount; ++ used += amount; ++} ++ ++template void loadsave_save::do_op(T& x) ++{ ++ unsigned long long v = x; ++ char buf[sizeof(T)]; ++ for(size_t i = 0; i < sizeof(T); i++) ++ buf[i] = v >> (8 * (sizeof(T) - i - 1)); ++ pushbytes(buf, sizeof(T)); ++} ++ ++template void loadsave_save::do_op(T& x, unsigned char _tag) ++{ ++ pushbytes((char*)&_tag, 1); ++ do_op(x); ++} ++ ++template void loadsave_save::do_op(T* x, size_t s, unsigned char _tag) ++{ ++ pushbytes((char*)&_tag, 1); ++ unsigned size = s; ++ do_op(size); ++ for(size_t i = 0; i < s; i++) ++ do_op(x[i]); ++} ++ ++loadsave_save::loadsave_save() ++{ ++ used = 0; ++ nextptr = 0; ++} ++ ++loadsave_save::loadsave_save(const std::vector& _memory) ++{ ++ used = 0; ++ nextptr = 0; ++ cmp = _memory; ++} ++ ++loadsave_save::~loadsave_save() throw() ++{ ++ for(auto i : memory) ++ delete[] i.first; ++} ++ ++void loadsave_save::operator()(bool& x) ++{ ++ char y = x ? 1 : 0; ++ char z = 0; ++ pushbytes(&z, 1); ++ pushbytes(&y, 1); ++} ++ ++void loadsave_save::operator()(signed char& x) { do_op(x, 1); } ++void loadsave_save::operator()(unsigned char& x) { do_op(x, 2); } ++void loadsave_save::operator()(signed short& x) { do_op(x, 3); } ++void loadsave_save::operator()(unsigned short& x) { do_op(x, 4); } ++void loadsave_save::operator()(signed int& x) { do_op(x, 5); } ++void loadsave_save::operator()(unsigned int& x) { do_op(x, 6); } ++void loadsave_save::operator()(signed long long& x) { do_op(x, 7); } ++void loadsave_save::operator()(unsigned long long& x) { do_op(x, 8); } ++void loadsave_save::operator()(signed char* x, size_t s) { do_op(x, s, 9); } ++void loadsave_save::operator()(unsigned char* x, size_t s) { do_op(x, s, 10); } ++void loadsave_save::operator()(signed short* x, size_t s) { do_op(x, s, 11); } ++void loadsave_save::operator()(unsigned short* x, size_t s) { do_op(x, s, 12); } ++void loadsave_save::operator()(signed int* x, size_t s) { do_op(x, s, 13); } ++void loadsave_save::operator()(unsigned int* x, size_t s) { do_op(x, s, 14); } ++void loadsave_save::operator()(signed long long* x, size_t s) { do_op(x, s, 15); } ++void loadsave_save::operator()(unsigned long long* x, size_t s) { do_op(x, s, 16); } ++bool loadsave_save::saving() { return true; } ++ ++void loadsave_save::operator()(unsigned char*& ptr, unsigned char* abase) ++{ ++ if(!ptr) { ++ char x = 0; ++ do_op(x, 17); ++ } else { ++ char x = 1; ++ unsigned y = ptr - abase; ++ do_op(x, 17); ++ do_op(y); ++ } ++} ++ ++void loadsave_save::operator()(const unsigned char*& ptr, unsigned char* abase) ++{ ++ if(!ptr) { ++ char x = 0; ++ do_op(x, 19); ++ } else { ++ char x = 1; ++ unsigned y = ptr - abase; ++ do_op(x, 19); ++ do_op(y); ++ } ++} ++ ++void loadsave_save::tag(unsigned short _tag) ++{ ++ do_op(_tag, 18); ++} ++ ++std::vector loadsave_save::get() ++{ ++ std::vector x; ++ x.resize(used); ++ size_t ptr = 0; ++ for(auto i : memory) { ++ memcpy(&x[ptr], i.first, i.second); ++ ptr += i.second; ++ } ++ return x; ++} ++} +diff --git a/libgambatte/src/loadsave.h b/libgambatte/src/loadsave.h +new file mode 100644 +index 0000000..10ebf63 +--- /dev/null ++++ b/libgambatte/src/loadsave.h +@@ -0,0 +1,160 @@ ++#ifndef _loadsave__hpp__included__ ++#define _loadsave__hpp__included__ ++/*************************************************************************** ++ * Copyright (C) 2012 by H. Ilari Liusvaara * ++ * ilari.liusvaara@elisanet.fi * ++ * * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License version 2 as * ++ * published by the Free Software Foundation. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License version 2 for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * version 2 along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ ***************************************************************************/ ++ ++#include ++#include ++#include ++#include ++ ++namespace gambatte { ++ class loadsave ++ { ++ private: ++ unsigned enumVal; ++ bool enumAssigned; ++ public: ++ virtual ~loadsave() throw(); ++ virtual void operator()(bool& x) = 0; ++ virtual void operator()(signed char& x) = 0; ++ virtual void operator()(unsigned char& x) = 0; ++ virtual void operator()(signed short& x) = 0; ++ virtual void operator()(unsigned short& x) = 0; ++ virtual void operator()(signed int& x) = 0; ++ virtual void operator()(unsigned int& x) = 0; ++ virtual void operator()(signed long long& x) = 0; ++ virtual void operator()(unsigned long long& x) = 0; ++ virtual void operator()(signed char* x, size_t s) = 0; ++ virtual void operator()(unsigned char* x, size_t s) = 0; ++ virtual void operator()(signed short* x, size_t s) = 0; ++ virtual void operator()(unsigned short* x, size_t s) = 0; ++ virtual void operator()(signed int* x, size_t s) = 0; ++ virtual void operator()(unsigned int* x, size_t s) = 0; ++ virtual void operator()(long long* x, size_t s) = 0; ++ virtual void operator()(unsigned long long* x, size_t s) = 0; ++ virtual void operator()(unsigned char*& ptr, unsigned char* abase) = 0; ++ virtual void operator()(const unsigned char*& ptr, unsigned char* abase) = 0; ++ virtual void tag(unsigned short tag) = 0; ++ void time(time_t& t) { ++ unsigned long long t_ = t; ++ (*this)(t_); ++ t = t_; ++ } ++ void startEnumeration() { ++ enumAssigned = false; ++ enumVal = 0xFFFFFFFFU; ++ if(!saving()) ++ (*this)(enumVal); ++ } ++ template void enumerate(T& ptr, T candiate, unsigned symbol) { ++ if(saving()) { ++ if(ptr == candiate) { ++ enumVal = symbol; ++ enumAssigned = true; ++ } ++ } else { ++ if(enumVal == symbol) { ++ ptr = candiate; ++ enumAssigned = true; ++ } ++ } ++ } ++ void endEnumeration() { ++ if(saving()) ++ (*this)(enumVal); ++ if(!enumAssigned) ++ throw std::runtime_error("Enumeration missing a choice"); ++ } ++ virtual bool saving() = 0; ++ }; ++ ++ class loadsave_load : public loadsave ++ { ++ const std::vector& memory; ++ size_t ptr; ++ template inline void do_op(T& x); ++ template inline void do_op(T& x, unsigned char _tag); ++ template void do_op(T* x, size_t s, unsigned char _tag); ++ public: ++ loadsave_load(const std::vector& _memory); ++ ~loadsave_load() throw(); ++ void operator()(bool& x); ++ void operator()(signed char& x); ++ void operator()(unsigned char& x); ++ void operator()(signed short& x); ++ void operator()(unsigned short& x); ++ void operator()(signed int& x); ++ void operator()(unsigned int& x); ++ void operator()(signed long long& x); ++ void operator()(unsigned long long& x); ++ void operator()(signed char* x, size_t s); ++ void operator()(unsigned char* x, size_t s); ++ void operator()(signed short* x, size_t s); ++ void operator()(unsigned short* x, size_t s); ++ void operator()(signed int* x, size_t s); ++ void operator()(unsigned int* x, size_t s); ++ void operator()(signed long long* x, size_t s); ++ void operator()(unsigned long long* x, size_t s); ++ void operator()(unsigned char*& ptr, unsigned char* abase); ++ void operator()(const unsigned char*& ptr, unsigned char* abase); ++ void tag(unsigned short _tag); ++ bool saving(); ++ }; ++ ++ class loadsave_save : public loadsave ++ { ++ std::vector> memory; ++ size_t nextptr; ++ size_t used; ++ inline void pushbytes(char* bytes, size_t amount); ++ template inline void do_op(T& x); ++ template inline void do_op(T& x, unsigned char _tag); ++ template void do_op(T* x, size_t s, unsigned char _tag); ++ std::vector cmp; ++ public: ++ loadsave_save(); ++ loadsave_save(const std::vector& _memory); ++ ~loadsave_save() throw(); ++ void operator()(bool& x); ++ void operator()(signed char& x); ++ void operator()(unsigned char& x); ++ void operator()(signed short& x); ++ void operator()(unsigned short& x); ++ void operator()(signed int& x); ++ void operator()(unsigned int& x); ++ void operator()(signed long long& x); ++ void operator()(unsigned long long& x); ++ void operator()(signed char* x, size_t s); ++ void operator()(unsigned char* x, size_t s); ++ void operator()(signed short* x, size_t s); ++ void operator()(unsigned short* x, size_t s); ++ void operator()(signed int* x, size_t s); ++ void operator()(unsigned int* x, size_t s); ++ void operator()(signed long long* x, size_t s); ++ void operator()(unsigned long long* x, size_t s); ++ void operator()(unsigned char*& ptr, unsigned char* abase); ++ void operator()(const unsigned char*& ptr, unsigned char* abase); ++ void tag(unsigned short _tag); ++ bool saving(); ++ std::vector get(); ++ }; ++} ++ ++#endif +diff --git a/libgambatte/src/mem/cartridge.cpp b/libgambatte/src/mem/cartridge.cpp +index 452efa4..dcfed26 100644 +--- a/libgambatte/src/mem/cartridge.cpp ++++ b/libgambatte/src/mem/cartridge.cpp +@@ -23,6 +23,10 @@ + #include + #include + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + namespace gambatte { + + namespace { +@@ -36,6 +40,8 @@ public: + virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned addr, unsigned bank) const { + return (addr< 0x4000) == (bank == 0); + } ++ void loadOrSave(loadsave& state) { ++ } + }; + + class Mbc0 : public DefaultMbc { +@@ -64,6 +70,10 @@ public: + enableRam = ss.enableRam; + memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0); + } ++ ++ void loadOrSave(loadsave& state) { ++ state(enableRam); ++ } + }; + + static inline unsigned rambanks(const MemPtrs &memptrs) { +@@ -95,6 +105,13 @@ public: + { + } + ++ void loadOrSave(loadsave& state) { ++ state(rombank); ++ state(rambank); ++ state(enableRam); ++ state(rambankMode); ++ } ++ + virtual void romWrite(const unsigned P, const unsigned data) { + switch (P >> 13 & 3) { + case 0: +@@ -168,6 +185,12 @@ public: + { + } + ++ void loadOrSave(loadsave& state) { ++ state(rombank); ++ state(enableRam); ++ state(rombank0Mode); ++ } ++ + virtual void romWrite(const unsigned P, const unsigned data) { + switch (P >> 13 & 3) { + case 0: +@@ -221,6 +244,11 @@ public: + { + } + ++ void loadOrSave(loadsave& state) { ++ state(rombank); ++ state(enableRam); ++ } ++ + virtual void romWrite(const unsigned P, const unsigned data) { + switch (P & 0x6100) { + case 0x0000: +@@ -277,6 +305,12 @@ public: + { + } + ++ void loadOrSave(loadsave& state) { ++ state(rombank); ++ state(rambank); ++ state(enableRam); ++ } ++ + virtual void romWrite(const unsigned P, const unsigned data) { + switch (P >> 13 & 3) { + case 0: +@@ -338,6 +372,13 @@ public: + { + } + ++ void loadOrSave(loadsave& state) { ++ state(rombank); ++ state(rambank); ++ state(enableRam); ++ state(rambankMode); ++ } ++ + virtual void romWrite(const unsigned P, const unsigned data) { + switch (P >> 13 & 3) { + case 0: +@@ -396,6 +437,12 @@ public: + { + } + ++ void loadOrSave(loadsave& state) { ++ state(rombank); ++ state(rambank); ++ state(enableRam); ++ } ++ + virtual void romWrite(const unsigned P, const unsigned data) { + switch (P >> 13 & 3) { + case 0: +@@ -505,7 +552,15 @@ static unsigned pow2ceil(unsigned n) { + + int Cartridge::loadROM(const std::string &romfile, const bool forceDmg, const bool multicartCompat) { + const std::auto_ptr rom(newFileInstance(romfile)); ++ return loadROM(rom.get(), forceDmg, multicartCompat, romfile); ++} + ++int Cartridge::loadROM(const unsigned char* image, size_t isize, const bool forceDmg, const bool multicartCompat) { ++ const std::auto_ptr rom(newFileInstance(image, isize)); ++ return loadROM(rom.get(), forceDmg, multicartCompat, ""); ++} ++ ++int Cartridge::loadROM(File* rom, const bool forceDmg, const bool multicartCompat, const std::string& filename) { + if (rom->fail()) + return -1; + +@@ -613,8 +668,15 @@ int Cartridge::loadROM(const std::string &romfile, const bool forceDmg, const bo + if (rom->fail()) + return -1; + +- defaultSaveBasePath = stripExtension(romfile); +- ++ if(filename != "") { ++ defaultSaveBasePath = stripExtension(filename); ++ memoryCartridge = false; ++ } else { ++ defaultSaveBasePath = ""; ++ memoryCartridge = true; ++ } ++ clearMemorySavedData(); ++ + switch (type) { + case PLAIN: mbc.reset(new Mbc0(memptrs)); break; + case MBC1: +@@ -653,45 +715,69 @@ void Cartridge::loadSavedata() { + const std::string &sbp = saveBasePath(); + + if (hasBattery(memptrs.romdata()[0x147])) { +- std::ifstream file((sbp + ".sav").c_str(), std::ios::binary | std::ios::in); ++ if(memoryCartridge) { ++ if(memoryCartridgeSram.size()) ++ memcpy(memptrs.rambankdata(), &memoryCartridgeSram[0], memptrs.rambankdataend() - memptrs.rambankdata()); ++ } else { ++ std::ifstream file((sbp + ".sav").c_str(), std::ios::binary | std::ios::in); + +- if (file.is_open()) { +- file.read(reinterpret_cast(memptrs.rambankdata()), memptrs.rambankdataend() - memptrs.rambankdata()); +- enforce8bit(memptrs.rambankdata(), memptrs.rambankdataend() - memptrs.rambankdata()); ++ if (file.is_open()) { ++ file.read(reinterpret_cast(memptrs.rambankdata()), memptrs.rambankdataend() - memptrs.rambankdata()); ++ enforce8bit(memptrs.rambankdata(), memptrs.rambankdataend() - memptrs.rambankdata()); ++ } + } + } + + if (hasRtc(memptrs.romdata()[0x147])) { +- std::ifstream file((sbp + ".rtc").c_str(), std::ios::binary | std::ios::in); ++ if(memoryCartridge) { ++ rtc.setBaseTime(memoryCartridgeRtcBase); ++ } else { ++ std::ifstream file((sbp + ".rtc").c_str(), std::ios::binary | std::ios::in); + +- if (file.is_open()) { +- unsigned long basetime = file.get() & 0xFF; ++ if (file.is_open()) { ++ unsigned long basetime = file.get() & 0xFF; + +- basetime = basetime << 8 | (file.get() & 0xFF); +- basetime = basetime << 8 | (file.get() & 0xFF); +- basetime = basetime << 8 | (file.get() & 0xFF); ++ basetime = basetime << 8 | (file.get() & 0xFF); ++ basetime = basetime << 8 | (file.get() & 0xFF); ++ basetime = basetime << 8 | (file.get() & 0xFF); + +- rtc.setBaseTime(basetime); ++ rtc.setBaseTime(basetime); ++ } + } + } + } + ++void Cartridge::clearMemorySavedData() ++{ ++ memoryCartridgeRtcBase = 0; ++ memoryCartridgeSram.resize(0); ++} ++ + void Cartridge::saveSavedata() { + const std::string &sbp = saveBasePath(); + + if (hasBattery(memptrs.romdata()[0x147])) { +- std::ofstream file((sbp + ".sav").c_str(), std::ios::binary | std::ios::out); +- file.write(reinterpret_cast(memptrs.rambankdata()), memptrs.rambankdataend() - memptrs.rambankdata()); ++ if(memoryCartridge) { ++ memoryCartridgeSram.resize(memptrs.rambankdataend() - memptrs.rambankdata()); ++ memcpy(&memoryCartridgeSram[0], memptrs.rambankdata(), memptrs.rambankdataend() - memptrs.rambankdata()); ++ } else { ++ std::ofstream file((sbp + ".sav").c_str(), std::ios::binary | std::ios::out); ++ file.write(reinterpret_cast(memptrs.rambankdata()), memptrs.rambankdataend() - memptrs.rambankdata()); ++ } + } + + if (hasRtc(memptrs.romdata()[0x147])) { +- std::ofstream file((sbp + ".rtc").c_str(), std::ios::binary | std::ios::out); +- const unsigned long basetime = rtc.getBaseTime(); ++ if(memoryCartridge) { ++ memoryCartridgeRtcBase = rtc.getBaseTime(); ++ } else { ++ std::ofstream file((sbp + ".rtc").c_str(), std::ios::binary | std::ios::out); ++ const unsigned long basetime = rtc.getBaseTime(); + +- file.put(basetime >> 24 & 0xFF); +- file.put(basetime >> 16 & 0xFF); +- file.put(basetime >> 8 & 0xFF); +- file.put(basetime & 0xFF); ++ file.put(basetime >> 24 & 0xFF); ++ file.put(basetime >> 16 & 0xFF); ++ file.put(basetime >> 8 & 0xFF); ++ file.put(basetime & 0xFF); ++ } + } + } + +@@ -737,4 +823,31 @@ void Cartridge::setGameGenie(const std::string &codes) { + } + } + ++std::pair Cartridge::getSaveRam() { ++ size_t sramsize = memptrs.rambankdataend() - memptrs.rambankdata(); ++ return std::make_pair(memptrs.rambankdata(), sramsize); ++} ++ ++std::pair Cartridge::getWorkRam() { ++ size_t worksize = memptrs.wramdataend() - memptrs.wramdata(0); ++ return std::make_pair(memptrs.wramdata(0), worksize); ++} ++ ++Cartridge::Cartridge(time_t (**_getCurrentTime)()) ++ : rtc(_getCurrentTime) { ++ memoryCartridge = true; ++} ++ ++void Cartridge::loadOrSave(loadsave& state) { ++ memptrs.loadOrSave(state); ++ rtc.loadOrSave(state); ++ mbc->loadOrSave(state); ++ unsigned ggsize = ggUndoList.size(); ++ state(ggsize); ++ if(!state.saving()) ++ ggUndoList.resize(ggsize); ++ for(size_t i = 0; i < ggsize; i++) ++ ggUndoList[i].loadOrSave(state); ++} ++ + } +diff --git a/libgambatte/src/mem/cartridge.h b/libgambatte/src/mem/cartridge.h +index bbb3662..3ae779e 100644 +--- a/libgambatte/src/mem/cartridge.h ++++ b/libgambatte/src/mem/cartridge.h +@@ -25,9 +25,16 @@ + #include + #include + #include ++#include "../loadsave.h" ++ ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. + + namespace gambatte { + ++class File; ++ + class Mbc { + public: + virtual ~Mbc() {} +@@ -35,13 +42,19 @@ public: + virtual void saveState(SaveState::Mem &ss) const = 0; + virtual void loadState(const SaveState::Mem &ss) = 0; + virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned address, unsigned rombank) const = 0; ++ virtual void loadOrSave(loadsave& state) = 0; + }; + + class Cartridge { + struct AddrData { +- unsigned long addr; ++ unsigned addr; + unsigned char data; +- AddrData(unsigned long addr, unsigned data) : addr(addr), data(data) {} ++ AddrData(unsigned addr, unsigned data) : addr(addr), data(data) {} ++ AddrData() {} ++ void loadOrSave(loadsave& state) { ++ state(addr); ++ state(data); ++ } + }; + + MemPtrs memptrs; +@@ -50,14 +63,22 @@ class Cartridge { + std::string defaultSaveBasePath; + std::string saveDir; + std::vector ggUndoList; +- ++ bool memoryCartridge; ++ time_t memoryCartridgeRtcBase; ++ std::vector memoryCartridgeSram; ++ + void applyGameGenie(const std::string &code); +- ++ ++ int loadROM(File* rom, const bool forceDmg, const bool multicartCompat, const std::string& filename); ++ void clearMemorySavedData(); + public: ++ Cartridge(time_t (**_getCurrentTime)()); + void setStatePtrs(SaveState &); + void saveState(SaveState &) const; + void loadState(const SaveState &); + ++ void loadOrSave(loadsave& state); ++ + bool loaded() const { return mbc.get(); } + + const unsigned char * rmem(unsigned area) const { return memptrs.rmem(area); } +@@ -84,8 +105,15 @@ public: + const std::string saveBasePath() const; + void setSaveDir(const std::string &dir); + int loadROM(const std::string &romfile, bool forceDmg, bool multicartCompat); ++ int loadROM(const unsigned char* image, size_t isize, bool forceDmg, bool multicartCompat); + const char * romTitle() const { return reinterpret_cast(memptrs.romdata() + 0x134); } + void setGameGenie(const std::string &codes); ++ ++ void setRtcBase(time_t time) { rtc.setBaseTime(time); } ++ time_t getRtcBase() { return rtc.getBaseTime(); } ++ std::pair getWorkRam(); ++ std::pair getSaveRam(); ++ + }; + + } +diff --git a/libgambatte/src/mem/memptrs.cpp b/libgambatte/src/mem/memptrs.cpp +index 243810c..049a8ba 100644 +--- a/libgambatte/src/mem/memptrs.cpp ++++ b/libgambatte/src/mem/memptrs.cpp +@@ -20,6 +20,10 @@ + #include + #include + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + namespace gambatte { + + MemPtrs::MemPtrs() : +@@ -39,7 +43,11 @@ MemPtrs::~MemPtrs() { + + void MemPtrs::reset(const unsigned rombanks, const unsigned rambanks, const unsigned wrambanks) { + delete []memchunk_; +- memchunk_ = new unsigned char[0x4000 + rombanks * 0x4000ul + rambanks * 0x2000ul + wrambanks * 0x1000ul + 0x4000]; ++ memchunk_size = 0x4000 + rombanks * 0x4000ul + rambanks * 0x2000ul + wrambanks * 0x1000ul + 0x4000; ++ memchunk_ = new unsigned char[memchunk_size]; ++ ++ //FIXME: Make this random. ++ memset(memchunk_, 0, memchunk_size); + + romdata_[0] = romdata(); + rambankdata_ = romdata_[0] + rombanks * 0x4000ul; +@@ -141,4 +149,26 @@ void MemPtrs::disconnectOamDmaAreas() { + } + } + ++void MemPtrs::loadOrSave(loadsave& state) ++{ ++ state(memchunk_, 0x4000); ++ state(rambankdata_, memchunk_size - (rambankdata_ - memchunk_)); ++ int oamDmaSrc_2 = oamDmaSrc_; ++ state(oamDmaSrc_2); ++ oamDmaSrc_ = (OamDmaSrc)oamDmaSrc_2; ++ //Rmem is constant. ++ for(unsigned i = 0; i < 0x10; i++) ++ state(wmem_[i], memchunk_); ++ for(unsigned i = 0; i < 0x10; i++) ++ state(rmem_[i], memchunk_); ++ state(romdata_[0], memchunk_); ++ state(romdata_[1], memchunk_); ++ state(rambankdata_, memchunk_); ++ state(rdisabledRam_, memchunk_); ++ state(wdisabledRam_, memchunk_); ++ state(rsrambankptr_, memchunk_); ++ state(wsrambankptr_, memchunk_); ++ //memchunk_size is cart constant, not saved. ++} ++ + } +diff --git a/libgambatte/src/mem/memptrs.h b/libgambatte/src/mem/memptrs.h +index 62c0fa9..2fc2789 100644 +--- a/libgambatte/src/mem/memptrs.h ++++ b/libgambatte/src/mem/memptrs.h +@@ -19,6 +19,12 @@ + #ifndef MEMPTRS_H + #define MEMPTRS_H + ++#include "../loadsave.h" ++ ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + namespace gambatte { + + enum OamDmaSrc { OAM_DMA_SRC_ROM, OAM_DMA_SRC_SRAM, OAM_DMA_SRC_VRAM, +@@ -36,7 +42,8 @@ class MemPtrs { + unsigned char *wdisabledRam_; + unsigned char *rsrambankptr_; + unsigned char *wsrambankptr_; +- ++ unsigned memchunk_size; ++ + OamDmaSrc oamDmaSrc_; + + MemPtrs(const MemPtrs &); +@@ -68,6 +75,8 @@ public: + void setRambank(unsigned ramFlags, unsigned rambank); + void setWrambank(unsigned bank); + void setOamDmaSrc(OamDmaSrc oamDmaSrc); ++ ++ void loadOrSave(loadsave& state); + }; + + inline bool isCgb(const MemPtrs &memptrs) { +diff --git a/libgambatte/src/mem/rtc.cpp b/libgambatte/src/mem/rtc.cpp +index 993db29..62e0dac 100644 +--- a/libgambatte/src/mem/rtc.cpp ++++ b/libgambatte/src/mem/rtc.cpp +@@ -19,9 +19,13 @@ + #include "rtc.h" + #include "../savestate.h" + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + namespace gambatte { + +-Rtc::Rtc() ++Rtc::Rtc(time_t (**_getCurrentTime)()) + : activeData(NULL), + activeSet(NULL), + baseTime(0), +@@ -33,12 +37,13 @@ Rtc::Rtc() + dataM(0), + dataS(0), + enabled(false), +- lastLatchData(false) ++ lastLatchData(false), ++ getCurrentTime(_getCurrentTime) + { + } + + void Rtc::doLatch() { +- std::time_t tmp = ((dataDh & 0x40) ? haltTime : std::time(0)) - baseTime; ++ std::time_t tmp = ((dataDh & 0x40) ? haltTime : (*getCurrentTime)()) - baseTime; + + while (tmp > 0x1FF * 86400) { + baseTime += 0x1FF * 86400; +@@ -113,44 +118,76 @@ void Rtc::loadState(const SaveState &state) { + } + + void Rtc::setDh(const unsigned new_dh) { +- const std::time_t unixtime = (dataDh & 0x40) ? haltTime : std::time(0); ++ const std::time_t unixtime = (dataDh & 0x40) ? haltTime : (*getCurrentTime)(); + const std::time_t old_highdays = ((unixtime - baseTime) / 86400) & 0x100; + baseTime += old_highdays * 86400; + baseTime -= ((new_dh & 0x1) << 8) * 86400; + + if ((dataDh ^ new_dh) & 0x40) { + if (new_dh & 0x40) +- haltTime = std::time(0); ++ haltTime = (*getCurrentTime)(); + else +- baseTime += std::time(0) - haltTime; ++ baseTime += (*getCurrentTime)() - haltTime; + } + } + + void Rtc::setDl(const unsigned new_lowdays) { +- const std::time_t unixtime = (dataDh & 0x40) ? haltTime : std::time(0); ++ const std::time_t unixtime = (dataDh & 0x40) ? haltTime : (*getCurrentTime)(); + const std::time_t old_lowdays = ((unixtime - baseTime) / 86400) & 0xFF; + baseTime += old_lowdays * 86400; + baseTime -= new_lowdays * 86400; + } + + void Rtc::setH(const unsigned new_hours) { +- const std::time_t unixtime = (dataDh & 0x40) ? haltTime : std::time(0); ++ const std::time_t unixtime = (dataDh & 0x40) ? haltTime : (*getCurrentTime)(); + const std::time_t old_hours = ((unixtime - baseTime) / 3600) % 24; + baseTime += old_hours * 3600; + baseTime -= new_hours * 3600; + } + + void Rtc::setM(const unsigned new_minutes) { +- const std::time_t unixtime = (dataDh & 0x40) ? haltTime : std::time(0); ++ const std::time_t unixtime = (dataDh & 0x40) ? haltTime : (*getCurrentTime)(); + const std::time_t old_minutes = ((unixtime - baseTime) / 60) % 60; + baseTime += old_minutes * 60; + baseTime -= new_minutes * 60; + } + + void Rtc::setS(const unsigned new_seconds) { +- const std::time_t unixtime = (dataDh & 0x40) ? haltTime : std::time(0); ++ const std::time_t unixtime = (dataDh & 0x40) ? haltTime : (*getCurrentTime)(); + baseTime += (unixtime - baseTime) % 60; + baseTime -= new_seconds; + } + ++void Rtc::loadOrSave(loadsave& state) ++{ ++ state.startEnumeration(); ++ state.enumerate(activeData, NULL, 0); ++ state.enumerate(activeData, &dataDh, 1); ++ state.enumerate(activeData, &dataDl, 2); ++ state.enumerate(activeData, &dataH, 3); ++ state.enumerate(activeData, &dataM, 4); ++ state.enumerate(activeData, &dataS, 5); ++ state.endEnumeration(); ++ ++ state.startEnumeration(); ++ state.enumerate(activeSet, NULL, 0); ++ state.enumerate(activeSet, &Rtc::setDh, 1); ++ state.enumerate(activeSet, &Rtc::setDl, 2); ++ state.enumerate(activeSet, &Rtc::setH, 3); ++ state.enumerate(activeSet, &Rtc::setM, 4); ++ state.enumerate(activeSet, &Rtc::setS, 5); ++ state.endEnumeration(); ++ ++ state.time(baseTime); ++ state.time(haltTime); ++ state(index); ++ state(dataDh); ++ state(dataDl); ++ state(dataH); ++ state(dataM); ++ state(dataS); ++ state(enabled); ++ state(lastLatchData); ++} ++ + } +diff --git a/libgambatte/src/mem/rtc.h b/libgambatte/src/mem/rtc.h +index c5b3b5a..206b46e 100644 +--- a/libgambatte/src/mem/rtc.h ++++ b/libgambatte/src/mem/rtc.h +@@ -20,6 +20,12 @@ + #define RTC_H + + #include ++#include "../loadsave.h" ++ ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + + namespace gambatte { + +@@ -39,6 +45,7 @@ private: + unsigned char dataS; + bool enabled; + bool lastLatchData; ++ time_t (**getCurrentTime)(); + + void doLatch(); + void doSwapActive(); +@@ -49,7 +56,7 @@ private: + void setS(unsigned new_seconds); + + public: +- Rtc(); ++ Rtc(time_t (**_getCurrentTime)()); + + const unsigned char* getActive() const { return activeData; } + std::time_t getBaseTime() const { return baseTime; } +@@ -84,6 +91,8 @@ public: + (this->*activeSet)(data); + *activeData = data; + } ++ ++ void loadOrSave(loadsave& state); + }; + + } +diff --git a/libgambatte/src/memory.cpp b/libgambatte/src/memory.cpp +index 01abb57..edba55b 100644 +--- a/libgambatte/src/memory.cpp ++++ b/libgambatte/src/memory.cpp +@@ -23,9 +23,13 @@ + #include "savestate.h" + #include + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + namespace gambatte { + +-Memory::Memory(const Interrupter &interrupter_in) ++Memory::Memory(const Interrupter &interrupter_in, time_t (**_getCurrentTime)()) + : vrambank(vram), + getInput(0), + divLastUpdate(0), +@@ -36,7 +40,8 @@ Memory::Memory(const Interrupter &interrupter_in) + dmaDestination(0), + oamDmaPos(0xFE), + serialCnt(0), +- blanklcd(false) ++ blanklcd(false), ++ cart(_getCurrentTime) + { + intreq.setEventTime(144*456ul); + intreq.setEventTime(0); +@@ -51,7 +56,7 @@ void Memory::setStatePtrs(SaveState &state) { + sound.setStatePtrs(state); + } + +-unsigned long Memory::saveState(SaveState &state, unsigned long cycleCounter) { ++unsigned Memory::saveState(SaveState &state, unsigned cycleCounter) { + cycleCounter = resetCounters(cycleCounter); + nontrivial_ff_read(0xFF05, cycleCounter); + nontrivial_ff_read(0xFF0F, cycleCounter); +@@ -74,7 +79,7 @@ unsigned long Memory::saveState(SaveState &state, unsigned long cycleCounter) { + return cycleCounter; + } + +-static inline int serialCntFrom(const unsigned long cyclesUntilDone, const bool cgbFast) { ++static inline int serialCntFrom(const unsigned cyclesUntilDone, const bool cgbFast) { + return cgbFast ? (cyclesUntilDone + 0xF) >> 4 : (cyclesUntilDone + 0x1FF) >> 9; + } + +@@ -116,14 +121,14 @@ void Memory::loadState(const SaveState &state) { + std::memset(vram + 0x2000, 0, 0x2000); + } + +-void Memory::setEndtime(const unsigned long cycleCounter, const unsigned long inc) { ++void Memory::setEndtime(const unsigned cycleCounter, const unsigned inc) { + if (intreq.eventTime(BLIT) <= cycleCounter) + intreq.setEventTime(intreq.eventTime(BLIT) + (70224 << isDoubleSpeed())); + + intreq.setEventTime(cycleCounter + (inc << isDoubleSpeed())); + } + +-void Memory::updateSerial(const unsigned long cc) { ++void Memory::updateSerial(const unsigned cc) { + if (intreq.eventTime(SERIAL) != DISABLED_TIME) { + if (intreq.eventTime(SERIAL) <= cc) { + ioamhram[0x101] = (((ioamhram[0x101] + 1) << serialCnt) - 1) & 0xFF; +@@ -138,18 +143,18 @@ void Memory::updateSerial(const unsigned long cc) { + } + } + +-void Memory::updateTimaIrq(const unsigned long cc) { ++void Memory::updateTimaIrq(const unsigned cc) { + while (intreq.eventTime(TIMA) <= cc) + tima.doIrqEvent(TimaInterruptRequester(intreq)); + } + +-void Memory::updateIrqs(const unsigned long cc) { ++void Memory::updateIrqs(const unsigned cc) { + updateSerial(cc); + updateTimaIrq(cc); + display.update(cc); + } + +-unsigned long Memory::event(unsigned long cycleCounter) { ++unsigned Memory::event(unsigned cycleCounter) { + if (lastOamDmaUpdate != DISABLED_TIME) + updateOamDma(cycleCounter); + +@@ -170,10 +175,10 @@ unsigned long Memory::event(unsigned long cycleCounter) { + case BLIT: + { + const bool lcden = ioamhram[0x140] >> 7 & 1; +- unsigned long blitTime = intreq.eventTime(BLIT); ++ unsigned blitTime = intreq.eventTime(BLIT); + + if (lcden | blanklcd) { +- display.updateScreen(blanklcd, cycleCounter); ++ display.updateScreen(blanklcd, cycleCounter, videoBuf_, pitch_); + intreq.setEventTime(DISABLED_TIME); + intreq.setEventTime(DISABLED_TIME); + +@@ -191,7 +196,7 @@ unsigned long Memory::event(unsigned long cycleCounter) { + break; + case OAM: + intreq.setEventTime(lastOamDmaUpdate == DISABLED_TIME ? +- static_cast(DISABLED_TIME) : intreq.eventTime(OAM) + 0xA0 * 4); ++ static_cast(DISABLED_TIME) : intreq.eventTime(OAM) + 0xA0 * 4); + break; + case DMA: + { +@@ -203,7 +208,7 @@ unsigned long Memory::event(unsigned long cycleCounter) { + + ackDmaReq(&intreq); + +- if ((static_cast(dmaDest) + length) & 0x10000) { ++ if ((static_cast(dmaDest) + length) & 0x10000) { + length = 0x10000 - dmaDest; + ioamhram[0x155] |= 0x80; + } +@@ -214,7 +219,7 @@ unsigned long Memory::event(unsigned long cycleCounter) { + dmaLength = 0; + + { +- unsigned long lOamDmaUpdate = lastOamDmaUpdate; ++ unsigned lOamDmaUpdate = lastOamDmaUpdate; + lastOamDmaUpdate = DISABLED_TIME; + + while (length--) { +@@ -295,7 +300,7 @@ unsigned long Memory::event(unsigned long cycleCounter) { + return cycleCounter; + } + +-unsigned long Memory::stop(unsigned long cycleCounter) { ++unsigned Memory::stop(unsigned cycleCounter) { + cycleCounter += 4 << isDoubleSpeed(); + + if (ioamhram[0x14D] & isCgb()) { +@@ -318,31 +323,31 @@ unsigned long Memory::stop(unsigned long cycleCounter) { + return cycleCounter; + } + +-static void decCycles(unsigned long &counter, const unsigned long dec) { ++static void decCycles(unsigned &counter, const unsigned dec) { + if (counter != DISABLED_TIME) + counter -= dec; + } + +-void Memory::decEventCycles(const MemEventId eventId, const unsigned long dec) { ++void Memory::decEventCycles(const MemEventId eventId, const unsigned dec) { + if (intreq.eventTime(eventId) != DISABLED_TIME) + intreq.setEventTime(eventId, intreq.eventTime(eventId) - dec); + } + +-unsigned long Memory::resetCounters(unsigned long cycleCounter) { ++unsigned Memory::resetCounters(unsigned cycleCounter) { + if (lastOamDmaUpdate != DISABLED_TIME) + updateOamDma(cycleCounter); + + updateIrqs(cycleCounter); + +- const unsigned long oldCC = cycleCounter; ++ const unsigned oldCC = cycleCounter; + + { +- const unsigned long divinc = (cycleCounter - divLastUpdate) >> 8; ++ const unsigned divinc = (cycleCounter - divLastUpdate) >> 8; + ioamhram[0x104] = (ioamhram[0x104] + divinc) & 0xFF; + divLastUpdate += divinc << 8; + } + +- const unsigned long dec = cycleCounter < 0x10000 ? 0 : (cycleCounter & ~0x7FFFul) - 0x8000; ++ const unsigned dec = cycleCounter < 0x10000 ? 0 : (cycleCounter & ~0x7FFFul) - 0x8000; + + decCycles(divLastUpdate, dec); + decCycles(lastOamDmaUpdate, dec); +@@ -381,7 +386,7 @@ void Memory::updateInput() { + ioamhram[0x100] &= button; + } + +-void Memory::updateOamDma(const unsigned long cycleCounter) { ++void Memory::updateOamDma(const unsigned cycleCounter) { + const unsigned char *const oamDmaSrc = oamDmaSrcPtr(); + unsigned cycles = (cycleCounter - lastOamDmaUpdate) >> 2; + +@@ -429,17 +434,17 @@ const unsigned char * Memory::oamDmaSrcPtr() const { + return ioamhram[0x146] == 0xFF && !isCgb() ? oamDmaSrcZero() : cart.rdisabledRam(); + } + +-void Memory::startOamDma(const unsigned long cycleCounter) { ++void Memory::startOamDma(const unsigned cycleCounter) { + display.oamChange(cart.rdisabledRam(), cycleCounter); + } + +-void Memory::endOamDma(const unsigned long cycleCounter) { ++void Memory::endOamDma(const unsigned cycleCounter) { + oamDmaPos = 0xFE; + cart.setOamDmaSrc(OAM_DMA_SRC_OFF); + display.oamChange(ioamhram, cycleCounter); + } + +-unsigned Memory::nontrivial_ff_read(const unsigned P, const unsigned long cycleCounter) { ++unsigned Memory::nontrivial_ff_read(const unsigned P, const unsigned cycleCounter) { + if (lastOamDmaUpdate != DISABLED_TIME) + updateOamDma(cycleCounter); + +@@ -453,7 +458,7 @@ unsigned Memory::nontrivial_ff_read(const unsigned P, const unsigned long cycleC + break; + case 0x04: + { +- const unsigned long divcycles = (cycleCounter - divLastUpdate) >> 8; ++ const unsigned divcycles = (cycleCounter - divLastUpdate) >> 8; + ioamhram[0x104] = (ioamhram[0x104] + divcycles) & 0xFF; + divLastUpdate += divcycles << 8; + } +@@ -532,7 +537,7 @@ static bool isInOamDmaConflictArea(const OamDmaSrc oamDmaSrc, const unsigned add + return addr < a[oamDmaSrc].areaUpper && addr - a[oamDmaSrc].exceptAreaLower >= a[oamDmaSrc].exceptAreaWidth; + } + +-unsigned Memory::nontrivial_read(const unsigned P, const unsigned long cycleCounter) { ++unsigned Memory::nontrivial_read(const unsigned P, const unsigned cycleCounter) { + if (P < 0xFF80) { + if (lastOamDmaUpdate != DISABLED_TIME) { + updateOamDma(cycleCounter); +@@ -571,7 +576,7 @@ unsigned Memory::nontrivial_read(const unsigned P, const unsigned long cycleCoun + return ioamhram[P - 0xFE00]; + } + +-void Memory::nontrivial_ff_write(const unsigned P, unsigned data, const unsigned long cycleCounter) { ++void Memory::nontrivial_ff_write(const unsigned P, unsigned data, const unsigned cycleCounter) { + if (lastOamDmaUpdate != DISABLED_TIME) + updateOamDma(cycleCounter); + +@@ -588,7 +593,7 @@ void Memory::nontrivial_ff_write(const unsigned P, unsigned data, const unsigned + serialCnt = 8; + intreq.setEventTime((data & 0x81) == 0x81 + ? (data & isCgb() * 2 ? (cycleCounter & ~0x7ul) + 0x10 * 8 : (cycleCounter & ~0xFFul) + 0x200 * 8) +- : static_cast(DISABLED_TIME)); ++ : static_cast(DISABLED_TIME)); + + data |= 0x7E - isCgb() * 2; + break; +@@ -949,7 +954,7 @@ void Memory::nontrivial_ff_write(const unsigned P, unsigned data, const unsigned + ioamhram[P - 0xFE00] = data; + } + +-void Memory::nontrivial_write(const unsigned P, const unsigned data, const unsigned long cycleCounter) { ++void Memory::nontrivial_write(const unsigned P, const unsigned data, const unsigned cycleCounter) { + if (lastOamDmaUpdate != DISABLED_TIME) { + updateOamDma(cycleCounter); + +@@ -986,24 +991,59 @@ void Memory::nontrivial_write(const unsigned P, const unsigned data, const unsig + ioamhram[P - 0xFE00] = data; + } + ++void Memory::postLoadRom() ++{ ++ sound.init(cart.isCgb()); ++ display.reset(ioamhram, cart.isCgb()); ++ interrupter.setGameShark(std::string()); ++} ++ + int Memory::loadROM(const std::string &romfile, const bool forceDmg, const bool multicartCompat) { + if (const int fail = cart.loadROM(romfile, forceDmg, multicartCompat)) + return fail; + +- sound.init(cart.isCgb()); +- display.reset(ioamhram, cart.isCgb()); +- interrupter.setGameShark(std::string()); ++ postLoadRom(); + + return 0; + } + +-unsigned Memory::fillSoundBuffer(const unsigned long cycleCounter) { ++int Memory::loadROM(const unsigned char* image, size_t isize, const bool forceDmg, const bool multicartCompat) { ++ if (const int fail = cart.loadROM(image, isize, forceDmg, multicartCompat)) ++ return fail; ++ ++ postLoadRom(); ++ ++ return 0; ++} ++ ++unsigned Memory::fillSoundBuffer(const unsigned cycleCounter) { + sound.generate_samples(cycleCounter, isDoubleSpeed()); + return sound.fillBuffer(); + } + +-void Memory::setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long rgb32) { ++void Memory::setDmgPaletteColor(unsigned palNum, unsigned colorNum, uint_least32_t rgb32) { + display.setDmgPaletteColor(palNum, colorNum, rgb32); + } + ++void Memory::loadOrSave(loadsave& state) ++{ ++ state(ioamhram, 0x200); ++ state(vram, 0x2000 * 2); ++ state(vrambank, vram); ++ //Don't save getInput, it has no state. ++ state(divLastUpdate); ++ state(lastOamDmaUpdate); ++ intreq.loadOrSave(state); ++ cart.loadOrSave(state); ++ tima.loadOrSave(state); ++ display.loadOrSave(state); ++ sound.loadOrSave(state); ++ interrupter.loadOrSave(state); ++ state(dmaSource); ++ state(dmaDestination); ++ state(oamDmaPos); ++ state(serialCnt); ++ state(blanklcd); ++} ++ + } +diff --git a/libgambatte/src/memory.h b/libgambatte/src/memory.h +index 9163367..8e4c4ee 100644 +--- a/libgambatte/src/memory.h ++++ b/libgambatte/src/memory.h +@@ -19,6 +19,10 @@ + #ifndef MEMORY_H + #define MEMORY_H + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + #include "mem/cartridge.h" + #include "video.h" + #include "sound.h" +@@ -35,8 +39,8 @@ class Memory { + unsigned char *vrambank; + + InputGetter *getInput; +- unsigned long divLastUpdate; +- unsigned long lastOamDmaUpdate; ++ unsigned divLastUpdate; ++ unsigned lastOamDmaUpdate; + + InterruptRequester intreq; + Cartridge cart; +@@ -51,34 +55,40 @@ class Memory { + unsigned char serialCnt; + bool blanklcd; + ++ uint_least32_t* videoBuf_; ++ unsigned pitch_; ++ + void updateInput(); +- void decEventCycles(MemEventId eventId, unsigned long dec); ++ void decEventCycles(MemEventId eventId, unsigned dec); + + void oamDmaInitSetup(); +- void updateOamDma(unsigned long cycleCounter); +- void startOamDma(unsigned long cycleCounter); +- void endOamDma(unsigned long cycleCounter); ++ void updateOamDma(unsigned cycleCounter); ++ void startOamDma(unsigned cycleCounter); ++ void endOamDma(unsigned cycleCounter); + const unsigned char * oamDmaSrcPtr() const; + +- unsigned nontrivial_ff_read(unsigned P, unsigned long cycleCounter); +- unsigned nontrivial_read(unsigned P, unsigned long cycleCounter); +- void nontrivial_ff_write(unsigned P, unsigned data, unsigned long cycleCounter); +- void nontrivial_write(unsigned P, unsigned data, unsigned long cycleCounter); ++ unsigned nontrivial_ff_read(unsigned P, unsigned cycleCounter); ++ unsigned nontrivial_read(unsigned P, unsigned cycleCounter); ++ void nontrivial_ff_write(unsigned P, unsigned data, unsigned cycleCounter); ++ void nontrivial_write(unsigned P, unsigned data, unsigned cycleCounter); + +- void updateSerial(unsigned long cc); +- void updateTimaIrq(unsigned long cc); +- void updateIrqs(unsigned long cc); ++ void updateSerial(unsigned cc); ++ void updateTimaIrq(unsigned cc); ++ void updateIrqs(unsigned cc); + + bool isDoubleSpeed() const { return display.isDoubleSpeed(); } + ++ void postLoadRom(); + public: +- explicit Memory(const Interrupter &interrupter); ++ explicit Memory(const Interrupter &interrupter, time_t (**_getCurrentTime)()); + + bool loaded() const { return cart.loaded(); } + const char * romTitle() const { return cart.romTitle(); } + ++ void loadOrSave(loadsave& state); ++ + void setStatePtrs(SaveState &state); +- unsigned long saveState(SaveState &state, unsigned long cc); ++ unsigned saveState(SaveState &state, unsigned cc); + void loadState(const SaveState &state/*, unsigned long oldCc*/); + void loadSavedata() { cart.loadSavedata(); } + void saveSavedata() { cart.saveSavedata(); } +@@ -88,67 +98,77 @@ public: + display.setOsdElement(osdElement); + } + +- unsigned long stop(unsigned long cycleCounter); ++ unsigned stop(unsigned cycleCounter); + bool isCgb() const { return display.isCgb(); } + bool ime() const { return intreq.ime(); } + bool halted() const { return intreq.halted(); } +- unsigned long nextEventTime() const { return intreq.minEventTime(); } ++ unsigned nextEventTime() const { return intreq.minEventTime(); } + + bool isActive() const { return intreq.eventTime(END) != DISABLED_TIME; } + +- long cyclesSinceBlit(const unsigned long cc) const { +- return cc < intreq.eventTime(BLIT) ? -1 : static_cast((cc - intreq.eventTime(BLIT)) >> isDoubleSpeed()); ++ signed cyclesSinceBlit(const unsigned cc) const { ++ return cc < intreq.eventTime(BLIT) ? -1 : static_cast((cc - intreq.eventTime(BLIT)) >> isDoubleSpeed()); + } + + void halt() { intreq.halt(); } +- void ei(unsigned long cycleCounter) { if (!ime()) { intreq.ei(cycleCounter); } } ++ void ei(unsigned cycleCounter) { if (!ime()) { intreq.ei(cycleCounter); } } + + void di() { intreq.di(); } + +- unsigned ff_read(const unsigned P, const unsigned long cycleCounter) { ++ unsigned ff_read(const unsigned P, const unsigned cycleCounter) { + return P < 0xFF80 ? nontrivial_ff_read(P, cycleCounter) : ioamhram[P - 0xFE00]; + } + +- unsigned read(const unsigned P, const unsigned long cycleCounter) { ++ unsigned read(const unsigned P, const unsigned cycleCounter) { + return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_read(P, cycleCounter); + } + +- void write(const unsigned P, const unsigned data, const unsigned long cycleCounter) { ++ void write(const unsigned P, const unsigned data, const unsigned cycleCounter) { + if (cart.wmem(P >> 12)) { + cart.wmem(P >> 12)[P] = data; + } else + nontrivial_write(P, data, cycleCounter); + } + +- void ff_write(const unsigned P, const unsigned data, const unsigned long cycleCounter) { ++ void ff_write(const unsigned P, const unsigned data, const unsigned cycleCounter) { + if (P - 0xFF80u < 0x7Fu) { + ioamhram[P - 0xFE00] = data; + } else + nontrivial_ff_write(P, data, cycleCounter); + } + +- unsigned long event(unsigned long cycleCounter); +- unsigned long resetCounters(unsigned long cycleCounter); ++ unsigned event(unsigned cycleCounter); ++ unsigned resetCounters(unsigned cycleCounter); + + int loadROM(const std::string &romfile, bool forceDmg, bool multicartCompat); ++ int loadROM(const unsigned char* image, size_t isize, bool forceDmg, bool multicartCompat); + void setSaveDir(const std::string &dir) { cart.setSaveDir(dir); } + + void setInputGetter(InputGetter *getInput) { + this->getInput = getInput; + } + +- void setEndtime(unsigned long cc, unsigned long inc); ++ void setEndtime(unsigned cc, unsigned inc); + + void setSoundBuffer(uint_least32_t *const buf) { sound.setBuffer(buf); } +- unsigned fillSoundBuffer(unsigned long cc); ++ unsigned fillSoundBuffer(unsigned cc); + + void setVideoBuffer(uint_least32_t *const videoBuf, const int pitch) { +- display.setVideoBuffer(videoBuf, pitch); ++ videoBuf_ = videoBuf; ++ pitch_ = pitch; + } + +- void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long rgb32); ++ void setDmgPaletteColor(unsigned palNum, unsigned colorNum, uint_least32_t rgb32); + void setGameGenie(const std::string &codes) { cart.setGameGenie(codes); } + void setGameShark(const std::string &codes) { interrupter.setGameShark(codes); } ++ ++ void setRtcBase(time_t time) { cart.setRtcBase(time); } ++ time_t getRtcBase() { return cart.getRtcBase(); } ++ std::pair getWorkRam() { return cart.getWorkRam(); } ++ std::pair getSaveRam() { return cart.getSaveRam(); } ++ std::pair getIoRam() { return std::make_pair(ioamhram, sizeof(ioamhram)); } ++ std::pair getVideoRam() { return std::make_pair(vram, sizeof(vram)); }; ++ + }; + + } +diff --git a/libgambatte/src/minkeeper.h b/libgambatte/src/minkeeper.h +index e745007..7a2bdf8 100644 +--- a/libgambatte/src/minkeeper.h ++++ b/libgambatte/src/minkeeper.h +@@ -19,7 +19,12 @@ + #ifndef MINKEEPER_H + #define MINKEEPER_H + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + #include ++#include "loadsave.h" + + namespace MinKeeperUtil { + template struct CeiledLog2 { enum { RESULT = 1 + CeiledLog2<(n + 1) / 2>::RESULT }; }; +@@ -74,35 +79,42 @@ class MinKeeper { + }; + + +- unsigned long values[ids]; +- unsigned long minValue_; ++ unsigned values[ids]; ++ unsigned minValue_; + void (*updateValueLut[Num::RESULT])(MinKeeper*); + int a[Sum::RESULT]; + + template static void updateValue(MinKeeper *s); + + public: +- explicit MinKeeper(unsigned long initValue = 0xFFFFFFFF); +- ++ explicit MinKeeper(unsigned initValue = 0xFFFFFFFFULL); ++ ++ void loadOrSave(gambatte::loadsave& state) { ++ state(values, ids); ++ state(minValue_); ++ //updateValueLut is constant for our purposes. ++ state(a, Sum::RESULT); ++ } ++ + int min() const { return a[0]; } +- unsigned long minValue() const { return minValue_; } ++ unsigned minValue() const { return minValue_; } + + template +- void setValue(const unsigned long cnt) { ++ void setValue(const unsigned cnt) { + values[id] = cnt; + updateValue(this); + } + +- void setValue(const int id, const unsigned long cnt) { ++ void setValue(const int id, const unsigned cnt) { + values[id] = cnt; + updateValueLut[id >> 1](this); + } + +- unsigned long value(const int id) const { return values[id]; } ++ unsigned value(const int id) const { return values[id]; } + }; + + template +-MinKeeper::MinKeeper(const unsigned long initValue) { ++MinKeeper::MinKeeper(const unsigned initValue) { + std::fill(values, values + ids, initValue); + + for (int i = 0; i < Num::RESULT; ++i) { +diff --git a/libgambatte/src/savestate.h b/libgambatte/src/savestate.h +index 1916c90..d85220d 100644 +--- a/libgambatte/src/savestate.h ++++ b/libgambatte/src/savestate.h +@@ -19,6 +19,12 @@ + #ifndef SAVESTATE_H + #define SAVESTATE_H + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ ++#include ++ + namespace gambatte { + + class SaverList; +@@ -27,20 +33,20 @@ struct SaveState { + template + class Ptr { + T *ptr; +- unsigned long sz; ++ unsigned sz; + + public: + Ptr() : ptr(0), sz(0) {} + const T* get() const { return ptr; } +- unsigned long getSz() const { return sz; } +- void set(T *ptr, const unsigned long sz) { this->ptr = ptr; this->sz = sz; } ++ unsigned getSz() const { return sz; } ++ void set(T *ptr, const unsigned sz) { this->ptr = ptr; this->sz = sz; } + + friend class SaverList; +- friend void setInitState(SaveState &, bool, bool); ++ friend void setInitState(SaveState &, bool, bool, time_t); + }; + + struct CPU { +- unsigned long cycleCounter; ++ unsigned cycleCounter; + unsigned short PC; + unsigned short SP; + unsigned char A; +@@ -59,13 +65,13 @@ struct SaveState { + Ptr sram; + Ptr wram; + Ptr ioamhram; +- unsigned long divLastUpdate; +- unsigned long timaLastUpdate; +- unsigned long tmatime; +- unsigned long nextSerialtime; +- unsigned long lastOamDmaUpdate; +- unsigned long minIntTime; +- unsigned long unhaltTime; ++ unsigned divLastUpdate; ++ unsigned timaLastUpdate; ++ unsigned tmatime; ++ unsigned nextSerialtime; ++ unsigned lastOamDmaUpdate; ++ unsigned minIntTime; ++ unsigned unhaltTime; + unsigned short rombank; + unsigned short dmaSource; + unsigned short dmaDestination; +@@ -85,8 +91,8 @@ struct SaveState { + Ptr oamReaderBuf; + Ptr oamReaderSzbuf; + +- unsigned long videoCycles; +- unsigned long enableDisplayM0Time; ++ unsigned videoCycles; ++ unsigned enableDisplayM0Time; + unsigned short lastM0Time; + unsigned short nextM0Irq; + unsigned short tileword; +@@ -115,24 +121,24 @@ struct SaveState { + + struct SPU { + struct Duty { +- unsigned long nextPosUpdate; ++ unsigned nextPosUpdate; + unsigned char nr3; + unsigned char pos; + }; + + struct Env { +- unsigned long counter; ++ unsigned counter; + unsigned char volume; + }; + + struct LCounter { +- unsigned long counter; ++ unsigned counter; + unsigned short lengthCounter; + }; + + struct { + struct { +- unsigned long counter; ++ unsigned counter; + unsigned short shadow; + unsigned char nr0; + bool negging; +@@ -155,8 +161,8 @@ struct SaveState { + struct { + Ptr waveRam; + LCounter lcounter; +- unsigned long waveCounter; +- unsigned long lastReadTime; ++ unsigned waveCounter; ++ unsigned lastReadTime; + unsigned char nr3; + unsigned char nr4; + unsigned char wavePos; +@@ -166,7 +172,7 @@ struct SaveState { + + struct { + struct { +- unsigned long counter; ++ unsigned counter; + unsigned short reg; + } lfsr; + Env env; +@@ -175,12 +181,12 @@ struct SaveState { + bool master; + } ch4; + +- unsigned long cycleCounter; ++ unsigned cycleCounter; + } spu; + + struct RTC { +- unsigned long baseTime; +- unsigned long haltTime; ++ unsigned baseTime; ++ unsigned haltTime; + unsigned char dataDh; + unsigned char dataDl; + unsigned char dataH; +diff --git a/libgambatte/src/sound.cpp b/libgambatte/src/sound.cpp +index 14d994e..5bf1e81 100644 +--- a/libgambatte/src/sound.cpp ++++ b/libgambatte/src/sound.cpp +@@ -21,6 +21,10 @@ + #include + #include + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + /* + Frame Sequencer + +@@ -89,7 +93,7 @@ void PSG::loadState(const SaveState &state) { + enabled = state.mem.ioamhram.get()[0x126] >> 7 & 1; + } + +-void PSG::accumulate_channels(const unsigned long cycles) { ++void PSG::accumulate_channels(const unsigned cycles) { + uint_least32_t *const buf = buffer + bufferPos; + + std::memset(buf, 0, cycles * sizeof(uint_least32_t)); +@@ -99,17 +103,16 @@ void PSG::accumulate_channels(const unsigned long cycles) { + ch4.update(buf, soVol, cycles); + } + +-void PSG::generate_samples(const unsigned long cycleCounter, const unsigned doubleSpeed) { +- const unsigned long cycles = (cycleCounter - lastUpdate) >> (1 + doubleSpeed); ++void PSG::generate_samples(const unsigned cycleCounter, const unsigned doubleSpeed) { ++ const unsigned cycles = (cycleCounter - lastUpdate) >> (1 + doubleSpeed); + lastUpdate += cycles << (1 + doubleSpeed); +- + if (cycles) + accumulate_channels(cycles); + + bufferPos += cycles; + } + +-void PSG::resetCounter(const unsigned long newCc, const unsigned long oldCc, const unsigned doubleSpeed) { ++void PSG::resetCounter(const unsigned newCc, const unsigned oldCc, const unsigned doubleSpeed) { + generate_samples(oldCc, doubleSpeed); + lastUpdate = newCc - (oldCc - lastUpdate); + } +@@ -155,11 +158,11 @@ unsigned PSG::fillBuffer() { + } + + #ifdef WORDS_BIGENDIAN +-static const unsigned long so1Mul = 0x00000001; +-static const unsigned long so2Mul = 0x00010000; ++static const unsigned so1Mul = 0x00000001; ++static const unsigned so2Mul = 0x00010000; + #else +-static const unsigned long so1Mul = 0x00010000; +-static const unsigned long so2Mul = 0x00000001; ++static const unsigned so1Mul = 0x00010000; ++static const unsigned so2Mul = 0x00000001; + #endif + + void PSG::set_so_volume(const unsigned nr50) { +@@ -167,7 +170,7 @@ void PSG::set_so_volume(const unsigned nr50) { + } + + void PSG::map_so(const unsigned nr51) { +- const unsigned long tmp = nr51 * so1Mul + (nr51 >> 4) * so2Mul; ++ const unsigned tmp = nr51 * so1Mul + (nr51 >> 4) * so2Mul; + + ch1.setSo((tmp & 0x00010001) * 0xFFFF); + ch2.setSo((tmp >> 1 & 0x00010001) * 0xFFFF); +@@ -179,4 +182,17 @@ unsigned PSG::getStatus() const { + return ch1.isActive() | ch2.isActive() << 1 | ch3.isActive() << 2 | ch4.isActive() << 3; + } + ++void PSG::loadOrSave(loadsave& state) ++{ ++ ch1.loadOrSave(state); ++ ch2.loadOrSave(state); ++ ch3.loadOrSave(state); ++ ch4.loadOrSave(state); ++ state(lastUpdate); ++ state(soVol); ++ state(rsum); ++ state(bufferPos); ++ state(enabled); ++} ++ + } +diff --git a/libgambatte/src/sound.h b/libgambatte/src/sound.h +index 71d5cdc..7fd3f82 100644 +--- a/libgambatte/src/sound.h ++++ b/libgambatte/src/sound.h +@@ -19,10 +19,15 @@ + #ifndef SOUND_H + #define SOUND_H + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + #include "sound/channel1.h" + #include "sound/channel2.h" + #include "sound/channel3.h" + #include "sound/channel4.h" ++#include "loadsave.h" + + namespace gambatte { + +@@ -34,8 +39,8 @@ class PSG { + + uint_least32_t *buffer; + +- unsigned long lastUpdate; +- unsigned long soVol; ++ unsigned lastUpdate; ++ unsigned soVol; + + uint_least32_t rsum; + +@@ -43,7 +48,7 @@ class PSG { + + bool enabled; + +- void accumulate_channels(unsigned long cycles); ++ void accumulate_channels(unsigned cycles); + + public: + PSG(); +@@ -53,8 +58,10 @@ public: + void saveState(SaveState &state); + void loadState(const SaveState &state); + +- void generate_samples(unsigned long cycleCounter, unsigned doubleSpeed); +- void resetCounter(unsigned long newCc, unsigned long oldCc, unsigned doubleSpeed); ++ void loadOrSave(loadsave& state); ++ ++ void generate_samples(unsigned cycleCounter, unsigned doubleSpeed); ++ void resetCounter(unsigned newCc, unsigned oldCc, unsigned doubleSpeed); + unsigned fillBuffer(); + void setBuffer(uint_least32_t *const buf) { buffer = buf; bufferPos = 0; } + +diff --git a/libgambatte/src/sound/channel1.cpp b/libgambatte/src/sound/channel1.cpp +index 82e623a..e282d0a 100644 +--- a/libgambatte/src/sound/channel1.cpp ++++ b/libgambatte/src/sound/channel1.cpp +@@ -20,6 +20,9 @@ + #include "../savestate.h" + #include + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. + + namespace gambatte { + +@@ -47,7 +50,7 @@ unsigned Channel1::SweepUnit::calcFreq() { + } + + void Channel1::SweepUnit::event() { +- const unsigned long period = nr0 >> 4 & 0x07; ++ const unsigned period = nr0 >> 4 & 0x07; + + if (period) { + const unsigned freq = calcFreq(); +@@ -70,7 +73,7 @@ void Channel1::SweepUnit::nr0Change(const unsigned newNr0) { + nr0 = newNr0; + } + +-void Channel1::SweepUnit::nr4Init(const unsigned long cc) { ++void Channel1::SweepUnit::nr4Init(const unsigned cc) { + negging = false; + shadow = dutyUnit.getFreq(); + +@@ -172,7 +175,7 @@ void Channel1::setNr4(const unsigned data) { + setEvent(); + } + +-void Channel1::setSo(const unsigned long soMask) { ++void Channel1::setSo(const unsigned soMask) { + this->soMask = soMask; + staticOutputTest(cycleCounter); + setEvent(); +@@ -215,15 +218,15 @@ void Channel1::loadState(const SaveState &state) { + master = state.spu.ch1.master; + } + +-void Channel1::update(uint_least32_t *buf, const unsigned long soBaseVol, unsigned long cycles) { +- const unsigned long outBase = envelopeUnit.dacIsOn() ? soBaseVol & soMask : 0; +- const unsigned long outLow = outBase * (0 - 15ul); +- const unsigned long endCycles = cycleCounter + cycles; ++void Channel1::update(uint_least32_t *buf, const unsigned soBaseVol, unsigned cycles) { ++ const unsigned outBase = envelopeUnit.dacIsOn() ? soBaseVol & soMask : 0; ++ const unsigned outLow = outBase * (0 - 15ul); ++ const unsigned endCycles = cycleCounter + cycles; + + for (;;) { +- const unsigned long outHigh = master ? outBase * (envelopeUnit.getVolume() * 2 - 15ul) : outLow; +- const unsigned long nextMajorEvent = nextEventUnit->getCounter() < endCycles ? nextEventUnit->getCounter() : endCycles; +- unsigned long out = dutyUnit.isHighState() ? outHigh : outLow; ++ const unsigned outHigh = master ? outBase * (envelopeUnit.getVolume() * 2 - 15ul) : outLow; ++ const unsigned nextMajorEvent = nextEventUnit->getCounter() < endCycles ? nextEventUnit->getCounter() : endCycles; ++ unsigned out = dutyUnit.isHighState() ? outHigh : outLow; + + while (dutyUnit.getCounter() <= nextMajorEvent) { + *buf = out - prevOut; +@@ -259,4 +262,25 @@ void Channel1::update(uint_least32_t *buf, const unsigned long soBaseVol, unsign + } + } + ++void Channel1::loadOrSave(loadsave& state) { ++ //disableMaster has no state. ++ lengthCounter.loadOrSave(state); ++ dutyUnit.loadOrSave(state); ++ envelopeUnit.loadOrSave(state); ++ sweepUnit.loadOrSave(state); ++ ++ state.startEnumeration(); ++ state.enumerate(nextEventUnit, NULL, 0); ++ state.enumerate(nextEventUnit, &sweepUnit, 1); ++ state.enumerate(nextEventUnit, &envelopeUnit, 2); ++ state.enumerate(nextEventUnit, &lengthCounter, 3); ++ state.endEnumeration(); ++ ++ state(cycleCounter); ++ state(soMask); ++ state(prevOut); ++ state(nr4); ++ state(master); ++} ++ + } +diff --git a/libgambatte/src/sound/channel1.h b/libgambatte/src/sound/channel1.h +index 9c77277..780f02d 100644 +--- a/libgambatte/src/sound/channel1.h ++++ b/libgambatte/src/sound/channel1.h +@@ -19,12 +19,17 @@ + #ifndef SOUND_CHANNEL1_H + #define SOUND_CHANNEL1_H + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + #include "gbint.h" + #include "master_disabler.h" + #include "length_counter.h" + #include "duty_unit.h" + #include "envelope_unit.h" + #include "static_output_tester.h" ++#include "loadsave.h" + + namespace gambatte { + +@@ -44,10 +49,15 @@ class Channel1 { + SweepUnit(MasterDisabler &disabler, DutyUnit &dutyUnit); + void event(); + void nr0Change(unsigned newNr0); +- void nr4Init(unsigned long cycleCounter); ++ void nr4Init(unsigned cycleCounter); + void reset(); + void saveState(SaveState &state) const; + void loadState(const SaveState &state); ++ void loadOrSave(loadsave& state) { ++ state(shadow); ++ state(nr0); ++ state(negging); ++ } + }; + + friend class StaticOutputTester; +@@ -61,9 +71,9 @@ class Channel1 { + + SoundUnit *nextEventUnit; + +- unsigned long cycleCounter; +- unsigned long soMask; +- unsigned long prevOut; ++ unsigned cycleCounter; ++ unsigned soMask; ++ unsigned prevOut; + + unsigned char nr4; + bool master; +@@ -78,15 +88,17 @@ public: + void setNr3(unsigned data); + void setNr4(unsigned data); + +- void setSo(unsigned long soMask); ++ void setSo(unsigned soMask); + bool isActive() const { return master; } + +- void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles); ++ void update(uint_least32_t *buf, unsigned soBaseVol, unsigned cycles); + + void reset(); + void init(bool cgb); + void saveState(SaveState &state); + void loadState(const SaveState &state); ++ ++ void loadOrSave(loadsave& state); + }; + + } +diff --git a/libgambatte/src/sound/channel2.cpp b/libgambatte/src/sound/channel2.cpp +index 91e15ee..16905bd 100644 +--- a/libgambatte/src/sound/channel2.cpp ++++ b/libgambatte/src/sound/channel2.cpp +@@ -19,6 +19,10 @@ + #include "channel2.h" + #include "../savestate.h" + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + namespace gambatte { + + Channel2::Channel2() : +@@ -80,7 +84,7 @@ void Channel2::setNr4(const unsigned data) { + setEvent(); + } + +-void Channel2::setSo(const unsigned long soMask) { ++void Channel2::setSo(const unsigned soMask) { + this->soMask = soMask; + staticOutputTest(cycleCounter); + setEvent(); +@@ -119,16 +123,15 @@ void Channel2::loadState(const SaveState &state) { + master = state.spu.ch2.master; + } + +-void Channel2::update(uint_least32_t *buf, const unsigned long soBaseVol, unsigned long cycles) { +- const unsigned long outBase = envelopeUnit.dacIsOn() ? soBaseVol & soMask : 0; +- const unsigned long outLow = outBase * (0 - 15ul); +- const unsigned long endCycles = cycleCounter + cycles; ++void Channel2::update(uint_least32_t *buf, const unsigned soBaseVol, unsigned cycles) { ++ const unsigned outBase = envelopeUnit.dacIsOn() ? soBaseVol & soMask : 0; ++ const unsigned outLow = outBase * (0 - 15ul); ++ const unsigned endCycles = cycleCounter + cycles; + + for (;;) { +- const unsigned long outHigh = master ? outBase * (envelopeUnit.getVolume() * 2 - 15ul) : outLow; +- const unsigned long nextMajorEvent = nextEventUnit->getCounter() < endCycles ? nextEventUnit->getCounter() : endCycles; +- unsigned long out = dutyUnit.isHighState() ? outHigh : outLow; +- ++ const unsigned outHigh = master ? outBase * (envelopeUnit.getVolume() * 2 - 15ul) : outLow; ++ const unsigned nextMajorEvent = nextEventUnit->getCounter() < endCycles ? nextEventUnit->getCounter() : endCycles; ++ unsigned out = dutyUnit.isHighState() ? outHigh : outLow; + while (dutyUnit.getCounter() <= nextMajorEvent) { + *buf += out - prevOut; + prevOut = out; +@@ -162,4 +165,24 @@ void Channel2::update(uint_least32_t *buf, const unsigned long soBaseVol, unsign + } + } + ++void Channel2::loadOrSave(loadsave& state) ++{ ++ //disableMaster has no state. ++ lengthCounter.loadOrSave(state); ++ dutyUnit.loadOrSave(state); ++ envelopeUnit.loadOrSave(state); ++ ++ state.startEnumeration(); ++ state.enumerate(nextEventUnit, NULL, 0); ++ state.enumerate(nextEventUnit, &lengthCounter, 1); ++ state.enumerate(nextEventUnit, &envelopeUnit, 2); ++ state.endEnumeration(); ++ ++ state(cycleCounter); ++ state(soMask); ++ state(prevOut); ++ state(nr4); ++ state(master); ++} ++ + } +diff --git a/libgambatte/src/sound/channel2.h b/libgambatte/src/sound/channel2.h +index d6ba821..b654da9 100644 +--- a/libgambatte/src/sound/channel2.h ++++ b/libgambatte/src/sound/channel2.h +@@ -24,6 +24,11 @@ + #include "duty_unit.h" + #include "envelope_unit.h" + #include "static_output_tester.h" ++#include "loadsave.h" ++ ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. + + namespace gambatte { + +@@ -40,9 +45,9 @@ class Channel2 { + + SoundUnit *nextEventUnit; + +- unsigned long cycleCounter; +- unsigned long soMask; +- unsigned long prevOut; ++ unsigned cycleCounter; ++ unsigned soMask; ++ unsigned prevOut; + + unsigned char nr4; + bool master; +@@ -56,16 +61,18 @@ public: + void setNr3(unsigned data); + void setNr4(unsigned data); + +- void setSo(unsigned long soMask); ++ void setSo(unsigned soMask); + // void deactivate() { disableMaster(); setEvent(); } + bool isActive() const { return master; } + +- void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles); ++ void update(uint_least32_t *buf, unsigned soBaseVol, unsigned cycles); + + void reset(); + void init(bool cgb); + void saveState(SaveState &state); + void loadState(const SaveState &state); ++ ++ void loadOrSave(loadsave& state); + }; + + } +diff --git a/libgambatte/src/sound/channel3.cpp b/libgambatte/src/sound/channel3.cpp +index a1bde94..a3f3aa4 100644 +--- a/libgambatte/src/sound/channel3.cpp ++++ b/libgambatte/src/sound/channel3.cpp +@@ -21,6 +21,10 @@ + #include + #include + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + static inline unsigned toPeriod(const unsigned nr3, const unsigned nr4) { + return 0x800 - ((nr4 << 8 & 0x700) | nr3); + } +@@ -80,7 +84,7 @@ void Channel3::setNr4(const unsigned data) { + } + } + +-void Channel3::setSo(const unsigned long soMask) { ++void Channel3::setSo(const unsigned soMask) { + this->soMask = soMask; + } + +@@ -128,10 +132,10 @@ void Channel3::loadState(const SaveState &state) { + setNr2(state.mem.ioamhram.get()[0x11C]); + } + +-void Channel3::updateWaveCounter(const unsigned long cc) { ++void Channel3::updateWaveCounter(const unsigned cc) { + if (cc >= waveCounter) { + const unsigned period = toPeriod(nr3, nr4); +- const unsigned long periods = (cc - waveCounter) / period; ++ const unsigned periods = (cc - waveCounter) / period; + + lastReadTime = waveCounter + periods * period; + waveCounter = lastReadTime + period; +@@ -143,15 +147,15 @@ void Channel3::updateWaveCounter(const unsigned long cc) { + } + } + +-void Channel3::update(uint_least32_t *buf, const unsigned long soBaseVol, unsigned long cycles) { +- const unsigned long outBase = (nr0/* & 0x80*/) ? soBaseVol & soMask : 0; ++void Channel3::update(uint_least32_t *buf, const unsigned soBaseVol, unsigned cycles) { ++ const unsigned outBase = (nr0/* & 0x80*/) ? soBaseVol & soMask : 0; + + if (outBase && rShift != 4) { +- const unsigned long endCycles = cycleCounter + cycles; ++ const unsigned endCycles = cycleCounter + cycles; + + for (;;) { +- const unsigned long nextMajorEvent = lengthCounter.getCounter() < endCycles ? lengthCounter.getCounter() : endCycles; +- unsigned long out = outBase * (master ? ((sampleBuf >> (~wavePos << 2 & 4) & 0xF) >> rShift) * 2 - 15ul : 0 - 15ul); ++ const unsigned nextMajorEvent = lengthCounter.getCounter() < endCycles ? lengthCounter.getCounter() : endCycles; ++ unsigned out = outBase * (master ? ((sampleBuf >> (~wavePos << 2 & 4) & 0xF) >> rShift) * 2 - 15ul : 0 - 15ul); + + while (waveCounter <= nextMajorEvent) { + *buf += out - prevOut; +@@ -181,7 +185,7 @@ void Channel3::update(uint_least32_t *buf, const unsigned long soBaseVol, unsign + } + } else { + if (outBase) { +- const unsigned long out = outBase * (0 - 15ul); ++ const unsigned out = outBase * (0 - 15ul); + + *buf += out - prevOut; + prevOut = out; +@@ -208,4 +212,23 @@ void Channel3::update(uint_least32_t *buf, const unsigned long soBaseVol, unsign + } + } + ++void Channel3::loadOrSave(loadsave& state) { ++ state(waveRam, 0x10); ++ //disableMaster has no saveable state. ++ lengthCounter.loadOrSave(state); ++ state(cycleCounter); ++ state(soMask); ++ state(prevOut); ++ state(waveCounter); ++ state(lastReadTime); ++ state(nr0); ++ state(nr3); ++ state(nr4); ++ state(wavePos); ++ state(rShift); ++ state(sampleBuf); ++ state(master); ++ state(cgb); ++} ++ + } +diff --git a/libgambatte/src/sound/channel3.h b/libgambatte/src/sound/channel3.h +index e80ec68..8fe0fe3 100644 +--- a/libgambatte/src/sound/channel3.h ++++ b/libgambatte/src/sound/channel3.h +@@ -19,9 +19,14 @@ + #ifndef SOUND_CHANNEL3_H + #define SOUND_CHANNEL3_H + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + #include "gbint.h" + #include "master_disabler.h" + #include "length_counter.h" ++#include "loadsave.h" + + namespace gambatte { + +@@ -29,10 +34,10 @@ struct SaveState; + + class Channel3 { + class Ch3MasterDisabler : public MasterDisabler { +- unsigned long &waveCounter; ++ unsigned &waveCounter; + + public: +- Ch3MasterDisabler(bool &m, unsigned long &wC) : MasterDisabler(m), waveCounter(wC) {} ++ Ch3MasterDisabler(bool &m, unsigned &wC) : MasterDisabler(m), waveCounter(wC) {} + void operator()() { MasterDisabler::operator()(); waveCounter = SoundUnit::COUNTER_DISABLED; } + }; + +@@ -41,11 +46,11 @@ class Channel3 { + Ch3MasterDisabler disableMaster; + LengthCounter lengthCounter; + +- unsigned long cycleCounter; +- unsigned long soMask; +- unsigned long prevOut; +- unsigned long waveCounter; +- unsigned long lastReadTime; ++ unsigned cycleCounter; ++ unsigned soMask; ++ unsigned prevOut; ++ unsigned waveCounter; ++ unsigned lastReadTime; + + unsigned char nr0; + unsigned char nr3; +@@ -57,7 +62,7 @@ class Channel3 { + bool master; + bool cgb; + +- void updateWaveCounter(unsigned long cc); ++ void updateWaveCounter(unsigned cc); + + public: + Channel3(); +@@ -72,8 +77,8 @@ public: + void setNr2(unsigned data); + void setNr3(unsigned data) { nr3 = data; } + void setNr4(unsigned data); +- void setSo(unsigned long soMask); +- void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles); ++ void setSo(unsigned soMask); ++ void update(uint_least32_t *buf, unsigned soBaseVol, unsigned cycles); + + unsigned waveRamRead(unsigned index) const { + if (master) { +@@ -96,6 +101,8 @@ public: + + waveRam[index] = data; + } ++ ++ void loadOrSave(loadsave& state); + }; + + } +diff --git a/libgambatte/src/sound/channel4.cpp b/libgambatte/src/sound/channel4.cpp +index 35c3c00..9d89db7 100644 +--- a/libgambatte/src/sound/channel4.cpp ++++ b/libgambatte/src/sound/channel4.cpp +@@ -20,7 +20,11 @@ + #include "../savestate.h" + #include + +-static unsigned long toPeriod(const unsigned nr3) { ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ ++static unsigned toPeriod(const unsigned nr3) { + unsigned s = (nr3 >> 4) + 3; + unsigned r = nr3 & 7; + +@@ -41,15 +45,15 @@ nr3(0), + master(false) + {} + +-void Channel4::Lfsr::updateBackupCounter(const unsigned long cc) { ++void Channel4::Lfsr::updateBackupCounter(const unsigned cc) { + /*if (backupCounter <= cc) { + const unsigned long period = toPeriod(nr3); + backupCounter = cc - (cc - backupCounter) % period + period; + }*/ + + if (backupCounter <= cc) { +- const unsigned long period = toPeriod(nr3); +- unsigned long periods = (cc - backupCounter) / period + 1; ++ const unsigned period = toPeriod(nr3); ++ unsigned periods = (cc - backupCounter) / period + 1; + + backupCounter += periods * period; + +@@ -75,7 +79,7 @@ void Channel4::Lfsr::updateBackupCounter(const unsigned long cc) { + } + } + +-void Channel4::Lfsr::reviveCounter(const unsigned long cc) { ++void Channel4::Lfsr::reviveCounter(const unsigned cc) { + updateBackupCounter(cc); + counter = backupCounter; + } +@@ -121,7 +125,7 @@ inline void Channel4::Lfsr::event() { + counter += period * nextStateDistance[reg & 0x3F];*/ + } + +-void Channel4::Lfsr::nr3Change(const unsigned newNr3, const unsigned long cc) { ++void Channel4::Lfsr::nr3Change(const unsigned newNr3, const unsigned cc) { + updateBackupCounter(cc); + nr3 = newNr3; + +@@ -129,7 +133,7 @@ void Channel4::Lfsr::nr3Change(const unsigned newNr3, const unsigned long cc) { + // counter = backupCounter + toPeriod(nr3) * (nextStateDistance[reg & 0x3F] - 1); + } + +-void Channel4::Lfsr::nr4Init(unsigned long cc) { ++void Channel4::Lfsr::nr4Init(unsigned cc) { + disableMaster(); + updateBackupCounter(cc); + master = true; +@@ -138,19 +142,19 @@ void Channel4::Lfsr::nr4Init(unsigned long cc) { + // counter = backupCounter + toPeriod(nr3) * (nextStateDistance[reg & 0x3F] - 1); + } + +-void Channel4::Lfsr::reset(const unsigned long cc) { ++void Channel4::Lfsr::reset(const unsigned cc) { + nr3 = 0; + disableMaster(); + backupCounter = cc + toPeriod(nr3); + } + +-void Channel4::Lfsr::resetCounters(const unsigned long oldCc) { ++void Channel4::Lfsr::resetCounters(const unsigned oldCc) { + updateBackupCounter(oldCc); + backupCounter -= COUNTER_MAX; + SoundUnit::resetCounters(oldCc); + } + +-void Channel4::Lfsr::saveState(SaveState &state, const unsigned long cc) { ++void Channel4::Lfsr::saveState(SaveState &state, const unsigned cc) { + updateBackupCounter(cc); + state.spu.ch4.lfsr.counter = backupCounter; + state.spu.ch4.lfsr.reg = reg; +@@ -219,7 +223,7 @@ void Channel4::setNr4(const unsigned data) { + setEvent(); + } + +-void Channel4::setSo(const unsigned long soMask) { ++void Channel4::setSo(const unsigned soMask) { + this->soMask = soMask; + staticOutputTest(cycleCounter); + setEvent(); +@@ -258,15 +262,15 @@ void Channel4::loadState(const SaveState &state) { + master = state.spu.ch4.master; + } + +-void Channel4::update(uint_least32_t *buf, const unsigned long soBaseVol, unsigned long cycles) { +- const unsigned long outBase = envelopeUnit.dacIsOn() ? soBaseVol & soMask : 0; +- const unsigned long outLow = outBase * (0 - 15ul); +- const unsigned long endCycles = cycleCounter + cycles; ++void Channel4::update(uint_least32_t *buf, const unsigned soBaseVol, unsigned cycles) { ++ const unsigned outBase = envelopeUnit.dacIsOn() ? soBaseVol & soMask : 0; ++ const unsigned outLow = outBase * (0 - 15ul); ++ const unsigned endCycles = cycleCounter + cycles; + + for (;;) { +- const unsigned long outHigh = /*master ? */outBase * (envelopeUnit.getVolume() * 2 - 15ul)/* : outLow*/; +- const unsigned long nextMajorEvent = nextEventUnit->getCounter() < endCycles ? nextEventUnit->getCounter() : endCycles; +- unsigned long out = lfsr.isHighState() ? outHigh : outLow; ++ const unsigned outHigh = /*master ? */outBase * (envelopeUnit.getVolume() * 2 - 15ul)/* : outLow*/; ++ const unsigned nextMajorEvent = nextEventUnit->getCounter() < endCycles ? nextEventUnit->getCounter() : endCycles; ++ unsigned out = lfsr.isHighState() ? outHigh : outLow; + + while (lfsr.getCounter() <= nextMajorEvent) { + *buf += out - prevOut; +@@ -301,4 +305,23 @@ void Channel4::update(uint_least32_t *buf, const unsigned long soBaseVol, unsign + } + } + ++void Channel4::loadOrSave(loadsave& state) { ++ //DisableMaster has no state. ++ lengthCounter.loadOrSave(state); ++ envelopeUnit.loadOrSave(state); ++ lfsr.loadOrSave(state); ++ ++ state.startEnumeration(); ++ state.enumerate(nextEventUnit, NULL, 0); ++ state.enumerate(nextEventUnit, &lengthCounter, 1); ++ state.enumerate(nextEventUnit, &envelopeUnit, 2); ++ state.endEnumeration(); ++ ++ state(cycleCounter); ++ state(soMask); ++ state(prevOut); ++ state(nr4); ++ state(master); ++} ++ + } +diff --git a/libgambatte/src/sound/channel4.h b/libgambatte/src/sound/channel4.h +index 00b0b5a..cb923b8 100644 +--- a/libgambatte/src/sound/channel4.h ++++ b/libgambatte/src/sound/channel4.h +@@ -24,6 +24,11 @@ + #include "length_counter.h" + #include "envelope_unit.h" + #include "static_output_tester.h" ++#include "loadsave.h" ++ ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. + + namespace gambatte { + +@@ -31,26 +36,32 @@ struct SaveState; + + class Channel4 { + class Lfsr : public SoundUnit { +- unsigned long backupCounter; ++ unsigned backupCounter; + unsigned short reg; + unsigned char nr3; + bool master; + +- void updateBackupCounter(unsigned long cc); ++ void updateBackupCounter(unsigned cc); + + public: + Lfsr(); + void event(); + bool isHighState() const { return ~reg & 1; } +- void nr3Change(unsigned newNr3, unsigned long cc); +- void nr4Init(unsigned long cc); +- void reset(unsigned long cc); +- void saveState(SaveState &state, const unsigned long cc); ++ void nr3Change(unsigned newNr3, unsigned cc); ++ void nr4Init(unsigned cc); ++ void reset(unsigned cc); ++ void saveState(SaveState &state, const unsigned cc); + void loadState(const SaveState &state); +- void resetCounters(unsigned long oldCc); ++ void resetCounters(unsigned oldCc); + void disableMaster() { killCounter(); master = false; reg = 0xFF; } + void killCounter() { counter = COUNTER_DISABLED; } +- void reviveCounter(unsigned long cc); ++ void reviveCounter(unsigned cc); ++ void loadOrSave(loadsave& state) { ++ state(backupCounter); ++ state(reg); ++ state(nr3); ++ state(master); ++ } + }; + + class Ch4MasterDisabler : public MasterDisabler { +@@ -70,9 +81,9 @@ class Channel4 { + + SoundUnit *nextEventUnit; + +- unsigned long cycleCounter; +- unsigned long soMask; +- unsigned long prevOut; ++ unsigned cycleCounter; ++ unsigned soMask; ++ unsigned prevOut; + + unsigned char nr4; + bool master; +@@ -86,15 +97,17 @@ public: + void setNr3(unsigned data) { lfsr.nr3Change(data, cycleCounter); /*setEvent();*/ } + void setNr4(unsigned data); + +- void setSo(unsigned long soMask); ++ void setSo(unsigned soMask); + bool isActive() const { return master; } + +- void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles); ++ void update(uint_least32_t *buf, unsigned soBaseVol, unsigned cycles); + + void reset(); + void init(bool cgb); + void saveState(SaveState &state); + void loadState(const SaveState &state); ++ ++ void loadOrSave(loadsave& state); + }; + + } +diff --git a/libgambatte/src/sound/duty_unit.cpp b/libgambatte/src/sound/duty_unit.cpp +index 23b8e52..83cedbf 100644 +--- a/libgambatte/src/sound/duty_unit.cpp ++++ b/libgambatte/src/sound/duty_unit.cpp +@@ -19,6 +19,10 @@ + #include "duty_unit.h" + #include + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + static inline bool toOutState(const unsigned duty, const unsigned pos) { + static const unsigned char duties[4] = { 0x80, 0x81, 0xE1, 0x7E }; + +@@ -31,9 +35,9 @@ static inline unsigned toPeriod(const unsigned freq) { + + namespace gambatte { + +-void DutyUnit::updatePos(const unsigned long cc) { ++void DutyUnit::updatePos(const unsigned cc) { + if (cc >= nextPosUpdate) { +- const unsigned long inc = (cc - nextPosUpdate) / period + 1; ++ const unsigned inc = (cc - nextPosUpdate) / period + 1; + nextPosUpdate += period * inc; + pos += inc; + pos &= 7; +@@ -59,7 +63,7 @@ void DutyUnit::setCounter() { + counter = COUNTER_DISABLED; + } + +-void DutyUnit::setFreq(const unsigned newFreq, const unsigned long cc) { ++void DutyUnit::setFreq(const unsigned newFreq, const unsigned cc) { + updatePos(cc); + period = toPeriod(newFreq); + setCounter(); +@@ -77,17 +81,17 @@ void DutyUnit::event() { + counter += inc; + } + +-void DutyUnit::nr1Change(const unsigned newNr1, const unsigned long cc) { ++void DutyUnit::nr1Change(const unsigned newNr1, const unsigned cc) { + updatePos(cc); + setDuty(newNr1); + setCounter(); + } + +-void DutyUnit::nr3Change(const unsigned newNr3, const unsigned long cc) { ++void DutyUnit::nr3Change(const unsigned newNr3, const unsigned cc) { + setFreq((getFreq() & 0x700) | newNr3, cc); + } + +-void DutyUnit::nr4Change(const unsigned newNr4, const unsigned long cc) { ++void DutyUnit::nr4Change(const unsigned newNr4, const unsigned cc) { + setFreq((newNr4 << 8 & 0x700) | (getFreq() & 0xFF), cc); + + if (newNr4 & 0x80) { +@@ -112,14 +116,14 @@ void DutyUnit::reset() { + setCounter(); + } + +-void DutyUnit::saveState(SaveState::SPU::Duty &dstate, const unsigned long cc) { ++void DutyUnit::saveState(SaveState::SPU::Duty &dstate, const unsigned cc) { + updatePos(cc); + dstate.nextPosUpdate = nextPosUpdate; + dstate.nr3 = getFreq() & 0xFF; + dstate.pos = pos; + } + +-void DutyUnit::loadState(const SaveState::SPU::Duty &dstate, const unsigned nr1, const unsigned nr4, const unsigned long cc) { ++void DutyUnit::loadState(const SaveState::SPU::Duty &dstate, const unsigned nr1, const unsigned nr4, const unsigned cc) { + nextPosUpdate = std::max(dstate.nextPosUpdate, cc); + pos = dstate.pos & 7; + setDuty(nr1); +@@ -128,7 +132,7 @@ void DutyUnit::loadState(const SaveState::SPU::Duty &dstate, const unsigned nr1, + setCounter(); + } + +-void DutyUnit::resetCounters(const unsigned long oldCc) { ++void DutyUnit::resetCounters(const unsigned oldCc) { + if (nextPosUpdate == COUNTER_DISABLED) + return; + +@@ -142,11 +146,21 @@ void DutyUnit::killCounter() { + setCounter(); + } + +-void DutyUnit::reviveCounter(const unsigned long cc) { ++void DutyUnit::reviveCounter(const unsigned cc) { + updatePos(cc); + high = toOutState(duty, pos); + enableEvents = true; + setCounter(); + } + ++void DutyUnit::loadOrSave(loadsave& state) { ++ loadOrSave2(state); ++ state(nextPosUpdate); ++ state(period); ++ state(pos); ++ state(duty); ++ state(high); ++ state(enableEvents); ++} ++ + } +diff --git a/libgambatte/src/sound/duty_unit.h b/libgambatte/src/sound/duty_unit.h +index f0fc49c..cf7f3b3 100644 +--- a/libgambatte/src/sound/duty_unit.h ++++ b/libgambatte/src/sound/duty_unit.h +@@ -19,14 +19,19 @@ + #ifndef DUTY_UNIT_H + #define DUTY_UNIT_H + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + #include "sound_unit.h" + #include "master_disabler.h" + #include "../savestate.h" ++#include "../loadsave.h" + + namespace gambatte { + + class DutyUnit : public SoundUnit { +- unsigned long nextPosUpdate; ++ unsigned nextPosUpdate; + unsigned short period; + unsigned char pos; + unsigned char duty; +@@ -35,25 +40,27 @@ class DutyUnit : public SoundUnit { + + void setCounter(); + void setDuty(unsigned nr1); +- void updatePos(unsigned long cc); ++ void updatePos(unsigned cc); + + public: + DutyUnit(); + void event(); + bool isHighState() const { return high; } +- void nr1Change(unsigned newNr1, unsigned long cc); +- void nr3Change(unsigned newNr3, unsigned long cc); +- void nr4Change(unsigned newNr4, unsigned long cc); ++ void nr1Change(unsigned newNr1, unsigned cc); ++ void nr3Change(unsigned newNr3, unsigned cc); ++ void nr4Change(unsigned newNr4, unsigned cc); + void reset(); +- void saveState(SaveState::SPU::Duty &dstate, unsigned long cc); +- void loadState(const SaveState::SPU::Duty &dstate, unsigned nr1, unsigned nr4, unsigned long cc); +- void resetCounters(unsigned long oldCc); ++ void saveState(SaveState::SPU::Duty &dstate, unsigned cc); ++ void loadState(const SaveState::SPU::Duty &dstate, unsigned nr1, unsigned nr4, unsigned cc); ++ void resetCounters(unsigned oldCc); + void killCounter(); +- void reviveCounter(unsigned long cc); +- ++ void reviveCounter(unsigned cc); ++ ++ void loadOrSave(loadsave& state); ++ + //intended for use by SweepUnit only. + unsigned getFreq() const { return 2048 - (period >> 1); } +- void setFreq(unsigned newFreq, unsigned long cc); ++ void setFreq(unsigned newFreq, unsigned cc); + }; + + class DutyMasterDisabler : public MasterDisabler { +diff --git a/libgambatte/src/sound/envelope_unit.cpp b/libgambatte/src/sound/envelope_unit.cpp +index 7bcb783..6036256 100644 +--- a/libgambatte/src/sound/envelope_unit.cpp ++++ b/libgambatte/src/sound/envelope_unit.cpp +@@ -19,12 +19,16 @@ + #include "envelope_unit.h" + #include + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + namespace gambatte { + + EnvelopeUnit::VolOnOffEvent EnvelopeUnit::nullEvent; + + void EnvelopeUnit::event() { +- const unsigned long period = nr2 & 7; ++ const unsigned period = nr2 & 7; + + if (period) { + unsigned newVol = volume; +@@ -63,9 +67,9 @@ bool EnvelopeUnit::nr2Change(const unsigned newNr2) { + return !(newNr2 & 0xF8); + } + +-bool EnvelopeUnit::nr4Init(const unsigned long cc) { ++bool EnvelopeUnit::nr4Init(const unsigned cc) { + { +- unsigned long period = nr2 & 7; ++ unsigned period = nr2 & 7; + + if (!period) + period = 8; +@@ -97,10 +101,17 @@ void EnvelopeUnit::saveState(SaveState::SPU::Env &estate) const { + estate.volume = volume; + } + +-void EnvelopeUnit::loadState(const SaveState::SPU::Env &estate, const unsigned nr2, const unsigned long cc) { ++void EnvelopeUnit::loadState(const SaveState::SPU::Env &estate, const unsigned nr2, const unsigned cc) { + counter = std::max(estate.counter, cc); + volume = estate.volume; + this->nr2 = nr2; + } + ++void EnvelopeUnit::loadOrSave(loadsave& state) ++{ ++ loadOrSave2(state); ++ state(nr2); ++ state(volume); ++} ++ + } +diff --git a/libgambatte/src/sound/envelope_unit.h b/libgambatte/src/sound/envelope_unit.h +index fc2551c..aa0cac4 100644 +--- a/libgambatte/src/sound/envelope_unit.h ++++ b/libgambatte/src/sound/envelope_unit.h +@@ -19,8 +19,13 @@ + #ifndef ENVELOPE_UNIT_H + #define ENVELOPE_UNIT_H + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + #include "sound_unit.h" + #include "../savestate.h" ++#include "../loadsave.h" + + namespace gambatte { + +@@ -28,7 +33,7 @@ class EnvelopeUnit : public SoundUnit { + public: + struct VolOnOffEvent { + virtual ~VolOnOffEvent() {} +- virtual void operator()(unsigned long /*cc*/) {} ++ virtual void operator()(unsigned /*cc*/) {} + }; + + private: +@@ -43,10 +48,11 @@ public: + bool dacIsOn() const { return nr2 & 0xF8; } + unsigned getVolume() const { return volume; } + bool nr2Change(unsigned newNr2); +- bool nr4Init(unsigned long cycleCounter); ++ bool nr4Init(unsigned cycleCounter); + void reset(); + void saveState(SaveState::SPU::Env &estate) const; +- void loadState(const SaveState::SPU::Env &estate, unsigned nr2, unsigned long cc); ++ void loadState(const SaveState::SPU::Env &estate, unsigned nr2, unsigned cc); ++ void loadOrSave(loadsave& state); + }; + + } +diff --git a/libgambatte/src/sound/length_counter.cpp b/libgambatte/src/sound/length_counter.cpp +index d295dc0..0fd9503 100644 +--- a/libgambatte/src/sound/length_counter.cpp ++++ b/libgambatte/src/sound/length_counter.cpp +@@ -20,6 +20,10 @@ + #include "master_disabler.h" + #include + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + namespace gambatte { + + LengthCounter::LengthCounter(MasterDisabler &disabler, const unsigned mask) : +@@ -36,12 +40,12 @@ void LengthCounter::event() { + disableMaster(); + } + +-void LengthCounter::nr1Change(const unsigned newNr1, const unsigned nr4, const unsigned long cycleCounter) { ++void LengthCounter::nr1Change(const unsigned newNr1, const unsigned nr4, const unsigned cycleCounter) { + lengthCounter = (~newNr1 & lengthMask) + 1; +- counter = (nr4 & 0x40) ?( (cycleCounter >> 13) + lengthCounter) << 13 : static_cast(COUNTER_DISABLED); ++ counter = (nr4 & 0x40) ?( (cycleCounter >> 13) + lengthCounter) << 13 : static_cast(COUNTER_DISABLED); + } + +-void LengthCounter::nr4Change(const unsigned oldNr4, const unsigned newNr4, const unsigned long cycleCounter) { ++void LengthCounter::nr4Change(const unsigned oldNr4, const unsigned newNr4, const unsigned cycleCounter) { + if (counter != COUNTER_DISABLED) + lengthCounter = (counter >> 13) - (cycleCounter >> 13); + +@@ -83,9 +87,16 @@ void LengthCounter::saveState(SaveState::SPU::LCounter &lstate) const { + lstate.lengthCounter = lengthCounter; + } + +-void LengthCounter::loadState(const SaveState::SPU::LCounter &lstate, const unsigned long cc) { ++void LengthCounter::loadState(const SaveState::SPU::LCounter &lstate, const unsigned cc) { + counter = std::max(lstate.counter, cc); + lengthCounter = lstate.lengthCounter; + } + ++void LengthCounter::loadOrSave(loadsave& state) ++{ ++ loadOrSave2(state); ++ state(lengthCounter); ++ state(cgb); ++} ++ + } +diff --git a/libgambatte/src/sound/length_counter.h b/libgambatte/src/sound/length_counter.h +index 3360ab1..f21fc9d 100644 +--- a/libgambatte/src/sound/length_counter.h ++++ b/libgambatte/src/sound/length_counter.h +@@ -19,8 +19,13 @@ + #ifndef LENGTH_COUNTER_H + #define LENGTH_COUNTER_H + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + #include "sound_unit.h" + #include "../savestate.h" ++#include "../loadsave.h" + + namespace gambatte { + +@@ -35,12 +40,14 @@ class LengthCounter : public SoundUnit { + public: + LengthCounter(MasterDisabler &disabler, unsigned lengthMask); + void event(); +- void nr1Change(unsigned newNr1, unsigned nr4, unsigned long cc); +- void nr4Change(unsigned oldNr4, unsigned newNr4, unsigned long cc); ++ void nr1Change(unsigned newNr1, unsigned nr4, unsigned cc); ++ void nr4Change(unsigned oldNr4, unsigned newNr4, unsigned cc); + // void reset(); + void init(bool cgb); + void saveState(SaveState::SPU::LCounter &lstate) const; +- void loadState(const SaveState::SPU::LCounter &lstate, unsigned long cc); ++ void loadState(const SaveState::SPU::LCounter &lstate, unsigned cc); ++ ++ void loadOrSave(loadsave& state); + }; + + } +diff --git a/libgambatte/src/sound/sound_unit.h b/libgambatte/src/sound/sound_unit.h +index b1ca691..55b69a9 100644 +--- a/libgambatte/src/sound/sound_unit.h ++++ b/libgambatte/src/sound/sound_unit.h +@@ -19,19 +19,28 @@ + #ifndef SOUND_UNIT_H + #define SOUND_UNIT_H + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ ++#include "../loadsave.h" ++ + namespace gambatte { + + class SoundUnit { + protected: +- unsigned long counter; ++ unsigned counter; + public: + enum { COUNTER_MAX = 0x80000000u, COUNTER_DISABLED = 0xFFFFFFFFu }; + + SoundUnit() : counter(COUNTER_DISABLED) {} + virtual ~SoundUnit() {} + virtual void event() = 0; +- unsigned long getCounter() const { return counter; } +- virtual void resetCounters(unsigned long /*oldCc*/) { if (counter != COUNTER_DISABLED) counter -= COUNTER_MAX; } ++ unsigned getCounter() const { return counter; } ++ virtual void resetCounters(unsigned /*oldCc*/) { if (counter != COUNTER_DISABLED) counter -= COUNTER_MAX; } ++ void loadOrSave2(loadsave& state) { ++ state(counter); ++ } + }; + + } +diff --git a/libgambatte/src/sound/static_output_tester.h b/libgambatte/src/sound/static_output_tester.h +index ac785e5..4ef164f 100644 +--- a/libgambatte/src/sound/static_output_tester.h ++++ b/libgambatte/src/sound/static_output_tester.h +@@ -19,6 +19,10 @@ + #ifndef STATIC_OUTPUT_TESTER_H + #define STATIC_OUTPUT_TESTER_H + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + #include "envelope_unit.h" + + namespace gambatte { +@@ -29,11 +33,11 @@ class StaticOutputTester : public EnvelopeUnit::VolOnOffEvent { + Unit &unit; + public: + StaticOutputTester(const Channel &ch, Unit &unit) : ch(ch), unit(unit) {} +- void operator()(unsigned long cc); ++ void operator()(unsigned cc); + }; + + template +-void StaticOutputTester::operator()(const unsigned long cc) { ++void StaticOutputTester::operator()(const unsigned cc) { + if (ch.soMask && ch.master && ch.envelopeUnit.getVolume()) + unit.reviveCounter(cc); + else +diff --git a/libgambatte/src/state_osd_elements.cpp b/libgambatte/src/state_osd_elements.cpp +index 4ec0c52..ffd91a3 100644 +--- a/libgambatte/src/state_osd_elements.cpp ++++ b/libgambatte/src/state_osd_elements.cpp +@@ -22,6 +22,10 @@ + #include + #include + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + namespace { + + using namespace gambatte; +@@ -71,7 +75,7 @@ life(4 * 60) { + print(pixels + 1 * w() + 1, w(), 0xE0E0E0ul, txt);*/ + + print(pixels, w(), ShadeFill(), txt); +- print(pixels + 1 * w() + 1, w(), 0xE0E0E0ul, txt); ++ print(pixels + 1 * w() + 1, w(), 0xE0E0E0u, txt); + } + + ShadedTextOsdElment::~ShadedTextOsdElment() { +@@ -142,7 +146,7 @@ life(4 * 60) { + + static const char txt[] = { E,m,p,t,bitmapfont::y,0 }; + +- print(pixels + 3 + (StateSaver::SS_HEIGHT / 2 - bitmapfont::HEIGHT / 2) * StateSaver::SS_WIDTH, StateSaver::SS_WIDTH, 0x808080ul, txt); ++ print(pixels + 3 + (StateSaver::SS_HEIGHT / 2 - bitmapfont::HEIGHT / 2) * StateSaver::SS_WIDTH, StateSaver::SS_WIDTH, 0x808080u, txt); + } + } + } +diff --git a/libgambatte/src/statesaver.cpp b/libgambatte/src/statesaver.cpp +index 5d6c313..29fac25 100644 +--- a/libgambatte/src/statesaver.cpp ++++ b/libgambatte/src/statesaver.cpp +@@ -23,6 +23,11 @@ + #include + #include + #include ++#include ++ ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. + + namespace { + +@@ -41,36 +46,36 @@ enum AsciiChar { + + struct Saver { + const char *label; +- void (*save)(std::ofstream &file, const SaveState &state); +- void (*load)(std::ifstream &file, SaveState &state); +- unsigned char labelsize; ++ void (*save)(std::ostream &file, const SaveState &state); ++ void (*load)(std::istream &file, SaveState &state); ++ unsigned int labelsize; + }; + + static inline bool operator<(const Saver &l, const Saver &r) { + return std::strcmp(l.label, r.label) < 0; + } + +-static void put24(std::ofstream &file, const unsigned long data) { ++static void put24(std::ostream &file, const unsigned long data) { + file.put(data >> 16 & 0xFF); + file.put(data >> 8 & 0xFF); + file.put(data & 0xFF); + } + +-static void put32(std::ofstream &file, const unsigned long data) { ++static void put32(std::ostream &file, const unsigned long data) { + file.put(data >> 24 & 0xFF); + file.put(data >> 16 & 0xFF); + file.put(data >> 8 & 0xFF); + file.put(data & 0xFF); + } + +-static void write(std::ofstream &file, const unsigned char data) { ++static void write(std::ostream &file, const unsigned char data) { + static const char inf[] = { 0x00, 0x00, 0x01 }; + + file.write(inf, sizeof(inf)); + file.put(data & 0xFF); + } + +-static void write(std::ofstream &file, const unsigned short data) { ++static void write(std::ostream &file, const unsigned short data) { + static const char inf[] = { 0x00, 0x00, 0x02 }; + + file.write(inf, sizeof(inf)); +@@ -78,30 +83,30 @@ static void write(std::ofstream &file, const unsigned short data) { + file.put(data & 0xFF); + } + +-static void write(std::ofstream &file, const unsigned long data) { ++static void write(std::ostream &file, const unsigned int data) { + static const char inf[] = { 0x00, 0x00, 0x04 }; + + file.write(inf, sizeof(inf)); + put32(file, data); + } + +-static inline void write(std::ofstream &file, const bool data) { ++static inline void write(std::ostream &file, const bool data) { + write(file, static_cast(data)); + } + +-static void write(std::ofstream &file, const unsigned char *data, const unsigned long sz) { ++static void write(std::ostream &file, const unsigned char *data, const unsigned long sz) { + put24(file, sz); + file.write(reinterpret_cast(data), sz); + } + +-static void write(std::ofstream &file, const bool *data, const unsigned long sz) { ++static void write(std::ostream &file, const bool *data, const unsigned long sz) { + put24(file, sz); + + for (unsigned long i = 0; i < sz; ++i) + file.put(data[i]); + } + +-static unsigned long get24(std::ifstream &file) { ++static unsigned long get24(std::istream &file) { + unsigned long tmp = file.get() & 0xFF; + + tmp = tmp << 8 | (file.get() & 0xFF); +@@ -109,15 +114,15 @@ static unsigned long get24(std::ifstream &file) { + return tmp << 8 | (file.get() & 0xFF); + } + +-static unsigned long read(std::ifstream &file) { +- unsigned long size = get24(file); ++static unsigned read(std::istream &file) { ++ unsigned size = get24(file); + + if (size > 4) { + file.ignore(size - 4); + size = 4; + } + +- unsigned long out = 0; ++ unsigned out = 0; + + switch (size) { + case 4: out = (out | (file.get() & 0xFF)) << 8; +@@ -129,23 +134,23 @@ static unsigned long read(std::ifstream &file) { + return out; + } + +-static inline void read(std::ifstream &file, unsigned char &data) { ++static inline void read(std::istream &file, unsigned char &data) { + data = read(file) & 0xFF; + } + +-static inline void read(std::ifstream &file, unsigned short &data) { ++static inline void read(std::istream &file, unsigned short &data) { + data = read(file) & 0xFFFF; + } + +-static inline void read(std::ifstream &file, unsigned long &data) { ++static inline void read(std::istream &file, unsigned int &data) { + data = read(file); + } + +-static inline void read(std::ifstream &file, bool &data) { ++static inline void read(std::istream &file, bool &data) { + data = read(file); + } + +-static void read(std::ifstream &file, unsigned char *data, unsigned long sz) { ++static void read(std::istream &file, unsigned char *data, unsigned long sz) { + const unsigned long size = get24(file); + + if (size < sz) +@@ -160,7 +165,7 @@ static void read(std::ifstream &file, unsigned char *data, unsigned long sz) { + } + } + +-static void read(std::ifstream &file, bool *data, unsigned long sz) { ++static void read(std::istream &file, bool *data, unsigned long sz) { + const unsigned long size = get24(file); + + if (size < sz) +@@ -193,8 +198,8 @@ public: + }; + + static void pushSaver(SaverList::list_t &list, const char *label, +- void (*save)(std::ofstream &file, const SaveState &state), +- void (*load)(std::ifstream &file, SaveState &state), unsigned labelsize) { ++ void (*save)(std::ostream &file, const SaveState &state), ++ void (*load)(std::istream &file, SaveState &state), unsigned labelsize) { + const Saver saver = { label, save, load, labelsize }; + list.push_back(saver); + } +@@ -202,8 +207,8 @@ static void pushSaver(SaverList::list_t &list, const char *label, + SaverList::SaverList() { + #define ADD(arg) do { \ + struct Func { \ +- static void save(std::ofstream &file, const SaveState &state) { write(file, state.arg); } \ +- static void load(std::ifstream &file, SaveState &state) { read(file, state.arg); } \ ++ static void save(std::ostream &file, const SaveState &state) { write(file, state.arg); } \ ++ static void load(std::istream &file, SaveState &state) { read(file, state.arg); } \ + }; \ + \ + pushSaver(list, label, Func::save, Func::load, sizeof label); \ +@@ -211,8 +216,8 @@ SaverList::SaverList() { + + #define ADDPTR(arg) do { \ + struct Func { \ +- static void save(std::ofstream &file, const SaveState &state) { write(file, state.arg.get(), state.arg.getSz()); } \ +- static void load(std::ifstream &file, SaveState &state) { read(file, state.arg.ptr, state.arg.getSz()); } \ ++ static void save(std::ostream &file, const SaveState &state) { write(file, state.arg.get(), state.arg.getSz()); } \ ++ static void load(std::istream &file, SaveState &state) { read(file, state.arg.ptr, state.arg.getSz()); } \ + }; \ + \ + pushSaver(list, label, Func::save, Func::load, sizeof label); \ +@@ -220,8 +225,8 @@ SaverList::SaverList() { + + #define ADDARRAY(arg) do { \ + struct Func { \ +- static void save(std::ofstream &file, const SaveState &state) { write(file, state.arg, sizeof(state.arg)); } \ +- static void load(std::ifstream &file, SaveState &state) { read(file, state.arg, sizeof(state.arg)); } \ ++ static void save(std::ostream &file, const SaveState &state) { write(file, state.arg, sizeof(state.arg)); } \ ++ static void load(std::istream &file, SaveState &state) { read(file, state.arg, sizeof(state.arg)); } \ + }; \ + \ + pushSaver(list, label, Func::save, Func::load, sizeof label); \ +@@ -373,7 +378,7 @@ static void blendPxlPairs(PxlSum *const dst, const PxlSum *const sums) { + dst->g = sums[1].g * 8 + (sums[0].g - sums[1].g ) * 3; + } + +-static void writeSnapShot(std::ofstream &file, const uint_least32_t *pixels, const int pitch) { ++static void writeSnapShot(std::ostream &file, const uint_least32_t *pixels, const int pitch) { + put24(file, pixels ? StateSaver::SS_WIDTH * StateSaver::SS_HEIGHT * sizeof(uint_least32_t) : 0); + + if (pixels) { +@@ -405,15 +410,9 @@ static void writeSnapShot(std::ofstream &file, const uint_least32_t *pixels, con + + static SaverList list; + +-} // anon namespace +- +-namespace gambatte { +- +-void StateSaver::saveState(const SaveState &state, ++void saveStateI(const SaveState &state, + const uint_least32_t *const videoBuf, +- const int pitch, const std::string &filename) { +- std::ofstream file(filename.c_str(), std::ios_base::binary); +- ++ const int pitch, std::ostream& file) { + if (file.fail()) + return; + +@@ -427,9 +426,7 @@ void StateSaver::saveState(const SaveState &state, + } + } + +-bool StateSaver::loadState(SaveState &state, const std::string &filename) { +- std::ifstream file(filename.c_str(), std::ios_base::binary); +- ++bool loadStateI(SaveState &state, std::istream& file) { + if (file.fail() || file.get() != 0) + return false; + +@@ -465,4 +462,36 @@ bool StateSaver::loadState(SaveState &state, const std::string &filename) { + return true; + } + ++} // anon namespace ++ ++namespace gambatte { ++ ++ ++void StateSaver::saveState(const SaveState &state, ++ const uint_least32_t *const videoBuf, ++ const int pitch, const std::string &filename) { ++ std::ofstream file(filename.c_str(), std::ios_base::binary); ++ saveStateI(state, videoBuf, pitch, file); ++} ++ ++bool StateSaver::loadState(SaveState &state, const std::string &filename) { ++ std::ifstream file(filename.c_str(), std::ios_base::binary); ++ return loadStateI(state, file); ++} ++ ++void StateSaver::saveState(const SaveState &state, ++ std::vector& data) { ++ std::ostringstream file; ++ saveStateI(state, NULL, 160, file); ++ std::string out = file.str(); ++ data.resize(out.size()); ++ std::copy(out.begin(), out.end(), data.begin()); ++} ++ ++bool StateSaver::loadState(SaveState &state, const std::vector& data) { ++ std::string in(data.begin(), data.end()); ++ std::istringstream file(in); ++ return loadStateI(state, file); ++} ++ + } +diff --git a/libgambatte/src/statesaver.h b/libgambatte/src/statesaver.h +index 2c58a42..f902403 100644 +--- a/libgambatte/src/statesaver.h ++++ b/libgambatte/src/statesaver.h +@@ -19,8 +19,13 @@ + #ifndef STATESAVER_H + #define STATESAVER_H + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + #include "gbint.h" + #include ++#include + + namespace gambatte { + +@@ -38,6 +43,8 @@ public: + static void saveState(const SaveState &state, + const uint_least32_t *videoBuf, int pitch, const std::string &filename); + static bool loadState(SaveState &state, const std::string &filename); ++ static void saveState(const SaveState &state, std::vector& data); ++ static bool loadState(SaveState &state, const std::vector& data); + }; + + } +diff --git a/libgambatte/src/tima.cpp b/libgambatte/src/tima.cpp +index 44ce31c..56b6e72 100644 +--- a/libgambatte/src/tima.cpp ++++ b/libgambatte/src/tima.cpp +@@ -19,6 +19,10 @@ + #include "tima.h" + #include "savestate.h" + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + static const unsigned char timaClock[4] = { 10, 4, 6, 8 }; + + namespace gambatte { +@@ -50,12 +54,12 @@ void Tima::loadState(const SaveState &state, const TimaInterruptRequester timaIr + ? tmatime_ + : lastUpdate_ + ((256u - tima_) << timaClock[tac_ & 3]) + 3) + : +- static_cast(DISABLED_TIME) ++ static_cast(DISABLED_TIME) + ); + } + +-void Tima::resetCc(const unsigned long oldCc, const unsigned long newCc, const TimaInterruptRequester timaIrq) { +- const unsigned long dec = oldCc - newCc; ++void Tima::resetCc(const unsigned oldCc, const unsigned newCc, const TimaInterruptRequester timaIrq) { ++ const unsigned dec = oldCc - newCc; + + if (tac_ & 0x04) { + updateIrq(oldCc, timaIrq); +@@ -69,8 +73,8 @@ void Tima::resetCc(const unsigned long oldCc, const unsigned long newCc, const T + } + } + +-void Tima::updateTima(const unsigned long cycleCounter) { +- const unsigned long ticks = (cycleCounter - lastUpdate_) >> timaClock[tac_ & 3]; ++void Tima::updateTima(const unsigned cycleCounter) { ++ const unsigned ticks = (cycleCounter - lastUpdate_) >> timaClock[tac_ & 3]; + + lastUpdate_ += ticks << timaClock[tac_ & 3]; + +@@ -81,7 +85,7 @@ void Tima::updateTima(const unsigned long cycleCounter) { + tima_ = tma_; + } + +- unsigned long tmp = tima_ + ticks; ++ unsigned tmp = tima_ + ticks; + + while (tmp > 0x100) + tmp -= 0x100 - tma_; +@@ -101,7 +105,7 @@ void Tima::updateTima(const unsigned long cycleCounter) { + tima_ = tmp; + } + +-void Tima::setTima(const unsigned data, const unsigned long cycleCounter, const TimaInterruptRequester timaIrq) { ++void Tima::setTima(const unsigned data, const unsigned cycleCounter, const TimaInterruptRequester timaIrq) { + if (tac_ & 0x04) { + updateIrq(cycleCounter, timaIrq); + updateTima(cycleCounter); +@@ -115,7 +119,7 @@ void Tima::setTima(const unsigned data, const unsigned long cycleCounter, const + tima_ = data; + } + +-void Tima::setTma(const unsigned data, const unsigned long cycleCounter, const TimaInterruptRequester timaIrq) { ++void Tima::setTma(const unsigned data, const unsigned cycleCounter, const TimaInterruptRequester timaIrq) { + if (tac_ & 0x04) { + updateIrq(cycleCounter, timaIrq); + updateTima(cycleCounter); +@@ -124,9 +128,9 @@ void Tima::setTma(const unsigned data, const unsigned long cycleCounter, const T + tma_ = data; + } + +-void Tima::setTac(const unsigned data, const unsigned long cycleCounter, const TimaInterruptRequester timaIrq) { ++void Tima::setTac(const unsigned data, const unsigned cycleCounter, const TimaInterruptRequester timaIrq) { + if (tac_ ^ data) { +- unsigned long nextIrqEventTime = timaIrq.nextIrqEventTime(); ++ unsigned nextIrqEventTime = timaIrq.nextIrqEventTime(); + + if (tac_ & 0x04) { + updateIrq(cycleCounter, timaIrq); +@@ -156,7 +160,7 @@ void Tima::setTac(const unsigned data, const unsigned long cycleCounter, const T + tac_ = data; + } + +-unsigned Tima::tima(unsigned long cycleCounter) { ++unsigned Tima::tima(unsigned cycleCounter) { + if (tac_ & 0x04) + updateTima(cycleCounter); + +@@ -168,4 +172,13 @@ void Tima::doIrqEvent(const TimaInterruptRequester timaIrq) { + timaIrq.setNextIrqEventTime(timaIrq.nextIrqEventTime() + ((256u - tma_) << timaClock[tac_ & 3])); + } + ++void Tima::loadOrSave(loadsave& state) ++{ ++ state(lastUpdate_); ++ state(tmatime_); ++ state(tima_); ++ state(tma_); ++ state(tac_); ++} ++ + } +diff --git a/libgambatte/src/tima.h b/libgambatte/src/tima.h +index 48e9ccd..2857934 100644 +--- a/libgambatte/src/tima.h ++++ b/libgambatte/src/tima.h +@@ -19,6 +19,10 @@ + #ifndef TIMA_H + #define TIMA_H + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + #include "interruptrequester.h" + + namespace gambatte { +@@ -29,37 +33,39 @@ class TimaInterruptRequester { + public: + explicit TimaInterruptRequester(InterruptRequester &intreq) : intreq(intreq) {} + void flagIrq() const { intreq.flagIrq(4); } +- unsigned long nextIrqEventTime() const { return intreq.eventTime(TIMA); } +- void setNextIrqEventTime(const unsigned long time) const { intreq.setEventTime(time); } ++ unsigned nextIrqEventTime() const { return intreq.eventTime(TIMA); } ++ void setNextIrqEventTime(const unsigned time) const { intreq.setEventTime(time); } + }; + + class Tima { +- unsigned long lastUpdate_; +- unsigned long tmatime_; ++ unsigned lastUpdate_; ++ unsigned tmatime_; + + unsigned char tima_; + unsigned char tma_; + unsigned char tac_; + +- void updateIrq(const unsigned long cc, const TimaInterruptRequester timaIrq) { ++ void updateIrq(const unsigned cc, const TimaInterruptRequester timaIrq) { + while (cc >= timaIrq.nextIrqEventTime()) + doIrqEvent(timaIrq); + } + +- void updateTima(unsigned long cc); ++ void updateTima(unsigned cc); + + public: + Tima(); + void saveState(SaveState &) const; + void loadState(const SaveState &, TimaInterruptRequester timaIrq); +- void resetCc(unsigned long oldCc, unsigned long newCc, TimaInterruptRequester timaIrq); ++ void resetCc(unsigned oldCc, unsigned newCc, TimaInterruptRequester timaIrq); + +- void setTima(unsigned tima, unsigned long cc, TimaInterruptRequester timaIrq); +- void setTma(unsigned tma, unsigned long cc, TimaInterruptRequester timaIrq); +- void setTac(unsigned tac, unsigned long cc, TimaInterruptRequester timaIrq); +- unsigned tima(unsigned long cc); ++ void setTima(unsigned tima, unsigned cc, TimaInterruptRequester timaIrq); ++ void setTma(unsigned tma, unsigned cc, TimaInterruptRequester timaIrq); ++ void setTac(unsigned tac, unsigned cc, TimaInterruptRequester timaIrq); ++ unsigned tima(unsigned cc); + + void doIrqEvent(TimaInterruptRequester timaIrq); ++ ++ void loadOrSave(loadsave& state); + }; + + } +diff --git a/libgambatte/src/video.cpp b/libgambatte/src/video.cpp +index 58fc6c1..b0e5c4e 100644 +--- a/libgambatte/src/video.cpp ++++ b/libgambatte/src/video.cpp +@@ -21,19 +21,23 @@ + #include + #include + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + namespace gambatte { + +-void LCD::setDmgPalette(unsigned long *const palette, const unsigned long *const dmgColors, const unsigned data) { ++void LCD::setDmgPalette(uint_least32_t *const palette, const uint_least32_t *const dmgColors, const unsigned data) { + palette[0] = dmgColors[data & 3]; + palette[1] = dmgColors[data >> 2 & 3]; + palette[2] = dmgColors[data >> 4 & 3]; + palette[3] = dmgColors[data >> 6 & 3]; + } + +-static unsigned long gbcToRgb32(const unsigned bgr15) { +- const unsigned long r = bgr15 & 0x1F; +- const unsigned long g = bgr15 >> 5 & 0x1F; +- const unsigned long b = bgr15 >> 10 & 0x1F; ++static uint_least32_t gbcToRgb32(const unsigned bgr15) { ++ const uint_least32_t r = bgr15 & 0x1F; ++ const uint_least32_t g = bgr15 >> 5 & 0x1F; ++ const uint_least32_t b = bgr15 >> 10 & 0x1F; + + return ((r * 13 + g * 2 + b) >> 1) << 16 | (g * 3 + b) << 9 | (r * 3 + g * 2 + b * 11) >> 1; + } +@@ -80,7 +84,6 @@ LCD::LCD(const unsigned char *const oamram, const unsigned char *const vram, con + setDmgPaletteColor(i, (3 - (i & 3)) * 85 * 0x010101); + + reset(oamram, false); +- setVideoBuffer(0, 160); + } + + void LCD::reset(const unsigned char *const oamram, const bool cgb) { +@@ -89,7 +92,7 @@ void LCD::reset(const unsigned char *const oamram, const bool cgb) { + refreshPalettes(); + } + +-static unsigned long mode2IrqSchedule(const unsigned statReg, const LyCounter &lyCounter, const unsigned long cycleCounter) { ++static unsigned mode2IrqSchedule(const unsigned statReg, const LyCounter &lyCounter, const unsigned cycleCounter) { + if (!(statReg & 0x20)) + return DISABLED_TIME; + +@@ -107,16 +110,16 @@ static unsigned long mode2IrqSchedule(const unsigned statReg, const LyCounter &l + return cycleCounter + next; + } + +-static inline unsigned long m0IrqTimeFromXpos166Time(const unsigned long xpos166Time, const bool cgb, const bool ds) { ++static inline unsigned m0IrqTimeFromXpos166Time(const unsigned xpos166Time, const bool cgb, const bool ds) { + return xpos166Time + cgb - ds; + } + +-static inline unsigned long hdmaTimeFromM0Time(const unsigned long m0Time, const bool ds) { ++static inline unsigned hdmaTimeFromM0Time(const unsigned m0Time, const bool ds) { + return m0Time + 1 - ds; + } + +-static unsigned long nextHdmaTime(const unsigned long lastM0Time, +- const unsigned long nextM0Time, const unsigned long cycleCounter, const bool ds) { ++static unsigned nextHdmaTime(const unsigned lastM0Time, ++ const unsigned nextM0Time, const unsigned cycleCounter, const bool ds) { + return cycleCounter < hdmaTimeFromM0Time(lastM0Time, ds) + ? hdmaTimeFromM0Time(lastM0Time, ds) + : hdmaTimeFromM0Time(nextM0Time, ds); +@@ -152,18 +155,18 @@ void LCD::loadState(const SaveState &state, const unsigned char *const oamram) { + lycIrq.reschedule(ppu.lyCounter(), ppu.now()); + + eventTimes_.setm(state.ppu.pendingLcdstatIrq +- ? ppu.now() + 1 : static_cast(DISABLED_TIME)); ++ ? ppu.now() + 1 : static_cast(DISABLED_TIME)); + eventTimes_.setm(state.ppu.oldWy != state.mem.ioamhram.get()[0x14A] +- ? ppu.now() + 1 : static_cast(DISABLED_TIME)); ++ ? ppu.now() + 1 : static_cast(DISABLED_TIME)); + eventTimes_.set(ppu.lyCounter().time()); + eventTimes_.setm(SpriteMapper::schedule(ppu.lyCounter(), ppu.now())); + eventTimes_.setm(lycIrq.time()); + eventTimes_.setm(ppu.lyCounter().nextFrameCycle(144 * 456, ppu.now())); + eventTimes_.setm(mode2IrqSchedule(statReg, ppu.lyCounter(), ppu.now())); +- eventTimes_.setm((statReg & 0x08) ? ppu.now() + state.ppu.nextM0Irq : static_cast(DISABLED_TIME)); ++ eventTimes_.setm((statReg & 0x08) ? ppu.now() + state.ppu.nextM0Irq : static_cast(DISABLED_TIME)); + eventTimes_.setm(state.mem.hdmaTransfer + ? nextHdmaTime(ppu.lastM0Time(), nextM0Time_.predictedNextM0Time(), ppu.now(), isDoubleSpeed()) +- : static_cast(DISABLED_TIME)); ++ : static_cast(DISABLED_TIME)); + } else for (int i = 0; i < NUM_MEM_EVENTS; ++i) + eventTimes_.set(static_cast(i), DISABLED_TIME); + +@@ -212,7 +215,7 @@ struct Blend { + }; + + template +-static void clear(T *buf, const unsigned long color, const int dpitch) { ++static void clear(T *buf, const uint_least32_t color, const int dpitch) { + unsigned lines = 144; + + while (lines--) { +@@ -223,11 +226,11 @@ static void clear(T *buf, const unsigned long color, const int dpitch) { + + } + +-void LCD::updateScreen(const bool blanklcd, const unsigned long cycleCounter) { ++void LCD::updateScreen(const bool blanklcd, const unsigned cycleCounter, uint_least32_t* vbuffer, unsigned vpitch) { + update(cycleCounter); + + if (blanklcd && ppu.frameBuf().fb()) { +- const unsigned long color = ppu.cgb() ? gbcToRgb32(0xFFFF) : dmgColorsRgb32[0]; ++ const uint_least32_t color = ppu.cgb() ? gbcToRgb32(0xFFFF) : dmgColorsRgb32[0]; + clear(ppu.frameBuf().fb(), color, ppu.frameBuf().pitch()); + } + +@@ -245,14 +248,15 @@ void LCD::updateScreen(const bool blanklcd, const unsigned long cycleCounter) { + } else + osdElement.reset(); + } ++ ppu.frameBuf().blit(vbuffer, vpitch); + } + +-void LCD::resetCc(const unsigned long oldCc, const unsigned long newCc) { ++void LCD::resetCc(const unsigned oldCc, const unsigned newCc) { + update(oldCc); + ppu.resetCc(oldCc, newCc); + + if (ppu.lcdc() & 0x80) { +- const unsigned long dec = oldCc - newCc; ++ const unsigned dec = oldCc - newCc; + + nextM0Time_.invalidatePredictedNextM0Time(); + lycIrq.reschedule(ppu.lyCounter(), newCc); +@@ -266,7 +270,7 @@ void LCD::resetCc(const unsigned long oldCc, const unsigned long newCc) { + } + } + +-void LCD::speedChange(const unsigned long cycleCounter) { ++void LCD::speedChange(const unsigned cycleCounter) { + update(cycleCounter); + ppu.speedChange(cycleCounter); + +@@ -290,13 +294,13 @@ void LCD::speedChange(const unsigned long cycleCounter) { + } + } + +-static inline unsigned long m0TimeOfCurrentLine(const unsigned long nextLyTime, +- const unsigned long lastM0Time, const unsigned long nextM0Time) ++static inline unsigned m0TimeOfCurrentLine(const unsigned nextLyTime, ++ const unsigned lastM0Time, const unsigned nextM0Time) + { + return nextM0Time < nextLyTime ? nextM0Time : lastM0Time; + } + +-unsigned long LCD::m0TimeOfCurrentLine(const unsigned long cc) { ++unsigned LCD::m0TimeOfCurrentLine(const unsigned cc) { + if (cc >= nextM0Time_.predictedNextM0Time()) { + update(cc); + nextM0Time_.predictNextM0Time(ppu); +@@ -306,7 +310,7 @@ unsigned long LCD::m0TimeOfCurrentLine(const unsigned long cc) { + } + + static bool isHdmaPeriod(const LyCounter &lyCounter, +- const unsigned long m0TimeOfCurrentLy, const unsigned long cycleCounter) ++ const unsigned m0TimeOfCurrentLy, const unsigned cycleCounter) + { + const unsigned timeToNextLy = lyCounter.time() - cycleCounter; + +@@ -314,7 +318,7 @@ static bool isHdmaPeriod(const LyCounter &lyCounter, + && cycleCounter >= hdmaTimeFromM0Time(m0TimeOfCurrentLy, lyCounter.isDoubleSpeed()); + } + +-void LCD::enableHdma(const unsigned long cycleCounter) { ++void LCD::enableHdma(const unsigned cycleCounter) { + if (cycleCounter >= nextM0Time_.predictedNextM0Time()) { + update(cycleCounter); + nextM0Time_.predictNextM0Time(ppu); +@@ -330,14 +334,14 @@ void LCD::enableHdma(const unsigned long cycleCounter) { + eventTimes_.setm(nextHdmaTime(ppu.lastM0Time(), nextM0Time_.predictedNextM0Time(), cycleCounter, isDoubleSpeed())); + } + +-void LCD::disableHdma(const unsigned long cycleCounter) { ++void LCD::disableHdma(const unsigned cycleCounter) { + if (cycleCounter >= eventTimes_.nextEventTime()) + update(cycleCounter); + + eventTimes_.setm(DISABLED_TIME); + } + +-bool LCD::vramAccessible(const unsigned long cycleCounter) { ++bool LCD::vramAccessible(const unsigned cycleCounter) { + if (cycleCounter >= eventTimes_.nextEventTime()) + update(cycleCounter); + +@@ -346,7 +350,7 @@ bool LCD::vramAccessible(const unsigned long cycleCounter) { + || cycleCounter + isDoubleSpeed() - ppu.cgb() + 2 >= m0TimeOfCurrentLine(cycleCounter); + } + +-bool LCD::cgbpAccessible(const unsigned long cycleCounter) { ++bool LCD::cgbpAccessible(const unsigned cycleCounter) { + if (cycleCounter >= eventTimes_.nextEventTime()) + update(cycleCounter); + +@@ -356,27 +360,27 @@ bool LCD::cgbpAccessible(const unsigned long cycleCounter) { + } + + static void doCgbColorChange(unsigned char *const pdata, +- unsigned long *const palette, unsigned index, const unsigned data) { ++ uint_least32_t *const palette, unsigned index, const unsigned data) { + pdata[index] = data; + index >>= 1; + palette[index] = gbcToRgb32(pdata[index << 1] | pdata[(index << 1) + 1] << 8); + } + +-void LCD::doCgbBgColorChange(unsigned index, const unsigned data, const unsigned long cycleCounter) { ++void LCD::doCgbBgColorChange(unsigned index, const unsigned data, const unsigned cycleCounter) { + if (cgbpAccessible(cycleCounter)) { + update(cycleCounter); + doCgbColorChange(bgpData, ppu.bgPalette(), index, data); + } + } + +-void LCD::doCgbSpColorChange(unsigned index, const unsigned data, const unsigned long cycleCounter) { ++void LCD::doCgbSpColorChange(unsigned index, const unsigned data, const unsigned cycleCounter) { + if (cgbpAccessible(cycleCounter)) { + update(cycleCounter); + doCgbColorChange(objpData, ppu.spPalette(), index, data); + } + } + +-bool LCD::oamReadable(const unsigned long cycleCounter) { ++bool LCD::oamReadable(const unsigned cycleCounter) { + if (!(ppu.lcdc() & 0x80) || ppu.inactivePeriodAfterDisplayEnable(cycleCounter)) + return true; + +@@ -389,7 +393,7 @@ bool LCD::oamReadable(const unsigned long cycleCounter) { + return ppu.lyCounter().ly() >= 144 || cycleCounter + isDoubleSpeed() - ppu.cgb() + 2 >= m0TimeOfCurrentLine(cycleCounter); + } + +-bool LCD::oamWritable(const unsigned long cycleCounter) { ++bool LCD::oamWritable(const unsigned cycleCounter) { + if (!(ppu.lcdc() & 0x80) || ppu.inactivePeriodAfterDisplayEnable(cycleCounter)) + return true; + +@@ -417,13 +421,13 @@ void LCD::mode3CyclesChange() { + } + } + +-void LCD::wxChange(const unsigned newValue, const unsigned long cycleCounter) { ++void LCD::wxChange(const unsigned newValue, const unsigned cycleCounter) { + update(cycleCounter + isDoubleSpeed() + 1); + ppu.setWx(newValue); + mode3CyclesChange(); + } + +-void LCD::wyChange(const unsigned newValue, const unsigned long cycleCounter) { ++void LCD::wyChange(const unsigned newValue, const unsigned cycleCounter) { + update(cycleCounter + 1); + ppu.setWy(newValue); + // mode3CyclesChange(); // should be safe to wait until after wy2 delay, because no mode3 events are close to when wy1 is read. +@@ -438,18 +442,18 @@ void LCD::wyChange(const unsigned newValue, const unsigned long cycleCounter) { + } + } + +-void LCD::scxChange(const unsigned newScx, const unsigned long cycleCounter) { ++void LCD::scxChange(const unsigned newScx, const unsigned cycleCounter) { + update(cycleCounter + ppu.cgb() + isDoubleSpeed()); + ppu.setScx(newScx); + mode3CyclesChange(); + } + +-void LCD::scyChange(const unsigned newValue, const unsigned long cycleCounter) { ++void LCD::scyChange(const unsigned newValue, const unsigned cycleCounter) { + update(cycleCounter + ppu.cgb() + isDoubleSpeed()); + ppu.setScy(newValue); + } + +-void LCD::oamChange(const unsigned long cycleCounter) { ++void LCD::oamChange(const unsigned cycleCounter) { + if (ppu.lcdc() & 0x80) { + update(cycleCounter); + ppu.oamChange(cycleCounter); +@@ -457,7 +461,7 @@ void LCD::oamChange(const unsigned long cycleCounter) { + } + } + +-void LCD::oamChange(const unsigned char *const oamram, const unsigned long cycleCounter) { ++void LCD::oamChange(const unsigned char *const oamram, const unsigned cycleCounter) { + update(cycleCounter); + ppu.oamChange(oamram, cycleCounter); + +@@ -465,7 +469,7 @@ void LCD::oamChange(const unsigned char *const oamram, const unsigned long cycle + eventTimes_.setm(SpriteMapper::schedule(ppu.lyCounter(), cycleCounter)); + } + +-void LCD::lcdcChange(const unsigned data, const unsigned long cycleCounter) { ++void LCD::lcdcChange(const unsigned data, const unsigned cycleCounter) { + const unsigned oldLcdc = ppu.lcdc(); + update(cycleCounter); + +@@ -522,7 +526,7 @@ void LCD::lcdcChange(const unsigned data, const unsigned long cycleCounter) { + ppu.setLcdc(data, cycleCounter); + } + +-void LCD::lcdstatChange(const unsigned data, const unsigned long cycleCounter) { ++void LCD::lcdstatChange(const unsigned data, const unsigned cycleCounter) { + if (cycleCounter >= eventTimes_.nextEventTime()) + update(cycleCounter); + +@@ -584,7 +588,7 @@ void LCD::lcdstatChange(const unsigned data, const unsigned long cycleCounter) { + m0Irq_.statRegChange(data, eventTimes_(MODE0_IRQ), cycleCounter, ppu.cgb()); + } + +-void LCD::lycRegChange(const unsigned data, const unsigned long cycleCounter) { ++void LCD::lycRegChange(const unsigned data, const unsigned cycleCounter) { + if (data == lycIrq.lycReg()) + return; + +@@ -628,7 +632,7 @@ void LCD::lycRegChange(const unsigned data, const unsigned long cycleCounter) { + } + } + +-unsigned LCD::getStat(const unsigned lycReg, const unsigned long cycleCounter) { ++unsigned LCD::getStat(const unsigned lycReg, const unsigned cycleCounter) { + unsigned stat = 0; + + if (ppu.lcdc() & 0x80) { +@@ -672,7 +676,7 @@ inline void LCD::doMode2IrqEvent() { + m2IrqStatReg_ = statReg; + + if (!(statReg & 0x08)) { +- unsigned long nextTime = eventTimes_(MODE2_IRQ) + ppu.lyCounter().lineTime(); ++ unsigned nextTime = eventTimes_(MODE2_IRQ) + ppu.lyCounter().lineTime(); + + if (ly == 0) { + nextTime -= 4; +@@ -726,7 +730,7 @@ inline void LCD::event() { + + eventTimes_.setm((statReg & 0x08) + ? m0IrqTimeFromXpos166Time(ppu.predictedNextXposTime(166), ppu.cgb(), isDoubleSpeed()) +- : static_cast(DISABLED_TIME)); ++ : static_cast(DISABLED_TIME)); + break; + + case ONESHOT_LCDSTATIRQ: +@@ -750,7 +754,7 @@ inline void LCD::event() { + } + } + +-void LCD::update(const unsigned long cycleCounter) { ++void LCD::update(const unsigned cycleCounter) { + if (!(ppu.lcdc() & 0x80)) + return; + +@@ -762,15 +766,11 @@ void LCD::update(const unsigned long cycleCounter) { + ppu.update(cycleCounter); + } + +-void LCD::setVideoBuffer(uint_least32_t *const videoBuf, const int pitch) { +- ppu.setFrameBuf(videoBuf, pitch); +-} +- +-void LCD::setDmgPaletteColor(const unsigned index, const unsigned long rgb32) { ++void LCD::setDmgPaletteColor(const unsigned index, const uint_least32_t rgb32) { + dmgColorsRgb32[index] = rgb32; + } + +-void LCD::setDmgPaletteColor(const unsigned palNum, const unsigned colorNum, const unsigned long rgb32) { ++void LCD::setDmgPaletteColor(const unsigned palNum, const unsigned colorNum, const uint_least32_t rgb32) { + if (palNum > 2 || colorNum > 3) + return; + +@@ -778,4 +778,18 @@ void LCD::setDmgPaletteColor(const unsigned palNum, const unsigned colorNum, con + refreshPalettes(); + } + ++void LCD::loadOrSave(loadsave& state) { ++ ppu.loadOrSave(state); ++ state(dmgColorsRgb32, 12); ++ state(bgpData, 64); ++ state(objpData, 64); ++ eventTimes_.loadOrSave(state); ++ m0Irq_.loadOrSave(state); ++ lycIrq.loadOrSave(state); ++ nextM0Time_.loadOrSave(state); ++ state(statReg); ++ state(m2IrqStatReg_); ++ state(m1IrqStatReg_); ++} ++ + } +diff --git a/libgambatte/src/video.h b/libgambatte/src/video.h +index e7802f1..9fe9454 100644 +--- a/libgambatte/src/video.h ++++ b/libgambatte/src/video.h +@@ -19,6 +19,10 @@ + #ifndef VIDEO_H + #define VIDEO_H + ++// ++// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara ++// - Make it rerecording-friendly. ++ + #include "video/ppu.h" + #include "video/lyc_irq.h" + #include "video/next_m0_time.h" +@@ -36,7 +40,7 @@ public: + explicit VideoInterruptRequester(InterruptRequester * intreq) : intreq(intreq) {} + void flagHdmaReq() const { gambatte::flagHdmaReq(intreq); } + void flagIrq(const unsigned bit) const { intreq->flagIrq(bit); } +- void setNextEventTime(const unsigned long time) const { intreq->setEventTime